All of lore.kernel.org
 help / color / mirror / Atom feed
* FAILED: patch "[PATCH] sunrpc: defer rq_argp and rq_resp free until after RCU grace" failed to apply to 6.1-stable tree
@ 2026-09-03 14:06 gregkh
  2026-09-09  0:25 ` [PATCH 6.1.y 1/5] SUNRPC: remove timeout arg from svc_recv() Sasha Levin
  2026-09-09  0:25 ` [PATCH 6.1.y 1/5] SUNRPC: remove timeout arg from svc_recv() Sasha Levin
  0 siblings, 2 replies; 11+ messages in thread
From: gregkh @ 2026-09-03 14:06 UTC (permalink / raw)
  To: jlayton, cel; +Cc: stable


The patch below does not apply to the 6.1-stable tree.
If someone wants it applied there, or to any other stable or longterm
tree, then please email the backport, including the original git commit
id to <stable@vger.kernel.org>.

To reproduce the conflict and resubmit, you may use the following commands:

git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.1.y
git checkout FETCH_HEAD
git cherry-pick -x c479bde671cbe2f9e152834a8b0eb7c3c295bbaf
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<stable@vger.kernel.org>' --in-reply-to '2026090350-comment-projector-6988@gregkh' --subject-prefix 'PATCH 6.1.y' 'HEAD^..'

Possible dependencies:



thanks,

greg k-h

------------------ original commit in Linus's tree ------------------

From c479bde671cbe2f9e152834a8b0eb7c3c295bbaf Mon Sep 17 00:00:00 2001
From: Jeff Layton <jlayton@kernel.org>
Date: Thu, 11 Jun 2026 16:00:47 -0400
Subject: [PATCH] sunrpc: defer rq_argp and rq_resp free until after RCU grace
 period
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

svc_rqst_free() frees rqstp->rq_argp and rqstp->rq_resp synchronously
via kfree(), but defers the rqstp struct free via kfree_rcu().  After
svc_exit_thread() calls list_del_rcu() and svc_rqst_free(), there is
a window where RCU readers that started before list_del_rcu() can still
traverse the thread list and find the rqstp.  These readers (e.g.
nfsd_nl_rpc_status_get_dumpit()) dereference rqstp->rq_argp, which has
already been freed — a use-after-free.

Fix this by moving the kfree of rq_argp and rq_resp into an explicit
call_rcu() callback alongside the struct free.  Resources not accessed
by RCU readers (bvec, buffer pages, scratch folio, auth_data) remain
synchronously freed.

Fixes: 812443865c5f ("sunrpc: add a rcu_head to svc_rqst and use kfree_rcu to free it")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Jeff Layton <jlayton@kernel.org>
Link: https://patch.msgid.link/20260611-nfsd-testing-v2-4-5b90e276f2d9@kernel.org
Signed-off-by: Chuck Lever <cel@kernel.org>

diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 86d39610cf0a..dd80a2eaaa74 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -716,6 +716,15 @@ svc_release_buffer(struct svc_rqst *rqstp)
 	}
 }
 
+static void svc_rqst_free_rcu(struct rcu_head *head)
+{
+	struct svc_rqst *rqstp = container_of(head, struct svc_rqst, rq_rcu_head);
+
+	kfree(rqstp->rq_resp);
+	kfree(rqstp->rq_argp);
+	kfree(rqstp);
+}
+
 static void
 svc_rqst_free(struct svc_rqst *rqstp)
 {
@@ -724,10 +733,8 @@ svc_rqst_free(struct svc_rqst *rqstp)
 	svc_release_buffer(rqstp);
 	if (rqstp->rq_scratch_folio)
 		folio_put(rqstp->rq_scratch_folio);
-	kfree(rqstp->rq_resp);
-	kfree(rqstp->rq_argp);
 	kfree(rqstp->rq_auth_data);
-	kfree_rcu(rqstp, rq_rcu_head);
+	call_rcu(&rqstp->rq_rcu_head, svc_rqst_free_rcu);
 }
 
 static struct svc_rqst *


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

* [PATCH 6.1.y 1/5] SUNRPC: remove timeout arg from svc_recv()
  2026-09-03 14:06 FAILED: patch "[PATCH] sunrpc: defer rq_argp and rq_resp free until after RCU grace" failed to apply to 6.1-stable tree gregkh
@ 2026-09-09  0:25 ` Sasha Levin
  2026-09-09  0:25   ` [PATCH 6.1.y 2/5] SUNRPC: make various functions static, or not exported Sasha Levin
                     ` (3 more replies)
  2026-09-09  0:25 ` [PATCH 6.1.y 1/5] SUNRPC: remove timeout arg from svc_recv() Sasha Levin
  1 sibling, 4 replies; 11+ messages in thread
From: Sasha Levin @ 2026-09-09  0:25 UTC (permalink / raw)
  To: stable; +Cc: NeilBrown, Chuck Lever, Sasha Levin

From: NeilBrown <neilb@suse.de>

[ Upstream commit c743b4259c3af2c0637c307f08a062d25fa3c99f ]

Most svc threads have no interest in a timeout.
nfsd sets it to 1 hour, but this is a wart of no significance.

lockd uses the timeout so that it can call nlmsvc_retry_blocked().
It also sometimes calls svc_wake_up() to ensure this is called.

So change lockd to be consistent and always use svc_wake_up() to trigger
nlmsvc_retry_blocked() - using a timer instead of a timeout to
svc_recv().

And change svc_recv() to not take a timeout arg.

This makes the sp_threads_timedout counter always zero.

Signed-off-by: NeilBrown <neilb@suse.de>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>

[ Stable backport note: The svc_recv timeout cleanup is unrelated to the
follow-up fix and does not fit the older lockd service loop. Drop those
hunks. Instead, make the existing svc request allocation/free helpers
private, move svc_rqst_free() before its first use, and convert the
scratch page to a folio. This aligns the lifetime-management context so
the follow-up fix applies cleanly. ]

[ sashal: Reduced backport -- upstream c743b4259c3af touches 9 file(s), this
  backport carries 2. Not backported here:
  fs/lockd/svc.c
  fs/lockd/svclock.c
  fs/nfs/callback.c
  fs/nfsd/nfssvc.c
  include/linux/lockd/lockd.h
  include/linux/sunrpc/svcsock.h
  net/sunrpc/svc_xprt.c
  This note is generated from the file lists only; see the resolution record
  for the reasoning. ]

Stable-dep-of: c479bde671cb ("sunrpc: defer rq_argp and rq_resp free until after RCU grace period")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 include/linux/sunrpc/svc.h |  7 ++-----
 net/sunrpc/svc.c           | 38 +++++++++++++++++---------------------
 2 files changed, 19 insertions(+), 26 deletions(-)

diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index 49621cc4e01bd..d26e01c63dde0 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -247,7 +247,7 @@ struct svc_rqst {
 	struct xdr_buf		rq_arg;
 	struct xdr_stream	rq_arg_stream;
 	struct xdr_stream	rq_res_stream;
-	struct page		*rq_scratch_page;
+	struct folio		*rq_scratch_folio;
 	struct xdr_buf		rq_res;
 	struct page		*rq_pages[RPCSVC_MAXPAGES + 1];
 	struct page *		*rq_respages;	/* points into rq_pages */
@@ -473,11 +473,8 @@ void svc_rpcb_cleanup(struct svc_serv *serv, struct net *net);
 int svc_bind(struct svc_serv *serv, struct net *net);
 struct svc_serv *svc_create(struct svc_program *, unsigned int,
 			    int (*threadfn)(void *data));
-struct svc_rqst *svc_rqst_alloc(struct svc_serv *serv,
-					struct svc_pool *pool, int node);
 void		   svc_rqst_replace_page(struct svc_rqst *rqstp,
 					 struct page *page);
-void		   svc_rqst_free(struct svc_rqst *);
 void		   svc_exit_thread(struct svc_rqst *);
 struct svc_serv *  svc_create_pooled(struct svc_program *prog,
 				     struct svc_stat *stats,
@@ -554,7 +551,7 @@ static inline void svcxdr_init_decode(struct svc_rqst *rqstp)
 	buf->len = buf->head->iov_len + buf->page_len + buf->tail->iov_len;
 
 	xdr_init_decode(xdr, buf, argv->iov_base, NULL);
-	xdr_set_scratch_page(xdr, rqstp->rq_scratch_page);
+	xdr_set_scratch_page(xdr, folio_page(rqstp->rq_scratch_folio, 0));
 }
 
 /**
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 9ae85347ab397..faa5193231240 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -630,7 +630,19 @@ svc_release_buffer(struct svc_rqst *rqstp)
 			put_page(rqstp->rq_pages[i]);
 }
 
-struct svc_rqst *
+static void
+svc_rqst_free(struct svc_rqst *rqstp)
+{
+	svc_release_buffer(rqstp);
+	if (rqstp->rq_scratch_folio)
+		folio_put(rqstp->rq_scratch_folio);
+	kfree(rqstp->rq_resp);
+	kfree(rqstp->rq_argp);
+	kfree(rqstp->rq_auth_data);
+	kfree_rcu(rqstp, rq_rcu_head);
+}
+
+static struct svc_rqst *
 svc_rqst_alloc(struct svc_serv *serv, struct svc_pool *pool, int node)
 {
 	struct svc_rqst	*rqstp;
@@ -644,8 +656,10 @@ svc_rqst_alloc(struct svc_serv *serv, struct svc_pool *pool, int node)
 	rqstp->rq_server = serv;
 	rqstp->rq_pool = pool;
 
-	rqstp->rq_scratch_page = alloc_pages_node(node, GFP_KERNEL, 0);
-	if (!rqstp->rq_scratch_page)
+	if (node == NUMA_NO_NODE)
+		node = numa_mem_id();
+	rqstp->rq_scratch_folio = __folio_alloc_node(GFP_KERNEL, 0, node);
+	if (!rqstp->rq_scratch_folio)
 		goto out_enomem;
 
 	rqstp->rq_argp = kmalloc_node(serv->sv_xdrsize, GFP_KERNEL, node);
@@ -664,7 +678,6 @@ svc_rqst_alloc(struct svc_serv *serv, struct svc_pool *pool, int node)
 	svc_rqst_free(rqstp);
 	return NULL;
 }
-EXPORT_SYMBOL_GPL(svc_rqst_alloc);
 
 static struct svc_rqst *
 svc_prepare_thread(struct svc_serv *serv, struct svc_pool *pool, int node)
@@ -847,23 +860,6 @@ void svc_rqst_replace_page(struct svc_rqst *rqstp, struct page *page)
 }
 EXPORT_SYMBOL_GPL(svc_rqst_replace_page);
 
-/*
- * Called from a server thread as it's exiting. Caller must hold the "service
- * mutex" for the service.
- */
-void
-svc_rqst_free(struct svc_rqst *rqstp)
-{
-	svc_release_buffer(rqstp);
-	if (rqstp->rq_scratch_page)
-		put_page(rqstp->rq_scratch_page);
-	kfree(rqstp->rq_resp);
-	kfree(rqstp->rq_argp);
-	kfree(rqstp->rq_auth_data);
-	kfree_rcu(rqstp, rq_rcu_head);
-}
-EXPORT_SYMBOL_GPL(svc_rqst_free);
-
 void
 svc_exit_thread(struct svc_rqst *rqstp)
 {
-- 
2.53.0


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

* [PATCH 6.1.y 2/5] SUNRPC: make various functions static, or not exported.
  2026-09-09  0:25 ` [PATCH 6.1.y 1/5] SUNRPC: remove timeout arg from svc_recv() Sasha Levin
@ 2026-09-09  0:25   ` Sasha Levin
  2026-09-09  0:25   ` [PATCH 6.1.y 3/5] SUNRPC: Introduce xdr_set_scratch_folio() Sasha Levin
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 11+ messages in thread
From: Sasha Levin @ 2026-09-09  0:25 UTC (permalink / raw)
  To: stable; +Cc: NeilBrown, Chuck Lever, Sasha Levin

From: NeilBrown <neilb@suse.de>

[ Upstream commit f2b27e1d72527f94f030b6356b3187576e60885b ]

Various functions are only used within the sunrpc module, and several
are only use in the one file.  So clean up:

These are marked static, and any EXPORT is removed.
  svc_rcpb_setup()
  svc_rqst_alloc()
  svc_rqst_free()  - also moved before first use
  svc_rpcbind_set_version()
  svc_drop() - also moved to svc.c

These are now not EXPORTed, but are not static.
  svc_authenticate()
  svc_sock_update_bufs()

Signed-off-by: NeilBrown <neilb@suse.de>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>

[ Stable backport note: svc_rqst_alloc() and svc_rqst_free() are already
  static, and the latter already precedes its first use, in the preceding
  dependency. Keep that implementation and its scratch folio handling.
  Do not import the newer page-release helper or authentication interfaces.

  Retain the visibility cleanup for svc_rpcb_setup(),
  svc_rpcbind_set_version(), svc_authenticate(), and svc_sock_update_bufs().
  Declare svc_authenticate() as int in the private header to match 6.1.
  Keep svc_drop() in svc_xprt.c: it still calls the file-local
  svc_xprt_release(), which upstream no longer calls from svc_drop().

  Add braces around the existing svc_release_buffer() page-release loop,
  without changing its behavior, to provide the exact context required by
  the first hunk of c479bde671cb. No functions are added. ]

[ sashal: Reduced backport -- upstream f2b27e1d72527 touches 8 file(s), this
  backport carries 7. Not backported here:
  net/sunrpc/svc_xprt.c
  This note is generated from the file lists only; see the resolution record
  for the reasoning. ]

Stable-dep-of: c479bde671cb ("sunrpc: defer rq_argp and rq_resp free until after RCU grace period")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 include/linux/sunrpc/svc.h     |  6 ------
 include/linux/sunrpc/svcauth.h |  1 -
 include/linux/sunrpc/svcsock.h |  1 -
 net/sunrpc/sunrpc.h            |  4 ++++
 net/sunrpc/svc.c               | 10 +++++-----
 net/sunrpc/svcauth.c           |  1 -
 net/sunrpc/svcsock.c           |  1 -
 7 files changed, 9 insertions(+), 15 deletions(-)

diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index d26e01c63dde0..4144a256fc255 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -468,7 +468,6 @@ struct svc_procedure {
 /*
  * Function prototypes.
  */
-int svc_rpcb_setup(struct svc_serv *serv, struct net *net);
 void svc_rpcb_cleanup(struct svc_serv *serv, struct net *net);
 int svc_bind(struct svc_serv *serv, struct net *net);
 struct svc_serv *svc_create(struct svc_program *, unsigned int,
@@ -509,11 +508,6 @@ int		   svc_generic_rpcbind_set(struct net *net,
 					   u32 version, int family,
 					   unsigned short proto,
 					   unsigned short port);
-int		   svc_rpcbind_set_version(struct net *net,
-					   const struct svc_program *progp,
-					   u32 version, int family,
-					   unsigned short proto,
-					   unsigned short port);
 
 #define	RPC_MAX_ADDRBUFLEN	(63U)
 
diff --git a/include/linux/sunrpc/svcauth.h b/include/linux/sunrpc/svcauth.h
index 6d9cc9080aca7..5e11fbe1fe463 100644
--- a/include/linux/sunrpc/svcauth.h
+++ b/include/linux/sunrpc/svcauth.h
@@ -149,7 +149,6 @@ struct auth_ops {
 
 struct svc_xprt;
 
-extern int	svc_authenticate(struct svc_rqst *rqstp);
 extern int	svc_authorise(struct svc_rqst *rqstp);
 extern int	svc_set_client(struct svc_rqst *rqstp);
 extern int	svc_auth_register(rpc_authflavor_t flavor, struct auth_ops *aops);
diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h
index 13aff355d5a13..cfcdbf4def22c 100644
--- a/include/linux/sunrpc/svcsock.h
+++ b/include/linux/sunrpc/svcsock.h
@@ -58,7 +58,6 @@ void		svc_close_net(struct svc_serv *, struct net *);
 int		svc_recv(struct svc_rqst *, long);
 int		svc_send(struct svc_rqst *);
 void		svc_drop(struct svc_rqst *);
-void		svc_sock_update_bufs(struct svc_serv *serv);
 int		svc_addsock(struct svc_serv *serv, struct net *net,
 			    const int fd, char *name_return, const size_t len,
 			    const struct cred *cred);
diff --git a/net/sunrpc/sunrpc.h b/net/sunrpc/sunrpc.h
index d4a362c9e4b3b..07ab21b64f904 100644
--- a/net/sunrpc/sunrpc.h
+++ b/net/sunrpc/sunrpc.h
@@ -36,7 +36,11 @@ static inline int sock_is_loopback(struct sock *sk)
 	return loopback;
 }
 
+struct svc_serv;
+struct svc_rqst;
 int rpc_clients_notifier_register(void);
 void rpc_clients_notifier_unregister(void);
 void auth_domain_cleanup(void);
+void svc_sock_update_bufs(struct svc_serv *serv);
+int svc_authenticate(struct svc_rqst *rqstp);
 #endif /* _NET_SUNRPC_SUNRPC_H */
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index faa5193231240..3fe7152ee8bf5 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -32,6 +32,7 @@
 #include <trace/events/sunrpc.h>
 
 #include "fail.h"
+#include "sunrpc.h"
 
 #define RPCDBG_FACILITY	RPCDBG_SVCDSP
 
@@ -388,7 +389,7 @@ struct svc_pool *svc_pool_for_cpu(struct svc_serv *serv)
 	return &serv->sv_pools[pidx % serv->sv_nrpools];
 }
 
-int svc_rpcb_setup(struct svc_serv *serv, struct net *net)
+static int svc_rpcb_setup(struct svc_serv *serv, struct net *net)
 {
 	int err;
 
@@ -400,7 +401,6 @@ int svc_rpcb_setup(struct svc_serv *serv, struct net *net)
 	svc_unregister(serv, net);
 	return 0;
 }
-EXPORT_SYMBOL_GPL(svc_rpcb_setup);
 
 void svc_rpcb_cleanup(struct svc_serv *serv, struct net *net)
 {
@@ -625,9 +625,10 @@ svc_release_buffer(struct svc_rqst *rqstp)
 {
 	unsigned int i;
 
-	for (i = 0; i < ARRAY_SIZE(rqstp->rq_pages); i++)
+	for (i = 0; i < ARRAY_SIZE(rqstp->rq_pages); i++) {
 		if (rqstp->rq_pages[i])
 			put_page(rqstp->rq_pages[i]);
+	}
 }
 
 static void
@@ -1009,7 +1010,7 @@ static int __svc_register(struct net *net, const char *progname,
 	return error;
 }
 
-int svc_rpcbind_set_version(struct net *net,
+static int svc_rpcbind_set_version(struct net *net,
 			    const struct svc_program *progp,
 			    u32 version, int family,
 			    unsigned short proto,
@@ -1019,7 +1020,6 @@ int svc_rpcbind_set_version(struct net *net,
 				version, family, proto, port);
 
 }
-EXPORT_SYMBOL_GPL(svc_rpcbind_set_version);
 
 int svc_generic_rpcbind_set(struct net *net,
 			    const struct svc_program *progp,
diff --git a/net/sunrpc/svcauth.c b/net/sunrpc/svcauth.c
index e72ba2f13f6c6..1694c01bbaf9c 100644
--- a/net/sunrpc/svcauth.c
+++ b/net/sunrpc/svcauth.c
@@ -84,7 +84,6 @@ svc_authenticate(struct svc_rqst *rqstp)
 	rqstp->rq_authop = aops;
 	return aops->accept(rqstp);
 }
-EXPORT_SYMBOL_GPL(svc_authenticate);
 
 int svc_set_client(struct svc_rqst *rqstp)
 {
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 23b4c728de598..e6204afa78fd6 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -1283,7 +1283,6 @@ void svc_sock_update_bufs(struct svc_serv *serv)
 		set_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags);
 	spin_unlock_bh(&serv->sv_lock);
 }
-EXPORT_SYMBOL_GPL(svc_sock_update_bufs);
 
 /*
  * Initialize socket for RPC use and create svc_sock struct
-- 
2.53.0


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

* [PATCH 6.1.y 3/5] SUNRPC: Introduce xdr_set_scratch_folio()
  2026-09-09  0:25 ` [PATCH 6.1.y 1/5] SUNRPC: remove timeout arg from svc_recv() Sasha Levin
  2026-09-09  0:25   ` [PATCH 6.1.y 2/5] SUNRPC: make various functions static, or not exported Sasha Levin
@ 2026-09-09  0:25   ` Sasha Levin
  2026-09-09  0:25   ` [PATCH 6.1.y 4/5] SUNRPC: Update svcxdr_init_decode() to call xdr_set_scratch_folio() Sasha Levin
  2026-09-09  0:25   ` [PATCH 6.1.y 5/5] sunrpc: defer rq_argp and rq_resp free until after RCU grace period Sasha Levin
  3 siblings, 0 replies; 11+ messages in thread
From: Sasha Levin @ 2026-09-09  0:25 UTC (permalink / raw)
  To: stable; +Cc: Anna Schumaker, Sasha Levin

From: Anna Schumaker <anna.schumaker@oracle.com>

[ Upstream commit c8a127596edc026e5364a7a609986dcd3999914c ]

This will replace xdr_set_scratch_page() when we switch pages to folios.

Signed-off-by: Anna Schumaker <anna.schumaker@oracle.com>
Stable-dep-of: c479bde671cb ("sunrpc: defer rq_argp and rq_resp free until after RCU grace period")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 include/linux/sunrpc/xdr.h | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h
index f84e2a1358e17..2b73b3db87d99 100644
--- a/include/linux/sunrpc/xdr.h
+++ b/include/linux/sunrpc/xdr.h
@@ -299,6 +299,19 @@ xdr_set_scratch_page(struct xdr_stream *xdr, struct page *page)
 	xdr_set_scratch_buffer(xdr, page_address(page), PAGE_SIZE);
 }
 
+/**
+ * xdr_set_scratch_folio - Attach a scratch buffer for decoding data
+ * @xdr: pointer to xdr_stream struct
+ * @page: an anonymous folio
+ *
+ * See xdr_set_scratch_buffer().
+ */
+static inline void
+xdr_set_scratch_folio(struct xdr_stream *xdr, struct folio *folio)
+{
+	xdr_set_scratch_buffer(xdr, folio_address(folio), folio_size(folio));
+}
+
 /**
  * xdr_reset_scratch_buffer - Clear scratch buffer information
  * @xdr: pointer to xdr_stream struct
-- 
2.53.0


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

* [PATCH 6.1.y 4/5] SUNRPC: Update svcxdr_init_decode() to call xdr_set_scratch_folio()
  2026-09-09  0:25 ` [PATCH 6.1.y 1/5] SUNRPC: remove timeout arg from svc_recv() Sasha Levin
  2026-09-09  0:25   ` [PATCH 6.1.y 2/5] SUNRPC: make various functions static, or not exported Sasha Levin
  2026-09-09  0:25   ` [PATCH 6.1.y 3/5] SUNRPC: Introduce xdr_set_scratch_folio() Sasha Levin
@ 2026-09-09  0:25   ` Sasha Levin
  2026-09-09  0:25   ` [PATCH 6.1.y 5/5] sunrpc: defer rq_argp and rq_resp free until after RCU grace period Sasha Levin
  3 siblings, 0 replies; 11+ messages in thread
From: Sasha Levin @ 2026-09-09  0:25 UTC (permalink / raw)
  To: stable; +Cc: Anna Schumaker, Sasha Levin

From: Anna Schumaker <anna.schumaker@oracle.com>

[ Upstream commit d57e43b72bf2071caac90da323849c3983a695f0 ]

The only snag here is that __folio_alloc_node() doesn't handle
NUMA_NO_NODE, so I also need to update svc_pool_map_get_node() to return
numa_mem_id() instead. I arrived at this approach by  looking at what
other users of __folio_alloc_node() do for this case.

Signed-off-by: Anna Schumaker <anna.schumaker@oracle.com>

[ Stable backport note: Earlier dependencies already converted rq_scratch_page
  to rq_scratch_folio, including allocation and release. Keep those changes
  and switch svcxdr_init_decode() to the xdr_set_scratch_folio() helper added
  by the immediately preceding dependency.

  Drop the svc_pool_map_get_node() change: svc_rqst_alloc() already converts
  NUMA_NO_NODE to numa_mem_id() before __folio_alloc_node(). Preserve that
  fallback and the existing pool/thread placement policy.

  The resulting dependency changes only the existing decoder helper call;
  no functions are added. The scratch-folio release and surrounding context
  required by c479bde671cb are retained, and its patch applies cleanly. ]

[ sashal: Reduced backport -- upstream d57e43b72bf20 touches 2 file(s), this
  backport carries 1. Not backported here:
  net/sunrpc/svc.c
  This note is generated from the file lists only; see the resolution record
  for the reasoning. ]

Stable-dep-of: c479bde671cb ("sunrpc: defer rq_argp and rq_resp free until after RCU grace period")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 include/linux/sunrpc/svc.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index 4144a256fc255..40ab44b993cf9 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -545,7 +545,7 @@ static inline void svcxdr_init_decode(struct svc_rqst *rqstp)
 	buf->len = buf->head->iov_len + buf->page_len + buf->tail->iov_len;
 
 	xdr_init_decode(xdr, buf, argv->iov_base, NULL);
-	xdr_set_scratch_page(xdr, folio_page(rqstp->rq_scratch_folio, 0));
+	xdr_set_scratch_folio(xdr, rqstp->rq_scratch_folio);
 }
 
 /**
-- 
2.53.0


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

* [PATCH 6.1.y 5/5] sunrpc: defer rq_argp and rq_resp free until after RCU grace period
  2026-09-09  0:25 ` [PATCH 6.1.y 1/5] SUNRPC: remove timeout arg from svc_recv() Sasha Levin
                     ` (2 preceding siblings ...)
  2026-09-09  0:25   ` [PATCH 6.1.y 4/5] SUNRPC: Update svcxdr_init_decode() to call xdr_set_scratch_folio() Sasha Levin
@ 2026-09-09  0:25   ` Sasha Levin
  3 siblings, 0 replies; 11+ messages in thread
From: Sasha Levin @ 2026-09-09  0:25 UTC (permalink / raw)
  To: stable; +Cc: Jeff Layton, Chuck Lever, Sasha Levin

From: Jeff Layton <jlayton@kernel.org>

[ Upstream commit c479bde671cbe2f9e152834a8b0eb7c3c295bbaf ]

svc_rqst_free() frees rqstp->rq_argp and rqstp->rq_resp synchronously
via kfree(), but defers the rqstp struct free via kfree_rcu().  After
svc_exit_thread() calls list_del_rcu() and svc_rqst_free(), there is
a window where RCU readers that started before list_del_rcu() can still
traverse the thread list and find the rqstp.  These readers (e.g.
nfsd_nl_rpc_status_get_dumpit()) dereference rqstp->rq_argp, which has
already been freed — a use-after-free.

Fix this by moving the kfree of rq_argp and rq_resp into an explicit
call_rcu() callback alongside the struct free.  Resources not accessed
by RCU readers (bvec, buffer pages, scratch folio, auth_data) remain
synchronously freed.

Fixes: 812443865c5f ("sunrpc: add a rcu_head to svc_rqst and use kfree_rcu to free it")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Jeff Layton <jlayton@kernel.org>
Link: https://patch.msgid.link/20260611-nfsd-testing-v2-4-5b90e276f2d9@kernel.org
Signed-off-by: Chuck Lever <cel@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 net/sunrpc/svc.c | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 3fe7152ee8bf5..c3d18ff3ce296 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -631,16 +631,23 @@ svc_release_buffer(struct svc_rqst *rqstp)
 	}
 }
 
+static void svc_rqst_free_rcu(struct rcu_head *head)
+{
+	struct svc_rqst *rqstp = container_of(head, struct svc_rqst, rq_rcu_head);
+
+	kfree(rqstp->rq_resp);
+	kfree(rqstp->rq_argp);
+	kfree(rqstp);
+}
+
 static void
 svc_rqst_free(struct svc_rqst *rqstp)
 {
 	svc_release_buffer(rqstp);
 	if (rqstp->rq_scratch_folio)
 		folio_put(rqstp->rq_scratch_folio);
-	kfree(rqstp->rq_resp);
-	kfree(rqstp->rq_argp);
 	kfree(rqstp->rq_auth_data);
-	kfree_rcu(rqstp, rq_rcu_head);
+	call_rcu(&rqstp->rq_rcu_head, svc_rqst_free_rcu);
 }
 
 static struct svc_rqst *
-- 
2.53.0


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

* [PATCH 6.1.y 1/5] SUNRPC: remove timeout arg from svc_recv()
  2026-09-03 14:06 FAILED: patch "[PATCH] sunrpc: defer rq_argp and rq_resp free until after RCU grace" failed to apply to 6.1-stable tree gregkh
  2026-09-09  0:25 ` [PATCH 6.1.y 1/5] SUNRPC: remove timeout arg from svc_recv() Sasha Levin
@ 2026-09-09  0:25 ` Sasha Levin
  2026-09-09  0:25   ` [PATCH 6.1.y 2/5] SUNRPC: make various functions static, or not exported Sasha Levin
                     ` (3 more replies)
  1 sibling, 4 replies; 11+ messages in thread
From: Sasha Levin @ 2026-09-09  0:25 UTC (permalink / raw)
  To: stable; +Cc: NeilBrown, Chuck Lever, Sasha Levin

From: NeilBrown <neilb@suse.de>

[ Upstream commit c743b4259c3af2c0637c307f08a062d25fa3c99f ]

Most svc threads have no interest in a timeout.
nfsd sets it to 1 hour, but this is a wart of no significance.

lockd uses the timeout so that it can call nlmsvc_retry_blocked().
It also sometimes calls svc_wake_up() to ensure this is called.

So change lockd to be consistent and always use svc_wake_up() to trigger
nlmsvc_retry_blocked() - using a timer instead of a timeout to
svc_recv().

And change svc_recv() to not take a timeout arg.

This makes the sp_threads_timedout counter always zero.

Signed-off-by: NeilBrown <neilb@suse.de>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>

[ Stable backport note: The svc_recv timeout cleanup is unrelated to the
follow-up fix and does not fit the older lockd service loop. Drop those
hunks. Instead, make the existing svc request allocation/free helpers
private, move svc_rqst_free() before its first use, and convert the
scratch page to a folio. This aligns the lifetime-management context so
the follow-up fix applies cleanly. ]

[ sashal: Reduced backport -- upstream c743b4259c3af touches 9 file(s), this
  backport carries 2. Not backported here:
  fs/lockd/svc.c
  fs/lockd/svclock.c
  fs/nfs/callback.c
  fs/nfsd/nfssvc.c
  include/linux/lockd/lockd.h
  include/linux/sunrpc/svcsock.h
  net/sunrpc/svc_xprt.c
  This note is generated from the file lists only; see the resolution record
  for the reasoning. ]

Stable-dep-of: c479bde671cb ("sunrpc: defer rq_argp and rq_resp free until after RCU grace period")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 include/linux/sunrpc/svc.h |  7 ++-----
 net/sunrpc/svc.c           | 38 +++++++++++++++++---------------------
 2 files changed, 19 insertions(+), 26 deletions(-)

diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index 49621cc4e01bd..d26e01c63dde0 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -247,7 +247,7 @@ struct svc_rqst {
 	struct xdr_buf		rq_arg;
 	struct xdr_stream	rq_arg_stream;
 	struct xdr_stream	rq_res_stream;
-	struct page		*rq_scratch_page;
+	struct folio		*rq_scratch_folio;
 	struct xdr_buf		rq_res;
 	struct page		*rq_pages[RPCSVC_MAXPAGES + 1];
 	struct page *		*rq_respages;	/* points into rq_pages */
@@ -473,11 +473,8 @@ void svc_rpcb_cleanup(struct svc_serv *serv, struct net *net);
 int svc_bind(struct svc_serv *serv, struct net *net);
 struct svc_serv *svc_create(struct svc_program *, unsigned int,
 			    int (*threadfn)(void *data));
-struct svc_rqst *svc_rqst_alloc(struct svc_serv *serv,
-					struct svc_pool *pool, int node);
 void		   svc_rqst_replace_page(struct svc_rqst *rqstp,
 					 struct page *page);
-void		   svc_rqst_free(struct svc_rqst *);
 void		   svc_exit_thread(struct svc_rqst *);
 struct svc_serv *  svc_create_pooled(struct svc_program *prog,
 				     struct svc_stat *stats,
@@ -554,7 +551,7 @@ static inline void svcxdr_init_decode(struct svc_rqst *rqstp)
 	buf->len = buf->head->iov_len + buf->page_len + buf->tail->iov_len;
 
 	xdr_init_decode(xdr, buf, argv->iov_base, NULL);
-	xdr_set_scratch_page(xdr, rqstp->rq_scratch_page);
+	xdr_set_scratch_page(xdr, folio_page(rqstp->rq_scratch_folio, 0));
 }
 
 /**
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 9ae85347ab397..faa5193231240 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -630,7 +630,19 @@ svc_release_buffer(struct svc_rqst *rqstp)
 			put_page(rqstp->rq_pages[i]);
 }
 
-struct svc_rqst *
+static void
+svc_rqst_free(struct svc_rqst *rqstp)
+{
+	svc_release_buffer(rqstp);
+	if (rqstp->rq_scratch_folio)
+		folio_put(rqstp->rq_scratch_folio);
+	kfree(rqstp->rq_resp);
+	kfree(rqstp->rq_argp);
+	kfree(rqstp->rq_auth_data);
+	kfree_rcu(rqstp, rq_rcu_head);
+}
+
+static struct svc_rqst *
 svc_rqst_alloc(struct svc_serv *serv, struct svc_pool *pool, int node)
 {
 	struct svc_rqst	*rqstp;
@@ -644,8 +656,10 @@ svc_rqst_alloc(struct svc_serv *serv, struct svc_pool *pool, int node)
 	rqstp->rq_server = serv;
 	rqstp->rq_pool = pool;
 
-	rqstp->rq_scratch_page = alloc_pages_node(node, GFP_KERNEL, 0);
-	if (!rqstp->rq_scratch_page)
+	if (node == NUMA_NO_NODE)
+		node = numa_mem_id();
+	rqstp->rq_scratch_folio = __folio_alloc_node(GFP_KERNEL, 0, node);
+	if (!rqstp->rq_scratch_folio)
 		goto out_enomem;
 
 	rqstp->rq_argp = kmalloc_node(serv->sv_xdrsize, GFP_KERNEL, node);
@@ -664,7 +678,6 @@ svc_rqst_alloc(struct svc_serv *serv, struct svc_pool *pool, int node)
 	svc_rqst_free(rqstp);
 	return NULL;
 }
-EXPORT_SYMBOL_GPL(svc_rqst_alloc);
 
 static struct svc_rqst *
 svc_prepare_thread(struct svc_serv *serv, struct svc_pool *pool, int node)
@@ -847,23 +860,6 @@ void svc_rqst_replace_page(struct svc_rqst *rqstp, struct page *page)
 }
 EXPORT_SYMBOL_GPL(svc_rqst_replace_page);
 
-/*
- * Called from a server thread as it's exiting. Caller must hold the "service
- * mutex" for the service.
- */
-void
-svc_rqst_free(struct svc_rqst *rqstp)
-{
-	svc_release_buffer(rqstp);
-	if (rqstp->rq_scratch_page)
-		put_page(rqstp->rq_scratch_page);
-	kfree(rqstp->rq_resp);
-	kfree(rqstp->rq_argp);
-	kfree(rqstp->rq_auth_data);
-	kfree_rcu(rqstp, rq_rcu_head);
-}
-EXPORT_SYMBOL_GPL(svc_rqst_free);
-
 void
 svc_exit_thread(struct svc_rqst *rqstp)
 {
-- 
2.53.0


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

* [PATCH 6.1.y 2/5] SUNRPC: make various functions static, or not exported.
  2026-09-09  0:25 ` [PATCH 6.1.y 1/5] SUNRPC: remove timeout arg from svc_recv() Sasha Levin
@ 2026-09-09  0:25   ` Sasha Levin
  2026-09-09  0:25   ` [PATCH 6.1.y 3/5] SUNRPC: Introduce xdr_set_scratch_folio() Sasha Levin
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 11+ messages in thread
From: Sasha Levin @ 2026-09-09  0:25 UTC (permalink / raw)
  To: stable; +Cc: NeilBrown, Chuck Lever, Sasha Levin

From: NeilBrown <neilb@suse.de>

[ Upstream commit f2b27e1d72527f94f030b6356b3187576e60885b ]

Various functions are only used within the sunrpc module, and several
are only use in the one file.  So clean up:

These are marked static, and any EXPORT is removed.
  svc_rcpb_setup()
  svc_rqst_alloc()
  svc_rqst_free()  - also moved before first use
  svc_rpcbind_set_version()
  svc_drop() - also moved to svc.c

These are now not EXPORTed, but are not static.
  svc_authenticate()
  svc_sock_update_bufs()

Signed-off-by: NeilBrown <neilb@suse.de>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>

[ Stable backport note: svc_rqst_alloc() and svc_rqst_free() are already
  static, and the latter already precedes its first use, in the preceding
  dependency. Keep that implementation and its scratch folio handling.
  Do not import the newer page-release helper or authentication interfaces.

  Retain the visibility cleanup for svc_rpcb_setup(),
  svc_rpcbind_set_version(), svc_authenticate(), and svc_sock_update_bufs().
  Declare svc_authenticate() as int in the private header to match 6.1.
  Keep svc_drop() in svc_xprt.c: it still calls the file-local
  svc_xprt_release(), which upstream no longer calls from svc_drop().

  Add braces around the existing svc_release_buffer() page-release loop,
  without changing its behavior, to provide the exact context required by
  the first hunk of c479bde671cb. No functions are added. ]

[ sashal: Reduced backport -- upstream f2b27e1d72527 touches 8 file(s), this
  backport carries 7. Not backported here:
  net/sunrpc/svc_xprt.c
  This note is generated from the file lists only; see the resolution record
  for the reasoning. ]

Stable-dep-of: c479bde671cb ("sunrpc: defer rq_argp and rq_resp free until after RCU grace period")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 include/linux/sunrpc/svc.h     |  6 ------
 include/linux/sunrpc/svcauth.h |  1 -
 include/linux/sunrpc/svcsock.h |  1 -
 net/sunrpc/sunrpc.h            |  4 ++++
 net/sunrpc/svc.c               | 10 +++++-----
 net/sunrpc/svcauth.c           |  1 -
 net/sunrpc/svcsock.c           |  1 -
 7 files changed, 9 insertions(+), 15 deletions(-)

diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index d26e01c63dde0..4144a256fc255 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -468,7 +468,6 @@ struct svc_procedure {
 /*
  * Function prototypes.
  */
-int svc_rpcb_setup(struct svc_serv *serv, struct net *net);
 void svc_rpcb_cleanup(struct svc_serv *serv, struct net *net);
 int svc_bind(struct svc_serv *serv, struct net *net);
 struct svc_serv *svc_create(struct svc_program *, unsigned int,
@@ -509,11 +508,6 @@ int		   svc_generic_rpcbind_set(struct net *net,
 					   u32 version, int family,
 					   unsigned short proto,
 					   unsigned short port);
-int		   svc_rpcbind_set_version(struct net *net,
-					   const struct svc_program *progp,
-					   u32 version, int family,
-					   unsigned short proto,
-					   unsigned short port);
 
 #define	RPC_MAX_ADDRBUFLEN	(63U)
 
diff --git a/include/linux/sunrpc/svcauth.h b/include/linux/sunrpc/svcauth.h
index 6d9cc9080aca7..5e11fbe1fe463 100644
--- a/include/linux/sunrpc/svcauth.h
+++ b/include/linux/sunrpc/svcauth.h
@@ -149,7 +149,6 @@ struct auth_ops {
 
 struct svc_xprt;
 
-extern int	svc_authenticate(struct svc_rqst *rqstp);
 extern int	svc_authorise(struct svc_rqst *rqstp);
 extern int	svc_set_client(struct svc_rqst *rqstp);
 extern int	svc_auth_register(rpc_authflavor_t flavor, struct auth_ops *aops);
diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h
index 13aff355d5a13..cfcdbf4def22c 100644
--- a/include/linux/sunrpc/svcsock.h
+++ b/include/linux/sunrpc/svcsock.h
@@ -58,7 +58,6 @@ void		svc_close_net(struct svc_serv *, struct net *);
 int		svc_recv(struct svc_rqst *, long);
 int		svc_send(struct svc_rqst *);
 void		svc_drop(struct svc_rqst *);
-void		svc_sock_update_bufs(struct svc_serv *serv);
 int		svc_addsock(struct svc_serv *serv, struct net *net,
 			    const int fd, char *name_return, const size_t len,
 			    const struct cred *cred);
diff --git a/net/sunrpc/sunrpc.h b/net/sunrpc/sunrpc.h
index d4a362c9e4b3b..07ab21b64f904 100644
--- a/net/sunrpc/sunrpc.h
+++ b/net/sunrpc/sunrpc.h
@@ -36,7 +36,11 @@ static inline int sock_is_loopback(struct sock *sk)
 	return loopback;
 }
 
+struct svc_serv;
+struct svc_rqst;
 int rpc_clients_notifier_register(void);
 void rpc_clients_notifier_unregister(void);
 void auth_domain_cleanup(void);
+void svc_sock_update_bufs(struct svc_serv *serv);
+int svc_authenticate(struct svc_rqst *rqstp);
 #endif /* _NET_SUNRPC_SUNRPC_H */
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index faa5193231240..3fe7152ee8bf5 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -32,6 +32,7 @@
 #include <trace/events/sunrpc.h>
 
 #include "fail.h"
+#include "sunrpc.h"
 
 #define RPCDBG_FACILITY	RPCDBG_SVCDSP
 
@@ -388,7 +389,7 @@ struct svc_pool *svc_pool_for_cpu(struct svc_serv *serv)
 	return &serv->sv_pools[pidx % serv->sv_nrpools];
 }
 
-int svc_rpcb_setup(struct svc_serv *serv, struct net *net)
+static int svc_rpcb_setup(struct svc_serv *serv, struct net *net)
 {
 	int err;
 
@@ -400,7 +401,6 @@ int svc_rpcb_setup(struct svc_serv *serv, struct net *net)
 	svc_unregister(serv, net);
 	return 0;
 }
-EXPORT_SYMBOL_GPL(svc_rpcb_setup);
 
 void svc_rpcb_cleanup(struct svc_serv *serv, struct net *net)
 {
@@ -625,9 +625,10 @@ svc_release_buffer(struct svc_rqst *rqstp)
 {
 	unsigned int i;
 
-	for (i = 0; i < ARRAY_SIZE(rqstp->rq_pages); i++)
+	for (i = 0; i < ARRAY_SIZE(rqstp->rq_pages); i++) {
 		if (rqstp->rq_pages[i])
 			put_page(rqstp->rq_pages[i]);
+	}
 }
 
 static void
@@ -1009,7 +1010,7 @@ static int __svc_register(struct net *net, const char *progname,
 	return error;
 }
 
-int svc_rpcbind_set_version(struct net *net,
+static int svc_rpcbind_set_version(struct net *net,
 			    const struct svc_program *progp,
 			    u32 version, int family,
 			    unsigned short proto,
@@ -1019,7 +1020,6 @@ int svc_rpcbind_set_version(struct net *net,
 				version, family, proto, port);
 
 }
-EXPORT_SYMBOL_GPL(svc_rpcbind_set_version);
 
 int svc_generic_rpcbind_set(struct net *net,
 			    const struct svc_program *progp,
diff --git a/net/sunrpc/svcauth.c b/net/sunrpc/svcauth.c
index e72ba2f13f6c6..1694c01bbaf9c 100644
--- a/net/sunrpc/svcauth.c
+++ b/net/sunrpc/svcauth.c
@@ -84,7 +84,6 @@ svc_authenticate(struct svc_rqst *rqstp)
 	rqstp->rq_authop = aops;
 	return aops->accept(rqstp);
 }
-EXPORT_SYMBOL_GPL(svc_authenticate);
 
 int svc_set_client(struct svc_rqst *rqstp)
 {
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 23b4c728de598..e6204afa78fd6 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -1283,7 +1283,6 @@ void svc_sock_update_bufs(struct svc_serv *serv)
 		set_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags);
 	spin_unlock_bh(&serv->sv_lock);
 }
-EXPORT_SYMBOL_GPL(svc_sock_update_bufs);
 
 /*
  * Initialize socket for RPC use and create svc_sock struct
-- 
2.53.0


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

* [PATCH 6.1.y 3/5] SUNRPC: Introduce xdr_set_scratch_folio()
  2026-09-09  0:25 ` [PATCH 6.1.y 1/5] SUNRPC: remove timeout arg from svc_recv() Sasha Levin
  2026-09-09  0:25   ` [PATCH 6.1.y 2/5] SUNRPC: make various functions static, or not exported Sasha Levin
@ 2026-09-09  0:25   ` Sasha Levin
  2026-09-09  0:25   ` [PATCH 6.1.y 4/5] SUNRPC: Update svcxdr_init_decode() to call xdr_set_scratch_folio() Sasha Levin
  2026-09-09  0:25   ` [PATCH 6.1.y 5/5] sunrpc: defer rq_argp and rq_resp free until after RCU grace period Sasha Levin
  3 siblings, 0 replies; 11+ messages in thread
From: Sasha Levin @ 2026-09-09  0:25 UTC (permalink / raw)
  To: stable; +Cc: Anna Schumaker, Sasha Levin

From: Anna Schumaker <anna.schumaker@oracle.com>

[ Upstream commit c8a127596edc026e5364a7a609986dcd3999914c ]

This will replace xdr_set_scratch_page() when we switch pages to folios.

Signed-off-by: Anna Schumaker <anna.schumaker@oracle.com>
Stable-dep-of: c479bde671cb ("sunrpc: defer rq_argp and rq_resp free until after RCU grace period")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 include/linux/sunrpc/xdr.h | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h
index f84e2a1358e17..2b73b3db87d99 100644
--- a/include/linux/sunrpc/xdr.h
+++ b/include/linux/sunrpc/xdr.h
@@ -299,6 +299,19 @@ xdr_set_scratch_page(struct xdr_stream *xdr, struct page *page)
 	xdr_set_scratch_buffer(xdr, page_address(page), PAGE_SIZE);
 }
 
+/**
+ * xdr_set_scratch_folio - Attach a scratch buffer for decoding data
+ * @xdr: pointer to xdr_stream struct
+ * @page: an anonymous folio
+ *
+ * See xdr_set_scratch_buffer().
+ */
+static inline void
+xdr_set_scratch_folio(struct xdr_stream *xdr, struct folio *folio)
+{
+	xdr_set_scratch_buffer(xdr, folio_address(folio), folio_size(folio));
+}
+
 /**
  * xdr_reset_scratch_buffer - Clear scratch buffer information
  * @xdr: pointer to xdr_stream struct
-- 
2.53.0


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

* [PATCH 6.1.y 4/5] SUNRPC: Update svcxdr_init_decode() to call xdr_set_scratch_folio()
  2026-09-09  0:25 ` [PATCH 6.1.y 1/5] SUNRPC: remove timeout arg from svc_recv() Sasha Levin
  2026-09-09  0:25   ` [PATCH 6.1.y 2/5] SUNRPC: make various functions static, or not exported Sasha Levin
  2026-09-09  0:25   ` [PATCH 6.1.y 3/5] SUNRPC: Introduce xdr_set_scratch_folio() Sasha Levin
@ 2026-09-09  0:25   ` Sasha Levin
  2026-09-09  0:25   ` [PATCH 6.1.y 5/5] sunrpc: defer rq_argp and rq_resp free until after RCU grace period Sasha Levin
  3 siblings, 0 replies; 11+ messages in thread
From: Sasha Levin @ 2026-09-09  0:25 UTC (permalink / raw)
  To: stable; +Cc: Anna Schumaker, Sasha Levin

From: Anna Schumaker <anna.schumaker@oracle.com>

[ Upstream commit d57e43b72bf2071caac90da323849c3983a695f0 ]

The only snag here is that __folio_alloc_node() doesn't handle
NUMA_NO_NODE, so I also need to update svc_pool_map_get_node() to return
numa_mem_id() instead. I arrived at this approach by  looking at what
other users of __folio_alloc_node() do for this case.

Signed-off-by: Anna Schumaker <anna.schumaker@oracle.com>

[ Stable backport note: Earlier dependencies already converted rq_scratch_page
  to rq_scratch_folio, including allocation and release. Keep those changes
  and switch svcxdr_init_decode() to the xdr_set_scratch_folio() helper added
  by the immediately preceding dependency.

  Drop the svc_pool_map_get_node() change: svc_rqst_alloc() already converts
  NUMA_NO_NODE to numa_mem_id() before __folio_alloc_node(). Preserve that
  fallback and the existing pool/thread placement policy.

  The resulting dependency changes only the existing decoder helper call;
  no functions are added. The scratch-folio release and surrounding context
  required by c479bde671cb are retained, and its patch applies cleanly. ]

[ sashal: Reduced backport -- upstream d57e43b72bf20 touches 2 file(s), this
  backport carries 1. Not backported here:
  net/sunrpc/svc.c
  This note is generated from the file lists only; see the resolution record
  for the reasoning. ]

Stable-dep-of: c479bde671cb ("sunrpc: defer rq_argp and rq_resp free until after RCU grace period")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 include/linux/sunrpc/svc.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index 4144a256fc255..40ab44b993cf9 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -545,7 +545,7 @@ static inline void svcxdr_init_decode(struct svc_rqst *rqstp)
 	buf->len = buf->head->iov_len + buf->page_len + buf->tail->iov_len;
 
 	xdr_init_decode(xdr, buf, argv->iov_base, NULL);
-	xdr_set_scratch_page(xdr, folio_page(rqstp->rq_scratch_folio, 0));
+	xdr_set_scratch_folio(xdr, rqstp->rq_scratch_folio);
 }
 
 /**
-- 
2.53.0


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

* [PATCH 6.1.y 5/5] sunrpc: defer rq_argp and rq_resp free until after RCU grace period
  2026-09-09  0:25 ` [PATCH 6.1.y 1/5] SUNRPC: remove timeout arg from svc_recv() Sasha Levin
                     ` (2 preceding siblings ...)
  2026-09-09  0:25   ` [PATCH 6.1.y 4/5] SUNRPC: Update svcxdr_init_decode() to call xdr_set_scratch_folio() Sasha Levin
@ 2026-09-09  0:25   ` Sasha Levin
  3 siblings, 0 replies; 11+ messages in thread
From: Sasha Levin @ 2026-09-09  0:25 UTC (permalink / raw)
  To: stable; +Cc: Jeff Layton, Chuck Lever, Sasha Levin

From: Jeff Layton <jlayton@kernel.org>

[ Upstream commit c479bde671cbe2f9e152834a8b0eb7c3c295bbaf ]

svc_rqst_free() frees rqstp->rq_argp and rqstp->rq_resp synchronously
via kfree(), but defers the rqstp struct free via kfree_rcu().  After
svc_exit_thread() calls list_del_rcu() and svc_rqst_free(), there is
a window where RCU readers that started before list_del_rcu() can still
traverse the thread list and find the rqstp.  These readers (e.g.
nfsd_nl_rpc_status_get_dumpit()) dereference rqstp->rq_argp, which has
already been freed — a use-after-free.

Fix this by moving the kfree of rq_argp and rq_resp into an explicit
call_rcu() callback alongside the struct free.  Resources not accessed
by RCU readers (bvec, buffer pages, scratch folio, auth_data) remain
synchronously freed.

Fixes: 812443865c5f ("sunrpc: add a rcu_head to svc_rqst and use kfree_rcu to free it")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Jeff Layton <jlayton@kernel.org>
Link: https://patch.msgid.link/20260611-nfsd-testing-v2-4-5b90e276f2d9@kernel.org
Signed-off-by: Chuck Lever <cel@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 net/sunrpc/svc.c | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 3fe7152ee8bf5..c3d18ff3ce296 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -631,16 +631,23 @@ svc_release_buffer(struct svc_rqst *rqstp)
 	}
 }
 
+static void svc_rqst_free_rcu(struct rcu_head *head)
+{
+	struct svc_rqst *rqstp = container_of(head, struct svc_rqst, rq_rcu_head);
+
+	kfree(rqstp->rq_resp);
+	kfree(rqstp->rq_argp);
+	kfree(rqstp);
+}
+
 static void
 svc_rqst_free(struct svc_rqst *rqstp)
 {
 	svc_release_buffer(rqstp);
 	if (rqstp->rq_scratch_folio)
 		folio_put(rqstp->rq_scratch_folio);
-	kfree(rqstp->rq_resp);
-	kfree(rqstp->rq_argp);
 	kfree(rqstp->rq_auth_data);
-	kfree_rcu(rqstp, rq_rcu_head);
+	call_rcu(&rqstp->rq_rcu_head, svc_rqst_free_rcu);
 }
 
 static struct svc_rqst *
-- 
2.53.0


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

end of thread, other threads:[~2026-09-09  0:25 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-03 14:06 FAILED: patch "[PATCH] sunrpc: defer rq_argp and rq_resp free until after RCU grace" failed to apply to 6.1-stable tree gregkh
2026-09-09  0:25 ` [PATCH 6.1.y 1/5] SUNRPC: remove timeout arg from svc_recv() Sasha Levin
2026-09-09  0:25   ` [PATCH 6.1.y 2/5] SUNRPC: make various functions static, or not exported Sasha Levin
2026-09-09  0:25   ` [PATCH 6.1.y 3/5] SUNRPC: Introduce xdr_set_scratch_folio() Sasha Levin
2026-09-09  0:25   ` [PATCH 6.1.y 4/5] SUNRPC: Update svcxdr_init_decode() to call xdr_set_scratch_folio() Sasha Levin
2026-09-09  0:25   ` [PATCH 6.1.y 5/5] sunrpc: defer rq_argp and rq_resp free until after RCU grace period Sasha Levin
2026-09-09  0:25 ` [PATCH 6.1.y 1/5] SUNRPC: remove timeout arg from svc_recv() Sasha Levin
2026-09-09  0:25   ` [PATCH 6.1.y 2/5] SUNRPC: make various functions static, or not exported Sasha Levin
2026-09-09  0:25   ` [PATCH 6.1.y 3/5] SUNRPC: Introduce xdr_set_scratch_folio() Sasha Levin
2026-09-09  0:25   ` [PATCH 6.1.y 4/5] SUNRPC: Update svcxdr_init_decode() to call xdr_set_scratch_folio() Sasha Levin
2026-09-09  0:25   ` [PATCH 6.1.y 5/5] sunrpc: defer rq_argp and rq_resp free until after RCU grace period Sasha Levin

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.