nfsd4: replace defer_free by svcxdr_tmpalloc

Avoid an extra allocation for the tmpbuf struct itself, and stop
ignoring some allocation failures.

Signed-off-by: J. Bruce Fields <bfields@redhat.com>
This commit is contained in:
J. Bruce Fields 2014-06-24 17:43:45 -04:00
parent bcaab953b1
commit d5e2338324
2 changed files with 26 additions and 33 deletions

View File

@ -181,25 +181,24 @@ static int zero_clientid(clientid_t *clid)
} }
/** /**
* defer_free - mark an allocation as deferred freed * svcxdr_tmpalloc - allocate memory to be freed after compound processing
* @argp: NFSv4 compound argument structure * @argp: NFSv4 compound argument structure
* @p: pointer to be freed (with kfree()) * @p: pointer to be freed (with kfree())
* *
* Marks @p to be freed when processing the compound operation * Marks @p to be freed when processing the compound operation
* described in @argp finishes. * described in @argp finishes.
*/ */
static int static void *
defer_free(struct nfsd4_compoundargs *argp, void *p) svcxdr_tmpalloc(struct nfsd4_compoundargs *argp, u32 len)
{ {
struct tmpbuf *tb; struct svcxdr_tmpbuf *tb;
tb = kmalloc(sizeof(*tb), GFP_KERNEL); tb = kmalloc(sizeof(*tb) + len, GFP_KERNEL);
if (!tb) if (!tb)
return -ENOMEM; return NULL;
tb->buf = p;
tb->next = argp->to_free; tb->next = argp->to_free;
argp->to_free = tb; argp->to_free = tb;
return 0; return tb->buf;
} }
/* /*
@ -212,13 +211,12 @@ defer_free(struct nfsd4_compoundargs *argp, void *p)
static char * static char *
svcxdr_dupstr(struct nfsd4_compoundargs *argp, void *buf, u32 len) svcxdr_dupstr(struct nfsd4_compoundargs *argp, void *buf, u32 len)
{ {
char *p = kmalloc(len + 1, GFP_KERNEL); char *p = svcxdr_tmpalloc(argp, len + 1);
if (!p) if (!p)
return NULL; return NULL;
memcpy(p, buf, len); memcpy(p, buf, len);
p[len] = '\0'; p[len] = '\0';
defer_free(argp, p);
return p; return p;
} }
@ -234,19 +232,13 @@ svcxdr_dupstr(struct nfsd4_compoundargs *argp, void *buf, u32 len)
*/ */
static char *savemem(struct nfsd4_compoundargs *argp, __be32 *p, int nbytes) static char *savemem(struct nfsd4_compoundargs *argp, __be32 *p, int nbytes)
{ {
if (p == argp->tmp) { void *ret;
p = kmemdup(argp->tmp, nbytes, GFP_KERNEL);
if (!p) ret = svcxdr_tmpalloc(argp, nbytes);
return NULL; if (!ret)
} else {
BUG_ON(p != argp->tmpp);
argp->tmpp = NULL;
}
if (defer_free(argp, p)) {
kfree(p);
return NULL; return NULL;
} else memcpy(ret, p, nbytes);
return (char *)p; return ret;
} }
static __be32 static __be32
@ -309,12 +301,10 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
if (nace > NFS4_ACL_MAX) if (nace > NFS4_ACL_MAX)
return nfserr_fbig; return nfserr_fbig;
*acl = kmalloc(nfs4_acl_bytes(nace), GFP_KERNEL); *acl = svcxdr_tmpalloc(argp, nfs4_acl_bytes(nace));
if (*acl == NULL) if (*acl == NULL)
return nfserr_jukebox; return nfserr_jukebox;
defer_free(argp, *acl);
(*acl)->naces = nace; (*acl)->naces = nace;
for (ace = (*acl)->aces; ace < (*acl)->aces + nace; ace++) { for (ace = (*acl)->aces; ace < (*acl)->aces + nace; ace++) {
READ_BUF(16); len += 16; READ_BUF(16); len += 16;
@ -1487,13 +1477,12 @@ nfsd4_decode_test_stateid(struct nfsd4_compoundargs *argp, struct nfsd4_test_sta
INIT_LIST_HEAD(&test_stateid->ts_stateid_list); INIT_LIST_HEAD(&test_stateid->ts_stateid_list);
for (i = 0; i < test_stateid->ts_num_ids; i++) { for (i = 0; i < test_stateid->ts_num_ids; i++) {
stateid = kmalloc(sizeof(struct nfsd4_test_stateid_id), GFP_KERNEL); stateid = svcxdr_tmpalloc(argp, sizeof(*stateid));
if (!stateid) { if (!stateid) {
status = nfserrno(-ENOMEM); status = nfserrno(-ENOMEM);
goto out; goto out;
} }
defer_free(argp, stateid);
INIT_LIST_HEAD(&stateid->ts_id_list); INIT_LIST_HEAD(&stateid->ts_id_list);
list_add_tail(&stateid->ts_id_list, &test_stateid->ts_stateid_list); list_add_tail(&stateid->ts_id_list, &test_stateid->ts_stateid_list);
@ -3977,9 +3966,8 @@ int nfsd4_release_compoundargs(void *rq, __be32 *p, void *resp)
kfree(args->tmpp); kfree(args->tmpp);
args->tmpp = NULL; args->tmpp = NULL;
while (args->to_free) { while (args->to_free) {
struct tmpbuf *tb = args->to_free; struct svcxdr_tmpbuf *tb = args->to_free;
args->to_free = tb->next; args->to_free = tb->next;
kfree(tb->buf);
kfree(tb); kfree(tb);
} }
return 1; return 1;

View File

@ -478,6 +478,14 @@ struct nfsd4_op {
bool nfsd4_cache_this_op(struct nfsd4_op *); bool nfsd4_cache_this_op(struct nfsd4_op *);
/*
* Memory needed just for the duration of processing one compound:
*/
struct svcxdr_tmpbuf {
struct svcxdr_tmpbuf *next;
char buf[];
};
struct nfsd4_compoundargs { struct nfsd4_compoundargs {
/* scratch variables for XDR decode */ /* scratch variables for XDR decode */
__be32 * p; __be32 * p;
@ -486,10 +494,7 @@ struct nfsd4_compoundargs {
int pagelen; int pagelen;
__be32 tmp[8]; __be32 tmp[8];
__be32 * tmpp; __be32 * tmpp;
struct tmpbuf { struct svcxdr_tmpbuf *to_free;
struct tmpbuf *next;
void *buf;
} *to_free;
struct svc_rqst *rqstp; struct svc_rqst *rqstp;