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,
}
out:
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;
kfree(tb->buf);
kfree(tb);
}
nfsd4_release_compoundargs(args);
if (current_fh)
fh_put(current_fh);
kfree(current_fh);
......
......@@ -287,27 +287,40 @@ u32 *read_buf(struct nfsd4_compoundargs *argp, int nbytes)
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;
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) {
p = kmalloc(nbytes, GFP_KERNEL);
if (!p) return NULL;
new = kmalloc(nbytes, GFP_KERNEL);
if (!new) return NULL;
p = new;
memcpy(p, argp->tmp, nbytes);
} else {
if (p != argp->tmpp)
BUG();
argp->tmpp = NULL;
}
tb = kmalloc(sizeof(*tb), GFP_KERNEL);
if (!tb) {
kfree(p);
if (defer_free(argp, kfree, p)) {
kfree(new);
return NULL;
}
tb->buf = p;
tb->next = argp->to_free;
argp->to_free = tb;
return (char*)p;
} else
return (char *)p;
}
......@@ -2461,6 +2474,24 @@ nfs4svc_encode_voidres(struct svc_rqst *rqstp, u32 *p, void *dummy)
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
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
status = nfsd4_decode_compound(args);
if (status) {
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;
kfree(tb->buf);
kfree(tb);
}
nfsd4_release_compoundargs(args);
}
return !status;
}
......
......@@ -378,6 +378,7 @@ struct nfsd4_compoundargs {
u32 * tmpp;
struct tmpbuf {
struct tmpbuf *next;
void (*release)(const void *);
void *buf;
} *to_free;
......@@ -449,6 +450,7 @@ extern int nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh,
extern int
nfsd4_release_lockowner(struct svc_rqst *rqstp,
struct nfsd4_release_lockowner *rlockowner);
extern void nfsd4_release_compoundargs(struct nfsd4_compoundargs *);
#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