nfsd4: replace defer_free by svcxdr_tmpalloc
authorJ. Bruce Fields <bfields@redhat.com>
Tue, 24 Jun 2014 21:43:45 +0000 (17:43 -0400)
committerJ. Bruce Fields <bfields@redhat.com>
Tue, 8 Jul 2014 21:14:27 +0000 (17:14 -0400)
Avoid an extra allocation for the tmpbuf struct itself, and stop
ignoring some allocation failures.

Signed-off-by: J. Bruce Fields <bfields@redhat.com>
fs/nfsd/nfs4xdr.c
fs/nfsd/xdr4.h

index fea41046427cfdc6c165a08d8248852feccc31cb..46115f2c3074993396d994bf135113a42bada292 100644 (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
  * @p: pointer to be freed (with kfree())
  *
  * Marks @p to be freed when processing the compound operation
  * described in @argp finishes.
  */
-static int
-defer_free(struct nfsd4_compoundargs *argp, void *p)
+static void *
+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)
-               return -ENOMEM;
-       tb->buf = p;
+               return NULL;
        tb->next = argp->to_free;
        argp->to_free = tb;
-       return 0;
+       return tb->buf;
 }
 
 /*
@@ -212,13 +211,12 @@ defer_free(struct nfsd4_compoundargs *argp, void *p)
 static char *
 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)
                return NULL;
        memcpy(p, buf, len);
        p[len] = '\0';
-       defer_free(argp, 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)
 {
-       if (p == argp->tmp) {
-               p = kmemdup(argp->tmp, nbytes, GFP_KERNEL);
-               if (!p)
-                       return NULL;
-       } else {
-               BUG_ON(p != argp->tmpp);
-               argp->tmpp = NULL;
-       }
-       if (defer_free(argp, p)) {
-               kfree(p);
+       void *ret;
+
+       ret = svcxdr_tmpalloc(argp, nbytes);
+       if (!ret)
                return NULL;
-       } else
-               return (char *)p;
+       memcpy(ret, p, nbytes);
+       return ret;
 }
 
 static __be32
@@ -309,12 +301,10 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
                if (nace > NFS4_ACL_MAX)
                        return nfserr_fbig;
 
-               *acl = kmalloc(nfs4_acl_bytes(nace), GFP_KERNEL);
+               *acl = svcxdr_tmpalloc(argp, nfs4_acl_bytes(nace));
                if (*acl == NULL)
                        return nfserr_jukebox;
 
-               defer_free(argp, *acl);
-
                (*acl)->naces = nace;
                for (ace = (*acl)->aces; ace < (*acl)->aces + nace; ace++) {
                        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);
 
        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) {
                        status = nfserrno(-ENOMEM);
                        goto out;
                }
 
-               defer_free(argp, stateid);
                INIT_LIST_HEAD(&stateid->ts_id_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);
        args->tmpp = NULL;
        while (args->to_free) {
-               struct tmpbuf *tb = args->to_free;
+               struct svcxdr_tmpbuf *tb = args->to_free;
                args->to_free = tb->next;
-               kfree(tb->buf);
                kfree(tb);
        }
        return 1;
index 4379cc871607d796ea543911d4a90de37fee836d..efce9010cad4be69ded839936b4b323c82754cb2 100644 (file)
@@ -478,6 +478,14 @@ 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 {
        /* scratch variables for XDR decode */
        __be32 *                        p;
@@ -486,10 +494,7 @@ struct nfsd4_compoundargs {
        int                             pagelen;
        __be32                          tmp[8];
        __be32 *                        tmpp;
-       struct tmpbuf {
-               struct tmpbuf *next;
-               void *buf;
-       }                               *to_free;
+       struct svcxdr_tmpbuf            *to_free;
 
        struct svc_rqst                 *rqstp;