All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/5] Fix NFSv3 READDIRPLUS failures
@ 2022-06-07 20:47 Chuck Lever
  2022-06-07 20:47 ` [PATCH v2 1/5] SUNRPC: Fix the calculation of xdr->end in xdr_get_next_encode_buffer() Chuck Lever
                   ` (5 more replies)
  0 siblings, 6 replies; 8+ messages in thread
From: Chuck Lever @ 2022-06-07 20:47 UTC (permalink / raw)
  To: linux-nfs; +Cc: trondmy, anna.schumaker

NFSD's new READDIRPLUS dirent encoder blows past the end of the
directory payload xdr_stream when the client requests more than a
page worth of directory entries. I tracked this down to how
xdr_get_next_encode_buffer() computes xdr->end. First patch in this
series is the fix. The remaining patches are clean-ups and
optimizations.

I want to get this series into 5.19-rc quickly. I would appreciate
getting one more R-b for this series, preferrably from one of the
NFS client maintainers.


Changes since v1:
- Adjusted patch 2/5 per Neil Brown's suggestion
- Series applied to my NFS client and tested there

---

Chuck Lever (5):
      SUNRPC: Fix the calculation of xdr->end in xdr_get_next_encode_buffer()
      SUNRPC: Optimize xdr_reserve_space()
      SUNRPC: Clean up xdr_commit_encode()
      SUNRPC: Clean up xdr_get_next_encode_buffer()
      SUNRPC: Remove pointer type casts from xdr_get_next_encode_buffer()


 include/linux/sunrpc/xdr.h | 16 +++++++++++++++-
 net/sunrpc/xdr.c           | 37 +++++++++++++++++++++++--------------
 2 files changed, 38 insertions(+), 15 deletions(-)

--
Chuck Lever


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v2 1/5] SUNRPC: Fix the calculation of xdr->end in xdr_get_next_encode_buffer()
  2022-06-07 20:47 [PATCH v2 0/5] Fix NFSv3 READDIRPLUS failures Chuck Lever
@ 2022-06-07 20:47 ` Chuck Lever
  2022-06-07 20:47 ` [PATCH v2 2/5] SUNRPC: Optimize xdr_reserve_space() Chuck Lever
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 8+ messages in thread
From: Chuck Lever @ 2022-06-07 20:47 UTC (permalink / raw)
  To: linux-nfs; +Cc: trondmy, anna.schumaker

I found that NFSD's new NFSv3 READDIRPLUS XDR encoder was screwing up
right at the end of the page array. xdr_get_next_encode_buffer() does
not compute the value of xdr->end correctly:

 * The check to see if we're on the final available page in xdr->buf
   needs to account for the space consumed by @nbytes.

 * The new xdr->end value needs to account for the portion of @nbytes
   that is to be encoded into the previous buffer.

Fixes: 2825a7f90753 ("nfsd4: allow encoding across page boundaries")
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Reviewed-by: NeilBrown <neilb@suse.de>
---
 net/sunrpc/xdr.c |    6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c
