diff mbox series

[08/16] SUNRPC: Avoid unnecessary copies in xdr_buf_pages_copy_left/right()

Message ID 20201209144801.700778-9-trondmy@kernel.org (mailing list archive)
State New
Headers show
Series Fixes for the NFSv4.2 READ_PLUS operation | expand

Commit Message

trondmy@kernel.org Dec. 9, 2020, 2:47 p.m. UTC
From: Trond Myklebust <trond.myklebust@hammerspace.com>

Moving data in the XDR page arrays can be expensive, since it can
involve touching up to a megabyte of data. Try to avoid doing so for the
case where the server returned less data than we preallocated.

Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
---
 net/sunrpc/xdr.c | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)
diff mbox series

Patch

diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c
index 7ca6208e7623..86a48c4cdcfc 100644
--- a/net/sunrpc/xdr.c
+++ b/net/sunrpc/xdr.c
@@ -600,14 +600,20 @@  static void xdr_buf_tail_shift_right(const struct xdr_buf *buf,
 static void xdr_buf_pages_shift_right(const struct xdr_buf *buf,
 				      unsigned int base, unsigned int shift)
 {
+	struct xdr_buf subbuf;
+
 	if (!shift)
 		return;
 	if (base >= buf->page_len) {
 		xdr_buf_tail_shift_right(buf, base - buf->page_len, shift);
 		return;
 	}
-	xdr_buf_tail_shift_right(buf, 0, shift);
-	xdr_buf_pages_copy_right(buf, base, shift);
+	base += buf->head->iov_len;
+	if (base >= buf->len)
+		return;
+	xdr_buf_subsegment(buf, &subbuf, base, buf->len - base);
+	xdr_buf_tail_shift_right(&subbuf, 0, shift);
+	xdr_buf_pages_copy_right(&subbuf, 0, shift);
 }
 
 static void xdr_buf_head_shift_right(const struct xdr_buf *buf,
@@ -710,14 +716,16 @@  static void xdr_buf_tail_shift_left(const struct xdr_buf *buf,
 static void xdr_buf_pages_shift_left(const struct xdr_buf *buf,
 				     unsigned int base, unsigned int shift)
 {
+	struct xdr_buf subbuf;
 	if (!shift)
 		return;
 	if (base >= buf->page_len) {
 		xdr_buf_tail_shift_left(buf, base - buf->page_len, shift);
 		return;
 	}
-	xdr_buf_pages_copy_left(buf, base, shift);
-	xdr_buf_tail_shift_left(buf, 0, shift);
+	xdr_buf_subsegment(buf, &subbuf, 0, buf->len);
+	xdr_buf_pages_copy_left(&subbuf, base, shift);
+	xdr_buf_tail_shift_left(&subbuf, 0, shift);
 }
 
 /**