nfsd4: more precise nfsd4_max_reply
[cascardo/linux.git] / fs / nfsd / nfs4xdr.c
index 2f0ea20..8b3d24d 100644 (file)
@@ -1605,40 +1605,13 @@ 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_GETATTR:
-       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 max_reply = 2 * RPC_MAX_AUTH_SIZE + 8; /* opcnt, status */
        int i;
 
        READ_BUF(4);
@@ -1647,6 +1620,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
        SAVEMEM(argp->tag, argp->taglen);
        READ32(argp->minorversion);
        READ32(argp->opcnt);
+       max_reply += 4 + (XDR_QUADLEN(argp->taglen) << 2);
 
        if (argp->taglen > NFSD4_MAX_TAGLEN)
                goto xdr_error;
@@ -1684,7 +1658,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
                 */
                cachethis |= nfsd4_cache_this_op(op);
 
-               max_reply = max(max_reply, nfsd4_max_reply(op->opnum));
+               max_reply += nfsd4_max_reply(argp->rqstp, op);
 
                if (op->status) {
                        argp->opcnt = i+1;
@@ -1694,8 +1668,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
        /* Sessions make the DRC unnecessary: */
        if (argp->minorversion)
                cachethis = false;
-       if (max_reply != INT_MAX)
-               svc_reserve(argp->rqstp, max_reply);
+       svc_reserve(argp->rqstp, max_reply);
        argp->rqstp->rq_cachetype = cachethis ? RC_REPLBUFF : RC_NOCACHE;
 
        DECODE_TAIL;