[PATCH net-next v3] wireguard: allowedips: Use kfree_rcu() instead of call_rcu()

Fushuai Wang posted 1 patch 3 weeks, 5 days ago
drivers/net/wireguard/allowedips.c | 9 ++-------
1 file changed, 2 insertions(+), 7 deletions(-)
[PATCH net-next v3] wireguard: allowedips: Use kfree_rcu() instead of call_rcu()
Posted by Fushuai Wang 3 weeks, 5 days ago
From: Fushuai Wang <wangfushuai@baidu.com>

Replace call_rcu() + kmem_cache_free() with kfree_rcu() to simplify
the code and reduce function size.

Signed-off-by: Fushuai Wang <wangfushuai@baidu.com>
---
 drivers/net/wireguard/allowedips.c | 9 ++-------
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/drivers/net/wireguard/allowedips.c b/drivers/net/wireguard/allowedips.c
index 09f7fcd7da78..5ece9acad64d 100644
--- a/drivers/net/wireguard/allowedips.c
+++ b/drivers/net/wireguard/allowedips.c
@@ -48,11 +48,6 @@ static void push_rcu(struct allowedips_node **stack,
 	}
 }
 
-static void node_free_rcu(struct rcu_head *rcu)
-{
-	kmem_cache_free(node_cache, container_of(rcu, struct allowedips_node, rcu));
-}
-
 static void root_free_rcu(struct rcu_head *rcu)
 {
 	struct allowedips_node *node, *stack[MAX_ALLOWEDIPS_DEPTH] = {
@@ -271,13 +266,13 @@ static void remove_node(struct allowedips_node *node, struct mutex *lock)
 	if (free_parent)
 		child = rcu_dereference_protected(parent->bit[!(node->parent_bit_packed & 1)],
 						  lockdep_is_held(lock));
-	call_rcu(&node->rcu, node_free_rcu);
+	kfree_rcu(node, rcu);
 	if (!free_parent)
 		return;
 	if (child)
 		child->parent_bit_packed = parent->parent_bit_packed;
 	*(struct allowedips_node **)(parent->parent_bit_packed & ~3UL) = child;
-	call_rcu(&parent->rcu, node_free_rcu);
+	kfree_rcu(parent, rcu);
 }
 
 static int remove(struct allowedips_node __rcu **trie, u8 bits, const u8 *key,
-- 
2.36.1
Re: [net-next,v3] wireguard: allowedips: Use kfree_rcu() instead of call_rcu()
Posted by Jakub Kicinski 3 weeks, 2 days ago
This is an AI-generated review of your patch. The human sending this
email has considered the AI review valid, or at least pausible.

For local reproduction steps see https://netdev-ai.bots.linux.dev/ai-local.html
---
wireguard: allowedips: Use kfree_rcu() instead of call_rcu()

This commit replaces call_rcu() with a custom kmem_cache_free() callback
with kfree_rcu() to simplify the code. The change affects how nodes are
freed in the remove_node() function.

> diff --git a/drivers/net/wireguard/allowedips.c b/drivers/net/wireguard/allowedips.c
> index 09f7fcd7da78..5ece9acad64d 100644
> --- a/drivers/net/wireguard/allowedips.c
> +++ b/drivers/net/wireguard/allowedips.c
> @@ -48,11 +48,6 @@ static void push_rcu(struct allowedips_node **stack,
>  	}
>  }
>
> -static void node_free_rcu(struct rcu_head *rcu)
> -{
> -	kmem_cache_free(node_cache, container_of(rcu, struct allowedips_node, rcu));
> -}
> -

[ ... ]

> @@ -271,13 +266,13 @@ static void remove_node(struct allowedips_node *node, struct mutex *lock)
>  	if (free_parent)
>  		child = rcu_dereference_protected(parent->bit[!(node->parent_bit_packed & 1)],
>  						  lockdep_is_held(lock));
> -	call_rcu(&node->rcu, node_free_rcu);
> +	kfree_rcu(node, rcu);

Does wg_allowedips_slab_uninit() need to be updated to use
kvfree_rcu_barrier() instead of rcu_barrier()?

When CONFIG_KVFREE_RCU_BATCHED is enabled (the default), kfree_rcu()
uses a batched mechanism that queues work via queue_rcu_work(). The
rcu_barrier() call waits for RCU callbacks to complete, but these
callbacks only queue the actual free to a workqueue via rcu_work_rcufn().
The workqueue work that calls kvfree() may still be pending after
rcu_barrier() returns.

The existing cleanup path is:
  wg_allowedips_slab_uninit() -> rcu_barrier() -> kmem_cache_destroy()

With kfree_rcu(), this sequence could destroy the slab cache while
kfree_rcu_work() still has pending frees queued. The proper barrier for
kfree_rcu() is kvfree_rcu_barrier() which also calls flush_rcu_work()
on all pending batches.

>  	if (!free_parent)
>  		return;
>  	if (child)
>  		child->parent_bit_packed = parent->parent_bit_packed;
>  	*(struct allowedips_node **)(parent->parent_bit_packed & ~3UL) = child;
> -	call_rcu(&parent->rcu, node_free_rcu);
> +	kfree_rcu(parent, rcu);
>  }
-- 
pw-bot: cr
Re: [net-next, v3] wireguard: allowedips: Use kfree_rcu() instead of call_rcu()
Posted by Petr Vaněk 3 weeks, 2 days ago
Hi Jakub,

