]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
NFSD: Relocate the xdr_reserve_space_vec() call site
authorChuck Lever <chuck.lever@oracle.com>
Wed, 8 Oct 2025 13:52:29 +0000 (09:52 -0400)
committerChuck Lever <chuck.lever@oracle.com>
Sun, 16 Nov 2025 23:20:11 +0000 (18:20 -0500)
In order to detect when a direct READ is possible, we need the send
buffer's .page_len to be zero when there is nothing in the buffer's
.pages array yet.

However, when xdr_reserve_space_vec() extends the size of the
xdr_stream to accommodate a READ payload, it adds to the send
buffer's .page_len.

It should be safe to reserve the stream space /after/ the VFS read
operation completes. This is, for example, how an NFSv3 READ works:
the VFS read goes into the rq_bvec, and is then added to the send
xdr_stream later by svcxdr_encode_opaque_pages().

Now that xdr_reserve_space_vec() uses the number of bytes actually
read, the xdr_truncate_encode() call is no longer necessary.

Reviewed-by: NeilBrown <neil@brown.name>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
fs/nfsd/nfs4xdr.c

index 494a703e05708b7965714f526f92aba1dfe9a1f7..30ce5851fe4c4932c767c04fdfdf79ea3f6fba59 100644 (file)
@@ -4480,18 +4480,30 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp,
        __be32 zero = xdr_zero;
        __be32 nfserr;
 
-       if (xdr_reserve_space_vec(xdr, maxcount) < 0)
-               return nfserr_resource;
-
        nfserr = nfsd_iter_read(resp->rqstp, read->rd_fhp, read->rd_nf,
                                read->rd_offset, &maxcount, base,
                                &read->rd_eof);
        read->rd_length = maxcount;
        if (nfserr)
                return nfserr;
+
+       /*
+        * svcxdr_encode_opaque_pages() is not used here because
+        * we don't want to encode subsequent results in this
+        * COMPOUND into the xdr->buf's tail, but rather those
+        * results should follow the NFS READ payload in the
+        * buf's pages.
+        */
+       if (xdr_reserve_space_vec(xdr, maxcount) < 0)
+               return nfserr_resource;
+
+       /*
+        * Mark the buffer location of the NFS READ payload so that
+        * direct placement-capable transports send only the
+        * payload bytes out-of-band.
+        */
        if (svc_encode_result_payload(resp->rqstp, starting_len, maxcount))
                return nfserr_io;
-       xdr_truncate_encode(xdr, starting_len + xdr_align_size(maxcount));
 
        write_bytes_to_xdr_buf(xdr->buf, starting_len + maxcount, &zero,
                               xdr_pad_size(maxcount));