index df194cc07035..b57cf9df4de8 100644
--- a/net/sunrpc/xdr.c
+++ b/net/sunrpc/xdr.c
@@ -979,7 +979,11 @@ static __be32 *xdr_get_next_encode_buffer(struct xdr_stream *xdr,
 	 */
 	xdr->p = (void *)p + frag2bytes;
 	space_left = xdr->buf->buflen - xdr->buf->len;
-	xdr->end = (void *)p + min_t(int, space_left, PAGE_SIZE);
+	if (space_left - nbytes >= PAGE_SIZE)
+		xdr->end = (void *)p + PAGE_SIZE;
+	else
+		xdr->end = (void *)p + space_left - frag1bytes;
+
 	xdr->buf->page_len += frag2bytes;
 	xdr->buf->len += nbytes;
 	return p;



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 2/5] SUNRPC: Optimize xdr_reserve_space()
  2022-06-07 20:47 [PATCH v2 0/5] Fix NFSv3 READDIRPLUS failures Chuck Lever
  2022-06-07 20:47 ` [PATCH v2 1/5] SUNRPC: Fix the calculation of xdr->end in xdr_get_next_encode_buffer() Chuck Lever
@ 2022-06-07 20:47 ` Chuck Lever
  2022-06-07 20:48 ` [PATCH v2 3/5] SUNRPC: Clean up xdr_commit_encode() Chuck Lever
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 8+ messages in thread
From: Chuck Lever @ 2022-06-07 20:47 UTC (permalink / raw)
  To: linux-nfs; +Cc: trondmy, anna.schumaker

Transitioning between encode buffers is quite infrequent. It happens
about 1 time in 400 calls to xdr_reserve_space(), measured on NFSD
with a typical build/test workload.

Force the compiler to remove that code from xdr_reserve_space(),
which is a hot path on both the server and the client. This change
reduces the size of xdr_reserve_space() from 10 cache lines to 2
when compiled with -Os.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 include/linux/sunrpc/xdr.h |   16 +++++++++++++++-
 net/sunrpc/xdr.c           |   17 ++++++++++-------
 2 files changed, 25 insertions(+), 8 deletions(-)

diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h
index 4417f667c757..5860f32e3958 100644
--- a/include/linux/sunrpc/xdr.h
+++ b/include/linux/sunrpc/xdr.h
@@ -243,7 +243,7 @@ extern void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf,
 extern __be32 *xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes);
 extern int xdr_reserve_space_vec(struct xdr_stream *xdr, struct kvec *vec,
 		size_t nbytes);
-extern void xdr_commit_encode(struct xdr_stream *xdr);
+extern void __xdr_commit_encode(struct xdr_stream *xdr);
 extern void xdr_truncate_encode(struct xdr_stream *xdr, size_t len);
 extern int xdr_restrict_buflen(struct xdr_stream *xdr, int newbuflen);
 extern void xdr_write_pages(struct xdr_stream *xdr, struct page **pages,
@@ -306,6 +306,20 @@ xdr_reset_scratch_buffer(struct xdr_stream *xdr)
 	xdr_set_scratch_buffer(xdr, NULL, 0);
 }
 
+/**
+ * xdr_commit_encode - Ensure all data is written to xdr->buf
+ * @xdr: pointer to xdr_stream
+ *
+ * Handle encoding across page boundaries by giving the caller a
+ * temporary location to write to, then later copying the data into
+ * place. __xdr_commit_encode() does that copying.
+ */
+static inline void xdr_commit_encode(struct xdr_stream *xdr)
+{
+	if (unlikely(xdr->scratch.iov_len))
+		__xdr_commit_encode(xdr);
+}
+
 /**
  * xdr_stream_remaining - Return the number of bytes remaining in the stream
  * @xdr: pointer to struct xdr_stream
diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c
index b57cf9df4de8..1ad8b4ef14de 100644
--- a/net/sunrpc/xdr.c
+++ b/net/sunrpc/xdr.c
@@ -919,7 +919,7 @@ void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p,
 EXPORT_SYMBOL_GPL(xdr_init_encode);
 
 /**
- * xdr_commit_encode - Ensure all data is written to buffer
+ * __xdr_commit_encode - Ensure all data is written to buffer
  * @xdr: pointer to xdr_stream
  *
  * We handle encoding across page boundaries by giving the caller a
@@ -931,22 +931,25 @@ EXPORT_SYMBOL_GPL(xdr_init_encode);
  * required at the end of encoding, or any other time when the xdr_buf
  * data might be read.
  */
-inline void xdr_commit_encode(struct xdr_stream *xdr)
+void __xdr_commit_encode(struct xdr_stream *xdr)
 {
 	int shift = xdr->scratch.iov_len;
 	void *page;
 
-	if (shift == 0)
-		return;
 	page = page_address(*xdr->page_ptr);
 	memcpy(xdr->scratch.iov_base, page, shift);
 	memmove(page, page + shift, (void *)xdr->p - page);
 	xdr_reset_scratch_buffer(xdr);
 }
-EXPORT_SYMBOL_GPL(xdr_commit_encode);
+EXPORT_SYMBOL_GPL(__xdr_commit_encode);
 
-static __be32 *xdr_get_next_encode_buffer(struct xdr_stream *xdr,
-		size_t nbytes)
+/*
+ * The buffer space to be reserved crosses the boundary between
+ * xdr->buf->head and xdr->buf->pages, or between two pages
+ * in xdr->buf->pages.
+ */
+static noinline __be32 *xdr_get_next_encode_buffer(struct xdr_stream *xdr,
+						   size_t nbytes)
 {
 	__be32 *p;
 	int space_left;



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 3/5] SUNRPC: Clean up xdr_commit_encode()
  2022-06-07 20:47 [PATCH v2 0/5] Fix NFSv3 READDIRPLUS failures Chuck Lever
  2022-06-07 20:47 ` [PATCH v2 1/5] SUNRPC: Fix the calculation of xdr->end in xdr_get_next_encode_buffer() Chuck Lever
  2022-06-07 20:47 ` [PATCH v2 2/5] SUNRPC: Optimize xdr_reserve_space() Chuck Lever
@ 2022-06-07 20:48 ` Chuck Lever
  2022-06-07 20:48 ` [PATCH v2 4/5] SUNRPC: Clean up xdr_get_next_encode_buffer() Chuck Lever
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 8+ messages in thread
From: Chuck Lever @ 2022-06-07 20:48 UTC (permalink / raw)
  To: linux-nfs; +Cc: trondmy, anna.schumaker

Both the kvec::iov_len field and the third parameter of memcpy() and
memmove() are size_t. There's no reason for the implicit conversion
from size_t to int and back. Change the type of @shift to make the
code easier to read and understand.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Reviewed-by: NeilBrown <neilb@suse.de>
---
 net/sunrpc/xdr.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c
index 1ad8b4ef14de..3c182041e790 100644
--- a/net/sunrpc/xdr.c
+++ b/net/sunrpc/xdr.c
@@ -933,7 +933,7 @@ EXPORT_SYMBOL_GPL(xdr_init_encode);
  */
 void __xdr_commit_encode(struct xdr_stream *xdr)
 {
-	int shift = xdr->scratch.iov_len;
+	size_t shift = xdr->scratch.iov_len;
 	void *page;
 
 	page = page_address(*xdr->page_ptr);



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 4/5] SUNRPC: Clean up xdr_get_next_encode_buffer()
  2022-06-07 20:47 [PATCH v2 0/5] Fix NFSv3 READDIRPLUS failures Chuck Lever
                   ` (2 preceding siblings ...)
  2022-06-07 20:48 ` [PATCH v2 3/5] SUNRPC: Clean up xdr_commit_encode() Chuck Lever
@ 2022-06-07 20:48 ` Chuck Lever
  2022-06-07 20:48 ` [PATCH v2 5/5] SUNRPC: Remove pointer type casts from xdr_get_next_encode_buffer() Chuck Lever
  2022-06-08 16:31 ` [PATCH v2 0/5] Fix NFSv3 READDIRPLUS failures J. Bruce Fields
  5 siblings, 0 replies; 8+ messages in thread