Minor side note: I noticed a small typo in the AI review foreword. I
assume this is part of a template:

On Wed, Jan 14, 2026 at 07:32:37PM -0800, Jakub Kicinski wrote:
> This is an AI-generated review of your patch. The human sending this
> email has considered the AI review valid, or at least pausible.
                                                        ^~~~~~~~
pausible -> plausible

Best,
Petr
Re: [net-next, v3] wireguard: allowedips: Use kfree_rcu() instead of call_rcu()
Posted by Jakub Kicinski 3 weeks, 2 days ago
On Thu, 15 Jan 2026 09:12:13 +0100 Petr Vaněk wrote:
> Hi Jakub,
> 
> Minor side note: I noticed a small typo in the AI review foreword. I
> assume this is part of a template:
> 
> On Wed, Jan 14, 2026 at 07:32:37PM -0800, Jakub Kicinski wrote:
> > This is an AI-generated review of your patch. The human sending this
> > email has considered the AI review valid, or at least pausible.  
>                                                         ^~~~~~~~
> pausible -> plausible

Ah, thanks :)
Re: [PATCH net-next v3] wireguard: allowedips: Use kfree_rcu() instead of call_rcu()
Posted by Fushuai Wang 3 weeks, 2 days ago
>> @@ -271,13 +266,13 @@ static void remove_node(struct allowedips_node *node, struct mutex *lock)
>>  	if (free_parent)
>>  		child = rcu_dereference_protected(parent->bit[!(node->parent_bit_packed & 1)],
>>  						  lockdep_is_held(lock));
>> -	call_rcu(&node->rcu, node_free_rcu);
>> +	kfree_rcu(node, rcu);
> 
> Does wg_allowedips_slab_uninit() need to be updated to use
> kvfree_rcu_barrier() instead of rcu_barrier()?
> 
> When CONFIG_KVFREE_RCU_BATCHED is enabled (the default), kfree_rcu()
> uses a batched mechanism that queues work via queue_rcu_work(). The
> rcu_barrier() call waits for RCU callbacks to complete, but these
> callbacks only queue the actual free to a workqueue via rcu_work_rcufn().
> The workqueue work that calls kvfree() may still be pending after
> rcu_barrier() returns.
> 
> The existing cleanup path is:
>   wg_allowedips_slab_uninit() -> rcu_barrier() -> kmem_cache_destroy()
> 
> With kfree_rcu(), this sequence could destroy the slab cache while
> kfree_rcu_work() still has pending frees queued. The proper barrier for
> kfree_rcu() is kvfree_rcu_barrier() which also calls flush_rcu_work()
> on all pending batches.

