[PATCH net-next v3 4/4] net: remove rcu_barrier() from __dev_change_net_namespace()

From: Qiliang Yuan

Date: Mon Nov 09 2026 - 03:23:29 EST


Commit 6549dd43c043 ("net: dev: fix the incorrect hold of net
namespace's lo device") added rcu_barrier() before
NETDEV_UNREGISTER_FINAL in dev_change_net_namespace(), so that dst
entries released by RCU callbacks were on the dst garbage list before
dst_ifdown() moved them to the loopback device of the old netns.
Commit 070f2d7e264a ("net: Drop NETDEV_UNREGISTER_FINAL") removed the
event but kept the barrier, and dead dst entries now point to
blackhole_netdev instead of a loopback device.

The barrier waits for the RCU callbacks pending on every CPU while RTNL
is held, which takes a full grace period on each netns move. Container
and sandbox managers move one end of a veth pair for every new network
namespace, so this limits how fast such namespaces can be created on the
whole system, regardless of how many threads create them.

Remove the barrier. The RCU callbacks queued by NETDEV_UNREGISTER
handlers free memory and drop device references, which the move does not
wait for. Routes cached through the moved device are rejected once its
netns changes: IPv4 and per-cpu IPv6 routes no longer match the rt_genid
or fib6_sernum of another netns, and the IPv6 exceptions of a nexthop
that leaves a group were already flushed when it left. Creating 400
netns, each with a veth pair whose host end is moved back to the initial
netns, a tap device, addresses and routes, in a 4 vCPU guest, median of
5 runs:

before after
1 thread 46 /s 56 /s
4 threads 58 /s 84 /s
16 threads 75 /s 146 /s

Signed-off-by: Qiliang Yuan <qiliang.yuan@xxxxxxxxx>
Reviewed-by: Eric Dumazet <edumazet@xxxxxxxxxx>
Reviewed-by: Kuniyuki Iwashima <kuniyu@xxxxxxxxxx>
---
net/core/dev.c | 1 -
1 file changed, 1 deletion(-)

diff --git a/net/core/dev.c b/net/core/dev.c
index 3b60b15e2175e..de1fd77440543 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -13044,7 +13044,6 @@ int __dev_change_net_namespace(struct net_device *dev, struct net *net,
* the device is just moving and can keep their slaves up.
*/
call_netdevice_notifiers(NETDEV_UNREGISTER, dev);
- rcu_barrier();

new_nsid = peernet2id_alloc(dev_net(dev), net, GFP_KERNEL);


--
2.43.0