From: Chuck Lever @ 2022-06-07 20:48 UTC (permalink / raw)
  To: linux-nfs; +Cc: trondmy, anna.schumaker

The value of @p is not used until the "location of the next item" is
computed. Help human readers by moving its initial assignment to the
paragraph where that value is used and by clarifying the antecedents
in the documenting comment.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Reviewed-by: NeilBrown <neilb@suse.com>
---
 net/sunrpc/xdr.c |    8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c
index 3c182041e790..eca02d122476 100644
--- a/net/sunrpc/xdr.c
+++ b/net/sunrpc/xdr.c
@@ -967,6 +967,7 @@ static noinline __be32 *xdr_get_next_encode_buffer(struct xdr_stream *xdr,
 		xdr->buf->page_len += frag1bytes;
 	xdr->page_ptr++;
 	xdr->iov = NULL;
+
 	/*
 	 * If the last encode didn't end exactly on a page boundary, the
 	 * next one will straddle boundaries.  Encode into the next
@@ -975,11 +976,12 @@ static noinline __be32 *xdr_get_next_encode_buffer(struct xdr_stream *xdr,
 	 * space at the end of the previous buffer:
 	 */
 	xdr_set_scratch_buffer(xdr, xdr->p, frag1bytes);
-	p = page_address(*xdr->page_ptr);
+
 	/*
-	 * Note this is where the next encode will start after we've
-	 * shifted this one back:
+	 * xdr->p is where the next encode will start after
+	 * xdr_commit_encode() has shifted this one back:
 	 */
+	p = page_address(*xdr->page_ptr);
 	xdr->p = (void *)p + frag2bytes;
 	space_left = xdr->buf->buflen - xdr->buf->len;
 	if (space_left - nbytes >= PAGE_SIZE)



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 5/5] SUNRPC: Remove pointer type casts from xdr_get_next_encode_buffer()
  2022-06-07 20:47 [PATCH v2 0/5] Fix NFSv3 READDIRPLUS failures Chuck Lever
                   ` (3 preceding siblings ...)
  2022-06-07 20:48 ` [PATCH v2 4/5] SUNRPC: Clean up xdr_get_next_encode_buffer() Chuck Lever
