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

[PATCH] knfsd: improve cleaning up of nfsd4 requests

Currently nfs4_arg->to_free keeps a list of void ptrs on which kfree is called
when freeing the nfs4_arg.  This allows us to do cleanup on e.g.  xdr decode
failures.  To allow more complicated objects to be freed (in particular,
acls), we add a "void (*release)(void *)" to allow us to request something
other than kfree be called when freeing.
Signed-off-by: default avatarJ. 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 7a9eaffa
...@@ -983,20 +983,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, ...@@ -983,20 +983,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
} }
out: out:
if (args->ops != args->iops) { nfsd4_release_compoundargs(args);
kfree(args->ops);
args->ops = args->iops;
}
if (args->tmpp) {
kfree(args->tmpp);
args->tmpp = NULL;
}
while (args->to_free) {
struct tmpbuf *tb = args->to_free;
args->to_free = tb->next;
kfree(tb->buf);
kfree(tb);
}
if (current_fh) if (current_fh)
fh_put(current_fh); fh_put(current_fh);
kfree(current_fh); kfree(current_fh);
......
...@@ -287,27 +287,40 @@ u32 *read_buf(struct nfsd4_compoundargs *argp, int nbytes) ...@@ -287,27 +287,40 @@ u32 *read_buf(struct nfsd4_compoundargs *argp, int nbytes)
return p; return p;
} }
char *savemem(struct nfsd4_compoundargs *argp, u32 *p, int nbytes) static int
defer_free(struct nfsd4_compoundargs *argp,
void (*release)(const void *), void *p)
{ {
struct tmpbuf *tb; struct tmpbuf *tb;
tb = kmalloc(sizeof(*tb), GFP_KERNEL);
if (!tb)
return -ENOMEM;
tb->buf = p;
tb->release = release;
tb->next = argp->to_free;
argp->to_free = tb;
return 0;
}
char *savemem(struct nfsd4_compoundargs *argp, u32 *p, int nbytes)
{
void *new = NULL;
if (p == argp->tmp) { if (p == argp->tmp) {
p = kmalloc(nbytes, GFP_KERNEL); new = kmalloc(nbytes, GFP_KERNEL);
if (!p) return NULL; if (!new) return NULL;
p = new;
memcpy(p, argp->tmp, nbytes); memcpy(p, argp->tmp, nbytes);
} else { } else {
if (p != argp->tmpp) if (p != argp->tmpp)
BUG(); BUG();
argp->tmpp = NULL; argp->tmpp = NULL;
} }
tb = kmalloc(sizeof(*tb), GFP_KERNEL); if (defer_free(argp, kfree, p)) {
if (!tb) { kfree(new);
kfree(p);
return NULL; return NULL;
} } else
tb->buf = p; return (char *)p;
tb->next = argp->to_free;
argp->to_free = tb;
return (char*)p;
} }
...@@ -2461,6 +2474,24 @@ nfs4svc_encode_voidres(struct svc_rqst *rqstp, u32 *p, void *dummy) ...@@ -2461,6 +2474,24 @@ nfs4svc_encode_voidres(struct svc_rqst *rqstp, u32 *p, void *dummy)
return xdr_ressize_check(rqstp, p); return xdr_ressize_check(rqstp, p);
} }
void nfsd4_release_compoundargs(struct nfsd4_compoundargs *args)
{
if (args->ops != args->iops) {
kfree(args->ops);
args->ops = args->iops;
}
if (args->tmpp) {
kfree(args->tmpp);
args->tmpp = NULL;
}
while (args->to_free) {
struct tmpbuf *tb = args->to_free;
args->to_free = tb->next;
tb->release(tb->buf);
kfree(tb);
}
}
int int
nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, u32 *p, struct nfsd4_compoundargs *args) nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, u32 *p, struct nfsd4_compoundargs *args)
{ {
...@@ -2477,20 +2508,7 @@ nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, u32 *p, struct nfsd4_compoun ...@@ -2477,20 +2508,7 @@ nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, u32 *p, struct nfsd4_compoun
status = nfsd4_decode_compound(args); status = nfsd4_decode_compound(args);
if (status) { if (status) {
if (args->ops != args->iops) { nfsd4_release_compoundargs(args);
kfree(args->ops);
args->ops = args->iops;
}
if (args->tmpp) {
kfree(args->tmpp);
args->tmpp = NULL;
}
while (args->to_free) {
struct tmpbuf *tb = args->to_free;
args->to_free = tb->next;
kfree(tb->buf);
kfree(tb);
}
} }
return !status; return !status;
} }
......
...@@ -378,6 +378,7 @@ struct nfsd4_compoundargs { ...@@ -378,6 +378,7 @@ struct nfsd4_compoundargs {
u32 * tmpp; u32 * tmpp;
struct tmpbuf { struct tmpbuf {
struct tmpbuf *next; struct tmpbuf *next;
void (*release)(const void *);
void *buf; void *buf;
} *to_free; } *to_free;
...@@ -449,6 +450,7 @@ extern int nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, ...@@ -449,6 +450,7 @@ extern int nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh,
extern int extern int
nfsd4_release_lockowner(struct svc_rqst *rqstp, nfsd4_release_lockowner(struct svc_rqst *rqstp,
struct nfsd4_release_lockowner *rlockowner); struct nfsd4_release_lockowner *rlockowner);
extern void nfsd4_release_compoundargs(struct nfsd4_compoundargs *);
#endif #endif
/* /*
......
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