diff options
Diffstat (limited to 'fs/nfsd')
-rw-r--r-- | fs/nfsd/nfs4xdr.c | 21 |
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) |