@ 2022-06-07 20:48 ` Chuck Lever
  2022-06-08 16:31 ` [PATCH v2 0/5] Fix NFSv3 READDIRPLUS failures J. Bruce Fields
  5 siblings, 0 replies; 8+ messages in thread
From: Chuck Lever @ 2022-06-07 20:48 UTC (permalink / raw)
  To: linux-nfs; +Cc: trondmy, anna.schumaker

To make the code easier to read, remove visual clutter by changing
the declared type of @p.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Reviewed-by: NeilBrown <neilb@suse.de>
---
 net/sunrpc/xdr.c |    8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c
index eca02d122476..f87a2d8f23a7 100644
--- a/net/sunrpc/xdr.c
+++ b/net/sunrpc/xdr.c
@@ -951,9 +951,9 @@ EXPORT_SYMBOL_GPL(__xdr_commit_encode);
 static noinline __be32 *xdr_get_next_encode_buffer(struct xdr_stream *xdr,
 						   size_t nbytes)
 {
-	__be32 *p;
 	int space_left;
 	int frag1bytes, frag2bytes;
+	void *p;
 
 	if (nbytes > PAGE_SIZE)
 		goto out_overflow; /* Bigger buffers require special handling */
@@ -982,12 +982,12 @@ static noinline __be32 *xdr_get_next_encode_buffer(struct xdr_stream *xdr,
 	 * xdr_commit_encode() has shifted this one back:
 	 */
 	p = page_address(*xdr->page_ptr);
-	xdr->p = (void *)p + frag2bytes;
+	xdr->p = p + frag2bytes;
 	space_left = xdr->buf->buflen - xdr->buf->len;
 	if (space_left - nbytes >= PAGE_SIZE)
-		xdr->end = (void *)p + PAGE_SIZE;
+		xdr->end = p + PAGE_SIZE;
 	else
-		xdr->end = (void *)p + space_left - frag1bytes;
+		xdr->end = p + space_left - frag1bytes;
 
 	xdr->buf->page_len += frag2bytes;
 	xdr->buf->len += nbytes;



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 0/5] Fix NFSv3 READDIRPLUS failures
  2022-06-07 20:47 [PATCH v2 0/5] Fix NFSv3 READDIRPLUS failures Chuck Lever
                   ` (4 preceding siblings ...)
  2022-06-07 20:48 ` [PATCH v2 5/5] SUNRPC: Remove pointer type casts from xdr_get_next_encode_buffer() Chuck Lever
@ 2022-06-08 16:31 ` J. Bruce Fields
  2022-06-08 16:35   ` Chuck Lever III
  5 siblings, 1 reply; 8+ messages in thread
From: J. Bruce Fields @ 2022-06-08 16:31 UTC (permalink / raw)
  To: Chuck Lever; +Cc: linux-nfs, trondmy, anna.schumaker

Looks good.  Feel free to add my reviewed-by:.

Do we have a test that reads a large enough directory?  Seems like that
plus the right kernel debugging options should have caught the original
bug.

--b.

On Tue, Jun 07, 2022 at 04:47:45PM -0400, Chuck Lever wrote:
> NFSD's new READDIRPLUS dirent encoder blows past the end of the
> directory payload xdr_stream when the client requests more than a
> page worth of directory entries. I tracked this down to how
> xdr_get_next_encode_buffer() computes xdr->end. First patch in this
> series is the fix. The remaining patches are clean-ups and
> optimizations.
> 
> I want to get this series into 5.19-rc quickly. I would appreciate
> getting one more R-b for this series, preferrably from one of the
> NFS client maintainers.
> 
> 
> Changes since v1:
> - Adjusted patch 2/5 per Neil Brown's suggestion
> - Series applied to my NFS client and tested there
> 
> ---
> 
> Chuck Lever (5):
>       SUNRPC: Fix the calculation of xdr->end in xdr_get_next_encode_buffer()
>       SUNRPC: Optimize xdr_reserve_space()
>       SUNRPC: Clean up xdr_commit_encode()
>       SUNRPC: Clean up xdr_get_next_encode_buffer()
>       SUNRPC: Remove pointer type casts from xdr_get_next_encode_buffer()
> 
> 
>  include/linux/sunrpc/xdr.h | 16 +++++++++++++++-
>  net/sunrpc/xdr.c           | 37 +++++++++++++++++++++++--------------
>  2 files changed, 38 insertions(+), 15 deletions(-)
> 
> --
> Chuck Lever

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 0/5] Fix NFSv3 READDIRPLUS failures
  2022-06-08 16:31 ` [PATCH v2 0/5] Fix NFSv3 READDIRPLUS failures J. Bruce Fields
@ 2022-06-08 16:35   ` Chuck Lever III
  0 siblings, 0 replies; 8+ messages in thread
