Commit 1d9612dd authored by Neil Brown's avatar Neil Brown Committed by Linus Torvalds

[PATCH] knfsd: reduce stack usage in nfsd4

nfsd4_proc_compound is using over a thousand bytes of stack.

This is partly because it declares two local svc_fh's, partly because of a big
switch statement which calls a bunch of functions which may be inlined.

Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>        
Signed-off-by: default avatarNeil Brown <neilb@cse.unsw.edu.au>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 0ba524ef
...@@ -318,7 +318,7 @@ nfsd4_commit(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_com ...@@ -318,7 +318,7 @@ nfsd4_commit(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_com
return status; return status;
} }
static inline int static int
nfsd4_create(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_create *create) nfsd4_create(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_create *create)
{ {
struct svc_fh resfh; struct svc_fh resfh;
...@@ -435,7 +435,7 @@ nfsd4_link(struct svc_rqst *rqstp, struct svc_fh *current_fh, ...@@ -435,7 +435,7 @@ nfsd4_link(struct svc_rqst *rqstp, struct svc_fh *current_fh,
return status; return status;
} }
static inline int static int
nfsd4_lookupp(struct svc_rqst *rqstp, struct svc_fh *current_fh) nfsd4_lookupp(struct svc_rqst *rqstp, struct svc_fh *current_fh)
{ {
struct svc_fh tmp_fh; struct svc_fh tmp_fh;
...@@ -773,13 +773,20 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, ...@@ -773,13 +773,20 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
struct nfsd4_compoundres *resp) struct nfsd4_compoundres *resp)
{ {
struct nfsd4_op *op; struct nfsd4_op *op;
struct svc_fh current_fh; struct svc_fh *current_fh = NULL;
struct svc_fh save_fh; struct svc_fh *save_fh = NULL;
int slack_space; /* in words, not bytes! */ int slack_space; /* in words, not bytes! */
int status; int status;
fh_init(&current_fh, NFS4_FHSIZE); status = nfserr_resource;
fh_init(&save_fh, NFS4_FHSIZE); current_fh = kmalloc(sizeof(*current_fh), GFP_KERNEL);
if (current_fh == NULL)
goto out;
fh_init(current_fh, NFS4_FHSIZE);
save_fh = kmalloc(sizeof(*save_fh), GFP_KERNEL);
if (save_fh == NULL)
goto out;
fh_init(save_fh, NFS4_FHSIZE);
resp->xbuf = &rqstp->rq_res; resp->xbuf = &rqstp->rq_res;
resp->p = rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len; resp->p = rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len;
...@@ -831,7 +838,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, ...@@ -831,7 +838,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
* SETATTR NOFILEHANDLE error handled in nfsd4_setattr * SETATTR NOFILEHANDLE error handled in nfsd4_setattr
* due to required returned bitmap argument * due to required returned bitmap argument
*/ */
if ((!current_fh.fh_dentry) && if ((!current_fh->fh_dentry) &&
!((op->opnum == OP_PUTFH) || (op->opnum == OP_PUTROOTFH) || !((op->opnum == OP_PUTFH) || (op->opnum == OP_PUTROOTFH) ||
(op->opnum == OP_SETCLIENTID) || (op->opnum == OP_SETCLIENTID) ||
(op->opnum == OP_SETCLIENTID_CONFIRM) || (op->opnum == OP_SETCLIENTID_CONFIRM) ||
...@@ -843,105 +850,105 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, ...@@ -843,105 +850,105 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
} }
switch (op->opnum) { switch (op->opnum) {
case OP_ACCESS: case OP_ACCESS:
op->status = nfsd4_access(rqstp, &current_fh, &op->u.access); op->status = nfsd4_access(rqstp, current_fh, &op->u.access);
break; break;
case OP_CLOSE: case OP_CLOSE:
op->status = nfsd4_close(rqstp, &current_fh, &op->u.close); op->status = nfsd4_close(rqstp, current_fh, &op->u.close);
if (op->u.close.cl_stateowner) if (op->u.close.cl_stateowner)
op->replay = op->replay =
&op->u.close.cl_stateowner->so_replay; &op->u.close.cl_stateowner->so_replay;
break; break;
case OP_COMMIT: case OP_COMMIT:
op->status = nfsd4_commit(rqstp, &current_fh, &op->u.commit); op->status = nfsd4_commit(rqstp, current_fh, &op->u.commit);
break; break;
case OP_CREATE: case OP_CREATE:
op->status = nfsd4_create(rqstp, &current_fh, &op->u.create); op->status = nfsd4_create(rqstp, current_fh, &op->u.create);
break; break;
case OP_GETATTR: case OP_GETATTR:
op->status = nfsd4_getattr(rqstp, &current_fh, &op->u.getattr); op->status = nfsd4_getattr(rqstp, current_fh, &op->u.getattr);
break; break;
case OP_GETFH: case OP_GETFH:
op->status = nfsd4_getfh(&current_fh, &op->u.getfh); op->status = nfsd4_getfh(current_fh, &op->u.getfh);
break; break;
case OP_LINK: case OP_LINK:
op->status = nfsd4_link(rqstp, &current_fh, &save_fh, &op->u.link); op->status = nfsd4_link(rqstp, current_fh, save_fh, &op->u.link);
break; break;
case OP_LOCK: case OP_LOCK:
op->status = nfsd4_lock(rqstp, &current_fh, &op->u.lock); op->status = nfsd4_lock(rqstp, current_fh, &op->u.lock);
if (op->u.lock.lk_stateowner) if (op->u.lock.lk_stateowner)
op->replay = op->replay =
&op->u.lock.lk_stateowner->so_replay; &op->u.lock.lk_stateowner->so_replay;
break; break;
case OP_LOCKT: case OP_LOCKT:
op->status = nfsd4_lockt(rqstp, &current_fh, &op->u.lockt); op->status = nfsd4_lockt(rqstp, current_fh, &op->u.lockt);
break; break;
case OP_LOCKU: case OP_LOCKU:
op->status = nfsd4_locku(rqstp, &current_fh, &op->u.locku); op->status = nfsd4_locku(rqstp, current_fh, &op->u.locku);
if (op->u.locku.lu_stateowner) if (op->u.locku.lu_stateowner)
op->replay = op->replay =
&op->u.locku.lu_stateowner->so_replay; &op->u.locku.lu_stateowner->so_replay;
break; break;
case OP_LOOKUP: case OP_LOOKUP:
op->status = nfsd4_lookup(rqstp, &current_fh, &op->u.lookup); op->status = nfsd4_lookup(rqstp, current_fh, &op->u.lookup);
break; break;
case OP_LOOKUPP: case OP_LOOKUPP:
op->status = nfsd4_lookupp(rqstp, &current_fh); op->status = nfsd4_lookupp(rqstp, current_fh);
break; break;
case OP_NVERIFY: case OP_NVERIFY:
op->status = nfsd4_verify(rqstp, &current_fh, &op->u.nverify); op->status = nfsd4_verify(rqstp, current_fh, &op->u.nverify);
if (op->status == nfserr_not_same) if (op->status == nfserr_not_same)
op->status = nfs_ok; op->status = nfs_ok;
break; break;
case OP_OPEN: case OP_OPEN:
op->status = nfsd4_open(rqstp, &current_fh, &op->u.open); op->status = nfsd4_open(rqstp, current_fh, &op->u.open);
if (op->u.open.op_stateowner) if (op->u.open.op_stateowner)
op->replay = op->replay =
&op->u.open.op_stateowner->so_replay; &op->u.open.op_stateowner->so_replay;
break; break;
case OP_OPEN_CONFIRM: case OP_OPEN_CONFIRM:
op->status = nfsd4_open_confirm(rqstp, &current_fh, &op->u.open_confirm); op->status = nfsd4_open_confirm(rqstp, current_fh, &op->u.open_confirm);
if (op->u.open_confirm.oc_stateowner) if (op->u.open_confirm.oc_stateowner)
op->replay = op->replay =
&op->u.open_confirm.oc_stateowner->so_replay; &op->u.open_confirm.oc_stateowner->so_replay;
break; break;
case OP_OPEN_DOWNGRADE: case OP_OPEN_DOWNGRADE:
op->status = nfsd4_open_downgrade(rqstp, &current_fh, &op->u.open_downgrade); op->status = nfsd4_open_downgrade(rqstp, current_fh, &op->u.open_downgrade);
if (op->u.open_downgrade.od_stateowner) if (op->u.open_downgrade.od_stateowner)
op->replay = op->replay =
&op->u.open_downgrade.od_stateowner->so_replay; &op->u.open_downgrade.od_stateowner->so_replay;
break; break;
case OP_PUTFH: case OP_PUTFH:
op->status = nfsd4_putfh(rqstp, &current_fh, &op->u.putfh); op->status = nfsd4_putfh(rqstp, current_fh, &op->u.putfh);
break; break;
case OP_PUTROOTFH: case OP_PUTROOTFH:
op->status = nfsd4_putrootfh(rqstp, &current_fh); op->status = nfsd4_putrootfh(rqstp, current_fh);
break; break;
case OP_READ: case OP_READ:
op->status = nfsd4_read(rqstp, &current_fh, &op->u.read); op->status = nfsd4_read(rqstp, current_fh, &op->u.read);
break; break;
case OP_READDIR: case OP_READDIR:
op->status = nfsd4_readdir(rqstp, &current_fh, &op->u.readdir); op->status = nfsd4_readdir(rqstp, current_fh, &op->u.readdir);
break; break;
case OP_READLINK: case OP_READLINK:
op->status = nfsd4_readlink(rqstp, &current_fh, &op->u.readlink); op->status = nfsd4_readlink(rqstp, current_fh, &op->u.readlink);
break; break;
case OP_REMOVE: case OP_REMOVE:
op->status = nfsd4_remove(rqstp, &current_fh, &op->u.remove); op->status = nfsd4_remove(rqstp, current_fh, &op->u.remove);
break; break;
case OP_RENAME: case OP_RENAME:
op->status = nfsd4_rename(rqstp, &current_fh, &save_fh, &op->u.rename); op->status = nfsd4_rename(rqstp, current_fh, save_fh, &op->u.rename);
break; break;
case OP_RENEW: case OP_RENEW:
op->status = nfsd4_renew(&op->u.renew); op->status = nfsd4_renew(&op->u.renew);
break; break;
case OP_RESTOREFH: case OP_RESTOREFH:
op->status = nfsd4_restorefh(&current_fh, &save_fh); op->status = nfsd4_restorefh(current_fh, save_fh);
break; break;
case OP_SAVEFH: case OP_SAVEFH:
op->status = nfsd4_savefh(&current_fh, &save_fh); op->status = nfsd4_savefh(current_fh, save_fh);
break; break;
case OP_SETATTR: case OP_SETATTR:
op->status = nfsd4_setattr(rqstp, &current_fh, &op->u.setattr); op->status = nfsd4_setattr(rqstp, current_fh, &op->u.setattr);
break; break;
case OP_SETCLIENTID: case OP_SETCLIENTID:
op->status = nfsd4_setclientid(rqstp, &op->u.setclientid); op->status = nfsd4_setclientid(rqstp, &op->u.setclientid);
...@@ -950,12 +957,12 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, ...@@ -950,12 +957,12 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
op->status = nfsd4_setclientid_confirm(rqstp, &op->u.setclientid_confirm); op->status = nfsd4_setclientid_confirm(rqstp, &op->u.setclientid_confirm);
break; break;
case OP_VERIFY: case OP_VERIFY:
op->status = nfsd4_verify(rqstp, &current_fh, &op->u.verify); op->status = nfsd4_verify(rqstp, current_fh, &op->u.verify);
if (op->status == nfserr_same) if (op->status == nfserr_same)
op->status = nfs_ok; op->status = nfs_ok;
break; break;
case OP_WRITE: case OP_WRITE:
op->status = nfsd4_write(rqstp, &current_fh, &op->u.write); op->status = nfsd4_write(rqstp, current_fh, &op->u.write);
break; break;
case OP_RELEASE_LOCKOWNER: case OP_RELEASE_LOCKOWNER:
op->status = nfsd4_release_lockowner(rqstp, &op->u.release_lockowner); op->status = nfsd4_release_lockowner(rqstp, &op->u.release_lockowner);
...@@ -990,8 +997,12 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, ...@@ -990,8 +997,12 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
kfree(tb->buf); kfree(tb->buf);
kfree(tb); kfree(tb);
} }
fh_put(&current_fh); if (current_fh)
fh_put(&save_fh); fh_put(current_fh);
kfree(current_fh);
if (save_fh)
fh_put(save_fh);
kfree(save_fh);
return status; return status;
} }
......
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