We do not need to add an explict kvfree_rcu_barrier(), becasue the commit
6c6c47b063b5 ("mm, slab: call kvfree_rcu_barrier() from kmem_cache_destroy()")
already does it.

---
Regards,
WANG
Re: [PATCH net-next v3] wireguard: allowedips: Use kfree_rcu() instead of call_rcu()
Posted by Eric Dumazet 3 weeks, 2 days ago
On Thu, Jan 15, 2026 at 6:12 AM Fushuai Wang <fushuai.wang@linux.dev> wrote:
>
> >> @@ -271,13 +266,13 @@ static void remove_node(struct allowedips_node *node, struct mutex *lock)
> >>      if (free_parent)
> >>              child = rcu_dereference_protected(parent->bit[!(node->parent_bit_packed & 1)],
> >>                                                lockdep_is_held(lock));
> >> -    call_rcu(&node->rcu, node_free_rcu);
> >> +    kfree_rcu(node, rcu);
> >
> > Does wg_allowedips_slab_uninit() need to be updated to use
> > kvfree_rcu_barrier() instead of rcu_barrier()?
> >
> > When CONFIG_KVFREE_RCU_BATCHED is enabled (the default), kfree_rcu()
> > uses a batched mechanism that queues work via queue_rcu_work(). The
> > rcu_barrier() call waits for RCU callbacks to complete, but these
> > callbacks only queue the actual free to a workqueue via rcu_work_rcufn().
> > The workqueue work that calls kvfree() may still be pending after
> > rcu_barrier() returns.
> >
> > The existing cleanup path is:
> >   wg_allowedips_slab_uninit() -> rcu_barrier() -> kmem_cache_destroy()
> >
> > With kfree_rcu(), this sequence could destroy the slab cache while
> > kfree_rcu_work() still has pending frees queued. The proper barrier for
> > kfree_rcu() is kvfree_rcu_barrier() which also calls flush_rcu_work()
> > on all pending batches.
>
> We do not need to add an explict kvfree_rcu_barrier(), becasue the commit
> 6c6c47b063b5 ("mm, slab: call kvfree_rcu_barrier() from kmem_cache_destroy()")
> already does it.

It was doing it, but got replaced recently with a plain rcu_barrier()

commit 0f35040de59371ad542b915d7b91176c9910dadc
Author: Harry Yoo <harry.yoo@oracle.com>
Date:   Mon Dec 8 00:41:47 2025 +0900

    mm/slab: introduce kvfree_rcu_barrier_on_cache() for cache destruction

We would like explicit +2 from mm _and_ rcu experts on this wireguard patch.

Thank you.
Re: [PATCH net-next v3] wireguard: allowedips: Use kfree_rcu() instead of call_rcu()
Posted by Jason A. Donenfeld 3 weeks, 2 days ago
Hi Eric,

On Thu, Jan 15, 2026 at 10:15 AM Eric Dumazet <edumazet@google.com> wrote:
> > > The existing cleanup path is:
> > >   wg_allowedips_slab_uninit() -> rcu_barrier() -> kmem_cache_destroy()
> > >
> > > With kfree_rcu(), this sequence could destroy the slab cache while
> > > kfree_rcu_work() still has pending frees queued. The proper barrier for
> > > kfree_rcu() is kvfree_rcu_barrier() which also calls flush_rcu_work()
> > > on all pending batches.
> >
> > We do not need to add an explict kvfree_rcu_barrier(), becasue the commit
> > 6c6c47b063b5 ("mm, slab: call kvfree_rcu_barrier() from kmem_cache_destroy()")
> > already does it.
>
> It was doing it, but got replaced recently with a plain rcu_barrier()
>
> commit 0f35040de59371ad542b915d7b91176c9910dadc
> Author: Harry Yoo <harry.yoo@oracle.com>
> Date:   Mon Dec 8 00:41:47 2025 +0900
>
>     mm/slab: introduce kvfree_rcu_barrier_on_cache() for cache destruction
>
> We would like explicit +2 from mm _and_ rcu experts on this wireguard patch.

I'll take this through the wireguard tree.

But just a question on your comment, "It was doing it, but got
replaced recently with a plain rcu_barrier()". Are you suggesting I
need a kvfree_rcu_barrier() instead? The latest net-next has a
kvfree_rcu_barrier_on_cache() called from kmem_cache_destroy()
still... But are you suggesting I add this anyway?

diff --git a/drivers/net/wireguard/allowedips.c
b/drivers/net/wireguard/allowedips.c
index 5ece9acad64d..aee39a0303b0 100644
--- a/drivers/net/wireguard/allowedips.c
+++ b/drivers/net/wireguard/allowedips.c
@@ -417,7 +417,7 @@ int __init wg_allowedips_slab_init(void)

 void wg_allowedips_slab_uninit(void)
 {
- rcu_barrier();
+ kvfree_rcu_barrier();
  kmem_cache_destroy(node_cache);
 }

Let me know.

Thanks,
Jason
Re: [PATCH net-next v3] wireguard: allowedips: Use kfree_rcu() instead of call_rcu()
Posted by Eric Dumazet 3 weeks, 2 days ago
On Thu, Jan 15, 2026 at 3:33 PM Jason A. Donenfeld <Jason@zx2c4.com> wrote:
>
> Hi Eric,
>
> On Thu, Jan 15, 2026 at 10:15 AM Eric Dumazet <edumazet@google.com> wrote:
> > > > The existing cleanup path is:
> > > >   wg_allowedips_slab_uninit() -> rcu_barrier() -> kmem_cache_destroy()
> > > >
> > > > With kfree_rcu(), this sequence could destroy the slab cache while
> > > > kfree_rcu_work() still has pending frees queued. The proper barrier for
> > > > kfree_rcu() is kvfree_rcu_barrier() which also calls flush_rcu_work()
> > > > on all pending batches.
> > >
> > > We do not need to add an explict kvfree_rcu_barrier(), becasue the commit
> > > 6c6c47b063b5 ("mm, slab: call kvfree_rcu_barrier() from kmem_cache_destroy()")
> > > already does it.
> >
> > It was doing it, but got replaced recently with a plain rcu_barrier()
> >
> > commit 0f35040de59371ad542b915d7b91176c9910dadc
> > Author: Harry Yoo <harry.yoo@oracle.com>
> > Date:   Mon Dec 8 00:41:47 2025 +0900
> >
> >     mm/slab: introduce kvfree_rcu_barrier_on_cache() for cache destruction
> >
> > We would like explicit +2 from mm _and_ rcu experts on this wireguard patch.
>
> I'll take this through the wireguard tree.
>
> But just a question on your comment, "It was doing it, but got
> replaced recently with a plain rcu_barrier()". Are you suggesting I
> need a kvfree_rcu_barrier() instead? The latest net-next has a
> kvfree_rcu_barrier_on_cache() called from kmem_cache_destroy()
> still... But are you suggesting I add this anyway?
>
> diff --git a/drivers/net/wireguard/allowedips.c
> b/drivers/net/wireguard/allowedips.c
> index 5ece9acad64d..aee39a0303b0 100644
> --- a/drivers/net/wireguard/allowedips.c
> +++ b/drivers/net/wireguard/allowedips.c
> @@ -417,7 +417,7 @@ int __init wg_allowedips_slab_init(void)
>
>  void wg_allowedips_slab_uninit(void)
>  {
> - rcu_barrier();
> + kvfree_rcu_barrier();

It seems kmem_cache_destroy() should take care of needed barriers,
at least this is what is claimed. An rcu_barrier() or kvfree_rcu_barrier()
should not be needed in wg_allowedips_slab_uninit() ?

Probably boring/distracting, I do not expect anyone needing to unload
this module in a loop and expect this to be ultra fast ?

>   kmem_cache_destroy(node_cache);
>  }
>
> Let me know.
>
> Thanks,
> Jason
Re: [PATCH net-next v3] wireguard: allowedips: Use kfree_rcu() instead of call_rcu()
Posted by Jason A. Donenfeld 2 weeks, 1 day ago
On Thu, Jan 15, 2026 at 03:40:17PM +0100, Eric Dumazet wrote:
> On Thu, Jan 15, 2026 at 3:33 PM Jason A. Donenfeld <Jason@zx2c4.com> wrote:
> >
> > Hi Eric,
> >
> > On Thu, Jan 15, 2026 at 10:15 AM Eric Dumazet <edumazet@google.com> wrote:
> > > > > The existing cleanup path is:
> > > > >   wg_allowedips_slab_uninit() -> rcu_barrier() -> kmem_cache_destroy()
> > > > >
> > > > > With kfree_rcu(), this sequence could destroy the slab cache while
> > > > > kfree_rcu_work() still has pending frees queued. The proper barrier for
> > > > > kfree_rcu() is kvfree_rcu_barrier() which also calls flush_rcu_work()
> > > > > on all pending batches.
> > > >
> > > > We do not need to add an explict kvfree_rcu_barrier(), becasue the commit
> > > > 6c6c47b063b5 ("mm, slab: call kvfree_rcu_barrier() from kmem_cache_destroy()")
> > > > already does it.
> > >
> > > It was doing it, but got replaced recently with a plain rcu_barrier()
> > >
> > > commit 0f35040de59371ad542b915d7b91176c9910dadc
> > > Author: Harry Yoo <harry.yoo@oracle.com>
> > > Date:   Mon Dec 8 00:41:47 2025 +0900
> > >
> > >     mm/slab: introduce kvfree_rcu_barrier_on_cache() for cache destruction
> > >
> > > We would like explicit +2 from mm _and_ rcu experts on this wireguard patch.
> >
> > I'll take this through the wireguard tree.
> >
> > But just a question on your comment, "It was doing it, but got
> > replaced recently with a plain rcu_barrier()". Are you suggesting I
> > need a kvfree_rcu_barrier() instead? The latest net-next has a
> > kvfree_rcu_barrier_on_cache() called from kmem_cache_destroy()
> > still... But are you suggesting I add this anyway?
> >
> > diff --git a/drivers/net/wireguard/allowedips.c
> > b/drivers/net/wireguard/allowedips.c
> > index 5ece9acad64d..aee39a0303b0 100644
> > --- a/drivers/net/wireguard/allowedips.c
> > +++ b/drivers/net/wireguard/allowedips.c
> > @@ -417,7 +417,7 @@ int __init wg_allowedips_slab_init(void)
> >
> >  void wg_allowedips_slab_uninit(void)
> >  {
> > - rcu_barrier();
> > + kvfree_rcu_barrier();
> 
> It seems kmem_cache_destroy() should take care of needed barriers,
> at least this is what is claimed. An rcu_barrier() or kvfree_rcu_barrier()
> should not be needed in wg_allowedips_slab_uninit() ?
> 
> Probably boring/distracting, I do not expect anyone needing to unload
> this module in a loop and expect this to be ultra fast ?

Okay so I'll take this patch, and perhaps amend to it the _removal_ of
that rcu_barrier()?

Jason
Re: [PATCH net-next v3] wireguard: allowedips: Use kfree_rcu() instead of call_rcu()
Posted by Simon Horman 3 weeks, 2 days ago
On Mon, Jan 12, 2026 at 09:06:33PM +0800, Fushuai Wang wrote:
> From: Fushuai Wang <wangfushuai@baidu.com>
> 
> Replace call_rcu() + kmem_cache_free() with kfree_rcu() to simplify
> the code and reduce function size.
> 
> Signed-off-by: Fushuai Wang <wangfushuai@baidu.com>

Thanks,

I believe this address prior review and moreover I agree
with the approach taken here.

Reviewed-by: Simon Horman <horms@kernel.org>

...