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,
const unsigned int rsize = NFS_SERVER(inode)->rsize;
int tot_bytes = 0;
int curpage = 0;
struct nfs_read_data rdata = {
.inode = inode,
.cred = ctx->cred,
.args = {
.fh = NFS_FH(inode),
.context = ctx,
},
.res = {
.fattr = &rdata.fattr,
},
};
struct nfs_read_data *rdata;
rdata = nfs_readdata_alloc();
if (!rdata)
return -ENOMEM;
memset(rdata, 0, sizeof(*rdata));
rdata->inode = inode;
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.offset = file_offset;
do {
rdata->args.pgbase = user_addr & ~PAGE_MASK;
rdata->args.offset = file_offset;
do {
int result;
rdata.args.count = count;
if (rdata.args.count > rsize)
rdata.args.count = rsize;
rdata.args.pages = &pages[curpage];
rdata->args.count = count;
if (rdata->args.count > rsize)
rdata->args.count = rsize;
rdata->args.pages = &pages[curpage];
dprintk("NFS: direct read: c=%u o=%Ld ua=%lu, pb=%u, cp=%u\n",
rdata.args.count, (long long) rdata.args.offset,
user_addr + tot_bytes, rdata.args.pgbase, curpage);
rdata->args.count, (long long) rdata->args.offset,
user_addr + tot_bytes, rdata->args.pgbase, curpage);
lock_kernel();
result = NFS_PROTO(inode)->read(&rdata);
result = NFS_PROTO(inode)->read(rdata);
unlock_kernel();
if (result <= 0) {
......@@ -159,23 +160,22 @@ nfs_direct_read_seg(struct inode *inode, struct nfs_open_context *ctx,
break;
if (result == -EISDIR)
result = -EINVAL;
nfs_readdata_free(rdata);
return result;
}
tot_bytes += result;
if (rdata.res.eof)
tot_bytes += result;
if (rdata->res.eof)
break;
rdata.args.offset += result;
rdata.args.pgbase += result;
curpage += rdata.args.pgbase >> PAGE_SHIFT;
rdata.args.pgbase &= ~PAGE_MASK;
rdata->args.offset += result;
rdata->args.pgbase += result;
curpage += rdata->args.pgbase >> PAGE_SHIFT;
rdata->args.pgbase &= ~PAGE_MASK;
count -= result;
} while (count != 0);
/* XXX: should we zero the rest of the user's buffer if we
* hit eof? */
nfs_readdata_free(rdata);
return tot_bytes;
}
......@@ -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
* nr_segs: size of iovec array
*
* generic_file_direct_IO has already pushed out any non-direct
* writes so that this read will see them when we read from the
* server.
* We've already pushed out any non-direct writes so that this read
* will see them when we read from the server.
*/
static ssize_t
nfs_direct_read(struct inode *inode, struct nfs_open_context *ctx,
......
......@@ -24,7 +24,6 @@
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/pagemap.h>
#include <linux/mempool.h>
#include <linux/sunrpc/clnt.h>
#include <linux/nfs_fs.h>
#include <linux/nfs_page.h>
......@@ -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 kmem_cache_t *nfs_rdata_cachep;
static mempool_t *nfs_rdata_mempool;
mempool_t *nfs_rdata_mempool;
#define MIN_POOL_READ (32)
static struct nfs_read_data *nfs_readdata_alloc(void)
{
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)
void nfs_readdata_release(struct rpc_task *task)
{
struct nfs_read_data *data = (struct nfs_read_data *)task->tk_calldata;
nfs_readdata_free(data);
......
......@@ -477,6 +477,26 @@ extern int nfs_readpages(struct file *, struct address_space *,
extern int nfs_pagein_list(struct list_head *, int);
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
* (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