Commit e5a9af8f authored by Trond Myklebust's avatar Trond Myklebust

Subject: [PATCH] NFS: Direct read path allocates nfs_read_data on the stack

 Reduce stack utilization in the NFS direct read path by using a
 dynamically allocated nfs_read_data structure instead of allocating one
 on the stack.  This reduces stack utilization of nfs_direct_read_seg
 from over 900 bytes to less than 100 bytes.
Signed-off-by: default avatarChuck Lever <cel@netapp.com>
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@fys.uio.no>
parent a0358cea
...@@ -124,34 +124,35 @@ nfs_direct_read_seg(struct inode *inode, struct nfs_open_context *ctx, ...@@ -124,34 +124,35 @@ nfs_direct_read_seg(struct inode *inode, struct nfs_open_context *ctx,
const unsigned int rsize = NFS_SERVER(inode)->rsize; const unsigned int rsize = NFS_SERVER(inode)->rsize;
int tot_bytes = 0; int tot_bytes = 0;
int curpage = 0; int curpage = 0;
struct nfs_read_data rdata = { struct nfs_read_data *rdata;
.inode = inode,
.cred = ctx->cred, rdata = nfs_readdata_alloc();
.args = { if (!rdata)
.fh = NFS_FH(inode), return -ENOMEM;
.context = ctx,
}, memset(rdata, 0, sizeof(*rdata));
.res = { rdata->inode = inode;
.fattr = &rdata.fattr, rdata->cred = ctx->cred;
}, rdata->args.fh = NFS_FH(inode);
}; rdata->args.context = ctx;
rdata->res.fattr = &rdata->fattr;
rdata.args.pgbase = user_addr & ~PAGE_MASK; rdata->args.pgbase = user_addr & ~PAGE_MASK;
rdata.args.offset = file_offset; rdata->args.offset = file_offset;
do { do {
int result; int result;
rdata.args.count = count; rdata->args.count = count;
if (rdata.args.count > rsize) if (rdata->args.count > rsize)
rdata.args.count = rsize; rdata->args.count = rsize;
rdata.args.pages = &pages[curpage]; rdata->args.pages = &pages[curpage];
dprintk("NFS: direct read: c=%u o=%Ld ua=%lu, pb=%u, cp=%u\n", dprintk("NFS: direct read: c=%u o=%Ld ua=%lu, pb=%u, cp=%u\n",
rdata.args.count, (long long) rdata.args.offset, rdata->args.count, (long long) rdata->args.offset,
user_addr + tot_bytes, rdata.args.pgbase, curpage); user_addr + tot_bytes, rdata->args.pgbase, curpage);
lock_kernel(); lock_kernel();
result = NFS_PROTO(inode)->read(&rdata); result = NFS_PROTO(inode)->read(rdata);
unlock_kernel(); unlock_kernel();
if (result <= 0) { if (result <= 0) {
...@@ -159,23 +160,22 @@ nfs_direct_read_seg(struct inode *inode, struct nfs_open_context *ctx, ...@@ -159,23 +160,22 @@ nfs_direct_read_seg(struct inode *inode, struct nfs_open_context *ctx,
break; break;
if (result == -EISDIR) if (result == -EISDIR)
result = -EINVAL; result = -EINVAL;
nfs_readdata_free(rdata);
return result; return result;
} }
tot_bytes += result; tot_bytes += result;
if (rdata.res.eof) if (rdata->res.eof)
break; break;
rdata.args.offset += result; rdata->args.offset += result;
rdata.args.pgbase += result; rdata->args.pgbase += result;
curpage += rdata.args.pgbase >> PAGE_SHIFT; curpage += rdata->args.pgbase >> PAGE_SHIFT;
rdata.args.pgbase &= ~PAGE_MASK; rdata->args.pgbase &= ~PAGE_MASK;
count -= result; count -= result;
} while (count != 0); } while (count != 0);
/* XXX: should we zero the rest of the user's buffer if we nfs_readdata_free(rdata);
* hit eof? */
return tot_bytes; return tot_bytes;
} }
...@@ -188,9 +188,8 @@ nfs_direct_read_seg(struct inode *inode, struct nfs_open_context *ctx, ...@@ -188,9 +188,8 @@ nfs_direct_read_seg(struct inode *inode, struct nfs_open_context *ctx,
* file_offset: offset in file to begin the operation * file_offset: offset in file to begin the operation
* nr_segs: size of iovec array * nr_segs: size of iovec array
* *
* generic_file_direct_IO has already pushed out any non-direct * We've already pushed out any non-direct writes so that this read
* writes so that this read will see them when we read from the * will see them when we read from the server.
* server.
*/ */
static ssize_t static ssize_t
nfs_direct_read(struct inode *inode, struct nfs_open_context *ctx, nfs_direct_read(struct inode *inode, struct nfs_open_context *ctx,
......
...@@ -24,7 +24,6 @@ ...@@ -24,7 +24,6 @@
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/mempool.h>
#include <linux/sunrpc/clnt.h> #include <linux/sunrpc/clnt.h>
#include <linux/nfs_fs.h> #include <linux/nfs_fs.h>
#include <linux/nfs_page.h> #include <linux/nfs_page.h>
...@@ -39,25 +38,11 @@ static void nfs_readpage_result_partial(struct nfs_read_data *, int); ...@@ -39,25 +38,11 @@ static void nfs_readpage_result_partial(struct nfs_read_data *, int);
static void nfs_readpage_result_full(struct nfs_read_data *, int); static void nfs_readpage_result_full(struct nfs_read_data *, int);
static kmem_cache_t *nfs_rdata_cachep; static kmem_cache_t *nfs_rdata_cachep;
static mempool_t *nfs_rdata_mempool; mempool_t *nfs_rdata_mempool;
#define MIN_POOL_READ (32) #define MIN_POOL_READ (32)
static struct nfs_read_data *nfs_readdata_alloc(void) void nfs_readdata_release(struct rpc_task *task)
{
struct nfs_read_data *p;
p = (struct nfs_read_data *)mempool_alloc(nfs_rdata_mempool, SLAB_NOFS);
if (p)
memset(p, 0, sizeof(*p));
return p;
}
static __inline__ void nfs_readdata_free(struct nfs_read_data *p)
{
mempool_free(p, nfs_rdata_mempool);
}
static void nfs_readdata_release(struct rpc_task *task)
{ {
struct nfs_read_data *data = (struct nfs_read_data *)task->tk_calldata; struct nfs_read_data *data = (struct nfs_read_data *)task->tk_calldata;
nfs_readdata_free(data); nfs_readdata_free(data);
......
...@@ -477,6 +477,26 @@ extern int nfs_readpages(struct file *, struct address_space *, ...@@ -477,6 +477,26 @@ extern int nfs_readpages(struct file *, struct address_space *,
extern int nfs_pagein_list(struct list_head *, int); extern int nfs_pagein_list(struct list_head *, int);
extern void nfs_readpage_result(struct rpc_task *); extern void nfs_readpage_result(struct rpc_task *);
/*
* Allocate and free nfs_read_data structures
*/
extern mempool_t *nfs_rdata_mempool;
static inline struct nfs_read_data *nfs_readdata_alloc(void)
{
struct nfs_read_data *p = mempool_alloc(nfs_rdata_mempool, SLAB_NOFS);
if (p)
memset(p, 0, sizeof(*p));
return p;
}
static inline void nfs_readdata_free(struct nfs_read_data *p)
{
mempool_free(p, nfs_rdata_mempool);
}
extern void nfs_readdata_release(struct rpc_task *task);
/* /*
* linux/fs/mount_clnt.c * linux/fs/mount_clnt.c
* (Used only by nfsroot module) * (Used only by nfsroot module)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment