nfsd4: improve write performance with better sendspace reservations
authorJ. Bruce Fields <bfields@redhat.com>
Tue, 5 Nov 2013 20:07:16 +0000 (15:07 -0500)
committerJ. Bruce Fields <bfields@redhat.com>
Wed, 13 Nov 2013 21:12:54 +0000 (16:12 -0500)
Currently the rpc code conservatively refuses to accept rpc's from a
client if the sum of its worst-case estimates of the replies it owes
that client exceed the send buffer space.

Unfortunately our estimate of the worst-case reply for an NFSv4 compound
is always the maximum read size.  This can unnecessarily limit the
number of operations we handle concurrently, for example in the case
most operations are writes (which have small replies).

We can do a little better if we check which ops the compound contains.

This is still a rough estimate, we'll need to improve on it some day.

Reported-by: Shyam Kaushik <shyamnfs1@gmail.com>
Tested-by: Shyam Kaushik <shyamnfs1@gmail.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
fs/nfsd/nfs4xdr.c

index d9d7fa9..9d76ee3 100644 (file)
@@ -1597,12 +1597,39 @@ nfsd4_opnum_in_range(struct nfsd4_compoundargs *argp, struct nfsd4_op *op)
        return true;
 }
 
+/*
+ * Return a rough estimate of the maximum possible reply size.  Note the
+ * estimate includes rpc headers so is meant to be passed to
+ * svc_reserve, not svc_reserve_auth.
+ *
+ * Also note the current compound encoding permits only one operation to
+ * use pages beyond the first one, so the maximum possible length is the
+ * maximum over these values, not the sum.
+ */
+static int nfsd4_max_reply(u32 opnum)
+{
+       switch (opnum) {
+       case OP_READLINK:
+       case OP_READDIR:
+               /*
+                * Both of these ops take a single page for data and put
+                * the head and tail in another page:
+                */
+               return 2 * PAGE_SIZE;
+       case OP_READ:
+               return INT_MAX;
+       default:
+               return PAGE_SIZE;
+       }
+}
+
 static __be32
 nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
 {
        DECODE_HEAD;
        struct nfsd4_op *op;
        bool cachethis = false;
+       int max_reply = PAGE_SIZE;
        int i;
 
        READ_BUF(4);
@@ -1652,10 +1679,14 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
                 * op in the compound wants to be cached:
                 */
                cachethis |= nfsd4_cache_this_op(op);
+
+               max_reply = max(max_reply, nfsd4_max_reply(op->opnum));
        }
        /* Sessions make the DRC unnecessary: */
        if (argp->minorversion)
                cachethis = false;
+       if (max_reply != INT_MAX)
+               svc_reserve(argp->rqstp, max_reply);
        argp->rqstp->rq_cachetype = cachethis ? RC_REPLBUFF : RC_NOCACHE;
 
        DECODE_TAIL;