Skip to content

Commit 0d32a6b

Browse files
committed
NFSD: Fix zero NFSv4 READ results when RQ_SPLICE_OK is not set
nfsd4_encode_readv() uses xdr->buf->page_len as a starting point for the nfsd_iter_read() sink buffer -- page_len is going to be offset by the parts of the COMPOUND that have already been encoded into xdr->buf->pages. However, that value must be captured /before/ xdr_reserve_space_vec() advances page_len by the expected size of the read payload. Otherwise, the whole front part of the first page of the payload in the reply will be uninitialized. Mantas hit this because sec=krb5i forces RQ_SPLICE_OK off, which invokes the readv part of the nfsd4_encode_read() path. Also, older Linux NFS clients appear to send shorter READ requests for files smaller than a page, whereas newer clients just send page-sized requests and let the server send as many bytes as are in the file. Reported-by: Mantas Mikulėnas <grawity@gmail.com> Closes: https://lore.kernel.org/linux-nfs/f1d0b234-e650-0f6e-0f5d-126b3d51d1eb@gmail.com/ Fixes: 703d752 ("NFSD: Hoist rq_vec preparation into nfsd_read() [step two]") Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
1 parent 88956ea commit 0d32a6b

File tree

1 file changed

+2
-2
lines changed

1 file changed

+2
-2
lines changed

fs/nfsd/nfs4xdr.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4113,6 +4113,7 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp,
41134113
struct file *file, unsigned long maxcount)
41144114
{
41154115
struct xdr_stream *xdr = resp->xdr;
4116+
unsigned int base = xdr->buf->page_len & ~PAGE_MASK;
41164117
unsigned int starting_len = xdr->buf->len;
41174118
__be32 zero = xdr_zero;
41184119
__be32 nfserr;
@@ -4121,8 +4122,7 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp,
41214122
return nfserr_resource;
41224123

41234124
nfserr = nfsd_iter_read(resp->rqstp, read->rd_fhp, file,
4124-
read->rd_offset, &maxcount,
4125-
xdr->buf->page_len & ~PAGE_MASK,
4125+
read->rd_offset, &maxcount, base,
41264126
&read->rd_eof);
41274127
read->rd_length = maxcount;
41284128
if (nfserr)

0 commit comments

Comments
 (0)