struct nfsd4_op *op;
        bool cachethis = false;
        int max_reply = 2 * RPC_MAX_AUTH_SIZE + 8; /* opcnt, status */
+       int readcount = 0;
+       int readbytes = 0;
        int i;
 
        READ_BUF(4);
                 */
                cachethis |= nfsd4_cache_this_op(op);
 
-               max_reply += nfsd4_max_reply(argp->rqstp, op);
+               if (op->opnum == OP_READ) {
+                       readcount++;
+                       readbytes += nfsd4_max_reply(argp->rqstp, op);
+               } else
+                       max_reply += nfsd4_max_reply(argp->rqstp, op);
 
                if (op->status) {
                        argp->opcnt = i+1;
        /* Sessions make the DRC unnecessary: */
        if (argp->minorversion)
                cachethis = false;
-       svc_reserve(argp->rqstp, max_reply);
+       svc_reserve(argp->rqstp, max_reply + readbytes);
        argp->rqstp->rq_cachetype = cachethis ? RC_REPLBUFF : RC_NOCACHE;
 
+       if (readcount > 1 || max_reply > PAGE_SIZE - 2*RPC_MAX_AUTH_SIZE)
+               argp->rqstp->rq_splice_ok = false;
+
        DECODE_TAIL;
 }
 
                return nfserr;
 
        p = xdr_reserve_space(xdr, 8); /* eof flag and byte count */
-       if (!p)
+       if (!p) {
+               WARN_ON_ONCE(resp->rqstp->rq_splice_ok);
                return nfserr_resource;
+       }
 
        /* Make sure there will be room for padding if needed: */
        if (xdr->end - xdr->p < 1)
                return nfserr_resource;
 
-       if (resp->xdr.buf->page_len)
+       if (resp->xdr.buf->page_len) {
+               WARN_ON_ONCE(resp->rqstp->rq_splice_ok);
                return nfserr_resource;
+       }
 
        maxcount = svc_max_payload(resp->rqstp);
        if (maxcount > read->rd_length)