FAILED: patch "[PATCH] sunrpc: defer rq_argp and rq_resp free until after RCU grace" failed to apply to 6.12-stable tree
Subsystems (4)
[email protected]
maintainerThe patch below does not apply to the 6.12-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 <[email protected]>.
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.12.y
git checkout FETCH_HEAD
git cherry-pick -x c479bde671cbe2f9e152834a8b0eb7c3c295bbaf
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026090349-throwing-hardware-8a25@gregkh' --subject-prefix 'PATCH 6.12.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 <[email protected]>
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.
net/sunrpc/svc.c +10 -3
@@ -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 *
Sasha Levin
maintainerPATCH 1/3 SUNRPC: Introduce xdr_set_scratch_folio()
From: Anna Schumaker <[email protected]>
[ Upstream commit c8a127596edc026e5364a7a609986dcd3999914c ]
This will replace xdr_set_scratch_page() when we switch pages to folios.
Stable-dep-of: c479bde671cb ("sunrpc: defer rq_argp and rq_resp free until after RCU grace period")
--- include/linux/sunrpc/xdr.h | 13 +++++++++++++ 1 file changed, 13 insertions(+)
include/linux/sunrpc/xdr.h +13 -0
@@ -317,6 +317,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
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/3 SUNRPC: Update svcxdr_init_decode() to call xdr_set_scratch_folio()
From: Anna Schumaker <[email protected]>
[ 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.
Stable-dep-of: c479bde671cb ("sunrpc: defer rq_argp and rq_resp free until after RCU grace period")
--- include/linux/sunrpc/svc.h | 4 ++-- net/sunrpc/svc.c | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-)
include/linux/sunrpc/svc.h +2 -2
@@ -190,7 +190,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 */
@@ -504,7 +504,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_folio (xdr, rqstp->rq_scratch_folio); }/**
net/sunrpc/svc.c +5 -5
@@ -352,7 +352,7 @@ static int svc_pool_map_get_node(unsigned int pidx)if (m->mode ==SVC_POOL_PERNODE )return m->pool_to[pidx]; } -return NUMA_NO_NODE ; +return numa_mem_id (); }/* * Set the given thread's cpus_allowed mask so that it
@@ -734,8 +734,8 @@ svc_rqst_free(struct svc_rqst *rqstp) {folio_batch_release (&rqstp->rq_fbatch);svc_release_buffer (rqstp); -if (rqstp->rq_scratch_page) -put_page (rqstp->rq_scratch_page); +if (rqstp->rq_scratch_folio) +folio_put (rqstp->rq_scratch_folio);kfree (rqstp->rq_resp);kfree (rqstp->rq_argp);kfree (rqstp->rq_auth_data);
@@ -756,8 +756,8 @@ svc_prepare_thread(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) + 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);
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 3/3 sunrpc: defer rq_argp and rq_resp free until after RCU grace period
In reply to Sasha LevinFrom: Jeff Layton <[email protected]>
[ 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.
--- net/sunrpc/svc.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-)
net/sunrpc/svc.c +10 -3
@@ -729,6 +729,15 @@ svc_release_buffer(struct svc_rqst *rqstp)put_page (rqstp->rq_pages[i]); } +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) {
@@ -736,10 +745,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 *
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 1/1 sunrpc: defer rq_argp and rq_resp free until after RCU grace period
In reply to [email protected]From: Jeff Layton <[email protected]>
[ 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.
--- net/sunrpc/svc.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-)
net/sunrpc/svc.c +10 -3
@@ -729,6 +729,15 @@ svc_release_buffer(struct svc_rqst *rqstp)put_page (rqstp->rq_pages[i]); } +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) {
@@ -736,10 +745,8 @@ 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); +call_rcu (&rqstp->rq_rcu_head, svc_rqst_free_rcu); } static struct svc_rqst *
Signature · 1 line
2.53.0