NFSv4.2: Fix READ_PLUS size calculations
authorAnna Schumaker <Anna.Schumaker@Netapp.com>
Wed, 31 May 2023 21:02:54 +0000 (17:02 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 13 Sep 2023 07:42:48 +0000 (09:42 +0200)
[ Upstream commit 8d18f6c5bb864d97a730f471c56cdecf313efe64 ]

I bump the decode_read_plus_maxsz to account for hole segments, but I
need to subtract out this increase when calling
rpc_prepare_reply_pages() so the common case of single data segment
replies can be directly placed into the xdr pages without needing to be
shifted around.

Reported-by: Chuck Lever <chuck.lever@oracle.com>
Fixes: d3b00a802c845 ("NFS: Replace the READ_PLUS decoding code")
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
fs/nfs/nfs42xdr.c

index ef3b150..7576538 100644 (file)
                                        (1 /* data_content4 */ + \
                                         2 /* data_info4.di_offset */ + \
                                         1 /* data_info4.di_length */)
+#define NFS42_READ_PLUS_HOLE_SEGMENT_SIZE \
+                                       (1 /* data_content4 */ + \
+                                        2 /* data_info4.di_offset */ + \
+                                        2 /* data_info4.di_length */)
+#define READ_PLUS_SEGMENT_SIZE_DIFF    (NFS42_READ_PLUS_HOLE_SEGMENT_SIZE - \
+                                        NFS42_READ_PLUS_DATA_SEGMENT_SIZE)
 #define decode_read_plus_maxsz         (op_decode_hdr_maxsz + \
                                         1 /* rpr_eof */ + \
                                         1 /* rpr_contents count */ + \
-                                        NFS42_READ_PLUS_DATA_SEGMENT_SIZE)
+                                        NFS42_READ_PLUS_HOLE_SEGMENT_SIZE)
 #define encode_seek_maxsz              (op_encode_hdr_maxsz + \
                                         encode_stateid_maxsz + \
                                         2 /* offset */ + \
@@ -781,8 +787,8 @@ static void nfs4_xdr_enc_read_plus(struct rpc_rqst *req,
        encode_putfh(xdr, args->fh, &hdr);
        encode_read_plus(xdr, args, &hdr);
 
-       rpc_prepare_reply_pages(req, args->pages, args->pgbase,
-                               args->count, hdr.replen);
+       rpc_prepare_reply_pages(req, args->pages, args->pgbase, args->count,
+                               hdr.replen - READ_PLUS_SEGMENT_SIZE_DIFF);
        encode_nops(&hdr);
 }