From: Chuck Lever III @ 2022-06-08 16:35 UTC (permalink / raw)
  To: Bruce Fields; +Cc: Linux NFS Mailing List, Trond Myklebust, Anna Schumaker



> On Jun 8, 2022, at 12:31 PM, J. Bruce Fields <bfields@fieldses.org> wrote:
> 
> Looks good.  Feel free to add my reviewed-by:.

Thanks!


> Do we have a test that reads a large enough directory?

Yes. I've been using a script that downloads and builds git, then runs
its unit test suite. That generates multi-page directory entry payloads.


> Seems like that
> plus the right kernel debugging options should have caught the original
> bug.

Yep, it triggered svcrdma_small_wrch_err.


--
Chuck Lever




^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2022-06-08 16:35 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-07 20:47 [PATCH v2 0/5] Fix NFSv3 READDIRPLUS failures Chuck Lever
2022-06-07 20:47 ` [PATCH v2 1/5] SUNRPC: Fix the calculation of xdr->end in xdr_get_next_encode_buffer() Chuck Lever
2022-06-07 20:47 ` [PATCH v2 2/5] SUNRPC: Optimize xdr_reserve_space() Chuck Lever
2022-06-07 20:48 ` [PATCH v2 3/5] SUNRPC: Clean up xdr_commit_encode() Chuck Lever
2022-06-07 20:48 ` [PATCH v2 4/5] SUNRPC: Clean up xdr_get_next_encode_buffer() Chuck Lever
2022-06-07 20:48 ` [PATCH v2 5/5] SUNRPC: Remove pointer type casts from xdr_get_next_encode_buffer() Chuck Lever
2022-06-08 16:31 ` [PATCH v2 0/5] Fix NFSv3 READDIRPLUS failures J. Bruce Fields
2022-06-08 16:35   ` Chuck Lever III

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.