aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/nfs4xdr.c
diff options
context:
space:
mode:
authorJ. Bruce Fields <bfields@redhat.com>2014-02-04 10:36:59 -0500
committerJ. Bruce Fields <bfields@redhat.com>2014-05-30 17:32:08 -0400
commitb0e35fda827e72cf4b065b52c4c472c28c004fca (patch)
tree63378e1441b4b8a211901dcda99e503bdd08c06d /fs/nfsd/nfs4xdr.c
parentccae70a9ee415a89b70e97a36886ab55191ebaea (diff)
nfsd4: turn off zero-copy-read in exotic cases
We currently allow only one read per compound, with operations before and after whose responses will require no more than about a page to encode. While we don't expect clients to violate those limits any time soon, this limitation isn't really condoned by the spec, so to future proof the server we should lift the limitation. At the same time we'd like to continue to support zero-copy reads. Supporting multiple zero-copy-reads per compound would require a new data structure to replace struct xdr_buf, which can represent only one set of included pages. So for now we plan to modify encode_read() to support either zero-copy or non-zero-copy reads, and use some heuristics at the start of the compound processing to decide whether a zero-copy read will work. This will allow us to support more exotic compounds without introducing a performance regression in the normal case. Later patches handle those "exotic compounds", this one just makes sure zero-copy is turned off in those cases. Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs/nfsd/nfs4xdr.c')
-rw-r--r--fs/nfsd/nfs4xdr.c21
1 files changed, 17 insertions, 4 deletions
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index cda6226bda91..f6a5cb722697 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -1612,6 +1612,8 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
1612 struct nfsd4_op *op; 1612 struct nfsd4_op *op;
1613 bool cachethis = false; 1613 bool cachethis = false;
1614 int max_reply = 2 * RPC_MAX_AUTH_SIZE + 8; /* opcnt, status */ 1614 int max_reply = 2 * RPC_MAX_AUTH_SIZE + 8; /* opcnt, status */
1615 int readcount = 0;
1616 int readbytes = 0;
1615 int i; 1617 int i;
1616 1618
1617 READ_BUF(4); 1619 READ_BUF(4);
@@ -1658,7 +1660,11 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
1658 */ 1660 */
1659 cachethis |= nfsd4_cache_this_op(op); 1661 cachethis |= nfsd4_cache_this_op(op);
1660 1662
1661 max_reply += nfsd4_max_reply(argp->rqstp, op); 1663 if (op->opnum == OP_READ) {
1664 readcount++;
1665 readbytes += nfsd4_max_reply(argp->rqstp, op);
1666 } else
1667 max_reply += nfsd4_max_reply(argp->rqstp, op);
1662 1668
1663 if (op->status) { 1669 if (op->status) {
1664 argp->opcnt = i+1; 1670 argp->opcnt = i+1;
@@ -1668,9 +1674,12 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
1668 /* Sessions make the DRC unnecessary: */ 1674 /* Sessions make the DRC unnecessary: */
1669 if (argp->minorversion) 1675 if (argp->minorversion)
1670 cachethis = false; 1676 cachethis = false;
1671 svc_reserve(argp->rqstp, max_reply); 1677 svc_reserve(argp->rqstp, max_reply + readbytes);
1672 argp->rqstp->rq_cachetype = cachethis ? RC_REPLBUFF : RC_NOCACHE; 1678 argp->rqstp->rq_cachetype = cachethis ? RC_REPLBUFF : RC_NOCACHE;
1673 1679
1680 if (readcount > 1 || max_reply > PAGE_SIZE - 2*RPC_MAX_AUTH_SIZE)
1681 argp->rqstp->rq_splice_ok = false;
1682
1674 DECODE_TAIL; 1683 DECODE_TAIL;
1675} 1684}
1676 1685
@@ -3078,15 +3087,19 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
3078 return nfserr; 3087 return nfserr;
3079 3088
3080 p = xdr_reserve_space(xdr, 8); /* eof flag and byte count */ 3089 p = xdr_reserve_space(xdr, 8); /* eof flag and byte count */
3081 if (!p) 3090 if (!p) {
3091 WARN_ON_ONCE(resp->rqstp->rq_splice_ok);
3082 return nfserr_resource; 3092 return nfserr_resource;
3093 }
3083 3094
3084 /* Make sure there will be room for padding if needed: */ 3095 /* Make sure there will be room for padding if needed: */
3085 if (xdr->end - xdr->p < 1) 3096 if (xdr->end - xdr->p < 1)
3086 return nfserr_resource; 3097 return nfserr_resource;
3087 3098
3088 if (resp->xdr.buf->page_len) 3099 if (resp->xdr.buf->page_len) {
3100 WARN_ON_ONCE(resp->rqstp->rq_splice_ok);
3089 return nfserr_resource; 3101 return nfserr_resource;
3102 }
3090 3103
3091 maxcount = svc_max_payload(resp->rqstp); 3104 maxcount = svc_max_payload(resp->rqstp);
3092 if (maxcount > read->rd_length) 3105 if (maxcount > read->rd_length)