* 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 a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox