Skip to content

Commit 76ce4dc

Browse files
committed
NFSD: Cap rsize_bop result based on send buffer size
Since before the git era, NFSD has conserved the number of pages held by each nfsd thread by combining the RPC receive and send buffers into a single array of pages. This works because there are no cases where an operation needs a large RPC Call message and a large RPC Reply at the same time. Once an RPC Call has been received, svc_process() updates svc_rqst::rq_res to describe the part of rq_pages that can be used for constructing the Reply. This means that the send buffer (rq_res) shrinks when the received RPC record containing the RPC Call is large. Add an NFSv4 helper that computes the size of the send buffer. It replaces svc_max_payload() in spots where svc_max_payload() returns a value that might be larger than the remaining send buffer space. Callers who need to know the transport's actual maximum payload size will continue to use svc_max_payload(). Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
1 parent 781fde1 commit 76ce4dc

1 file changed

Lines changed: 24 additions & 24 deletions

File tree

fs/nfsd/nfs4proc.c

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2771,6 +2771,22 @@ nfsd4_proc_compound(struct svc_rqst *rqstp)
27712771

27722772
#define op_encode_channel_attrs_maxsz (6 + 1 + 1)
27732773

2774+
/*
2775+
* The _rsize() helpers are invoked by the NFSv4 COMPOUND decoder, which
2776+
* is called before sunrpc sets rq_res.buflen. Thus we have to compute
2777+
* the maximum payload size here, based on transport limits and the size
2778+
* of the remaining space in the rq_pages array.
2779+
*/
2780+
static u32 nfsd4_max_payload(const struct svc_rqst *rqstp)
2781+
{
2782+
u32 buflen;
2783+
2784+
buflen = (rqstp->rq_page_end - rqstp->rq_next_page) * PAGE_SIZE;
2785+
buflen -= rqstp->rq_auth_slack;
2786+
buflen -= rqstp->rq_res.head[0].iov_len;
2787+
return min_t(u32, buflen, svc_max_payload(rqstp));
2788+
}
2789+
27742790
static u32 nfsd4_only_status_rsize(const struct svc_rqst *rqstp,
27752791
const struct nfsd4_op *op)
27762792
{
@@ -2816,9 +2832,9 @@ static u32 nfsd4_getattr_rsize(const struct svc_rqst *rqstp,
28162832
u32 ret = 0;
28172833

28182834
if (bmap0 & FATTR4_WORD0_ACL)
2819-
return svc_max_payload(rqstp);
2835+
return nfsd4_max_payload(rqstp);
28202836
if (bmap0 & FATTR4_WORD0_FS_LOCATIONS)
2821-
return svc_max_payload(rqstp);
2837+
return nfsd4_max_payload(rqstp);
28222838

28232839
if (bmap1 & FATTR4_WORD1_OWNER) {
28242840
ret += IDMAP_NAMESZ + 4;
@@ -2878,19 +2894,15 @@ static u32 nfsd4_open_rsize(const struct svc_rqst *rqstp,
28782894
static u32 nfsd4_read_rsize(const struct svc_rqst *rqstp,
28792895
const struct nfsd4_op *op)
28802896
{
2881-
u32 maxcount = 0, rlen = 0;
2882-
2883-
maxcount = svc_max_payload(rqstp);
2884-
rlen = min(op->u.read.rd_length, maxcount);
2897+
u32 rlen = min(op->u.read.rd_length, nfsd4_max_payload(rqstp));
28852898

28862899
return (op_encode_hdr_size + 2 + XDR_QUADLEN(rlen)) * sizeof(__be32);
28872900
}
28882901

28892902
static u32 nfsd4_read_plus_rsize(const struct svc_rqst *rqstp,
28902903
const struct nfsd4_op *op)
28912904
{
2892-
u32 maxcount = svc_max_payload(rqstp);
2893-
u32 rlen = min(op->u.read.rd_length, maxcount);
2905+
u32 rlen = min(op->u.read.rd_length, nfsd4_max_payload(rqstp));
28942906
/*
28952907
* If we detect that the file changed during hole encoding, then we
28962908
* recover by encoding the remaining reply as data. This means we need
@@ -2904,10 +2916,7 @@ static u32 nfsd4_read_plus_rsize(const struct svc_rqst *rqstp,
29042916
static u32 nfsd4_readdir_rsize(const struct svc_rqst *rqstp,
29052917
const struct nfsd4_op *op)
29062918
{
2907-
u32 maxcount = 0, rlen = 0;
2908-
2909-
maxcount = svc_max_payload(rqstp);
2910-
rlen = min(op->u.readdir.rd_maxcount, maxcount);
2919+
u32 rlen = min(op->u.readdir.rd_maxcount, nfsd4_max_payload(rqstp));
29112920

29122921
return (op_encode_hdr_size + op_encode_verifier_maxsz +
29132922
XDR_QUADLEN(rlen)) * sizeof(__be32);
@@ -3046,10 +3055,7 @@ static u32 nfsd4_copy_notify_rsize(const struct svc_rqst *rqstp,
30463055
static u32 nfsd4_getdeviceinfo_rsize(const struct svc_rqst *rqstp,
30473056
const struct nfsd4_op *op)
30483057
{
3049-
u32 maxcount = 0, rlen = 0;
3050-
3051-
maxcount = svc_max_payload(rqstp);
3052-
rlen = min(op->u.getdeviceinfo.gd_maxcount, maxcount);
3058+
u32 rlen = min(op->u.getdeviceinfo.gd_maxcount, nfsd4_max_payload(rqstp));
30533059

30543060
return (op_encode_hdr_size +
30553061
1 /* gd_layout_type*/ +
@@ -3099,10 +3105,7 @@ static u32 nfsd4_seek_rsize(const struct svc_rqst *rqstp,
30993105
static u32 nfsd4_getxattr_rsize(const struct svc_rqst *rqstp,
31003106
const struct nfsd4_op *op)
31013107
{
3102-
u32 maxcount, rlen;
3103-
3104-
maxcount = svc_max_payload(rqstp);
3105-
rlen = min_t(u32, XATTR_SIZE_MAX, maxcount);
3108+
u32 rlen = min_t(u32, XATTR_SIZE_MAX, nfsd4_max_payload(rqstp));
31063109

31073110
return (op_encode_hdr_size + 1 + XDR_QUADLEN(rlen)) * sizeof(__be32);
31083111
}
@@ -3116,10 +3119,7 @@ static u32 nfsd4_setxattr_rsize(const struct svc_rqst *rqstp,
31163119
static u32 nfsd4_listxattrs_rsize(const struct svc_rqst *rqstp,
31173120
const struct nfsd4_op *op)
31183121
{
3119-
u32 maxcount, rlen;
3120-
3121-
maxcount = svc_max_payload(rqstp);
3122-
rlen = min(op->u.listxattrs.lsxa_maxcount, maxcount);
3122+
u32 rlen = min(op->u.listxattrs.lsxa_maxcount, nfsd4_max_payload(rqstp));
31233123

31243124
return (op_encode_hdr_size + 4 + XDR_QUADLEN(rlen)) * sizeof(__be32);
31253125
}

0 commit comments

Comments
 (0)