]> www.infradead.org Git - users/willy/pagecache.git/commitdiff
net: expedite synchronize_net() for cleanup_net()
authorEric Dumazet <edumazet@google.com>
Tue, 14 Jan 2025 20:55:27 +0000 (20:55 +0000)
committerJakub Kicinski <kuba@kernel.org>
Thu, 16 Jan 2025 03:17:03 +0000 (19:17 -0800)
cleanup_net() is the single thread responsible
for netns dismantles, and a serious bottleneck.

Before we can get per-netns RTNL, make sure
all synchronize_net() called from this thread
are using rcu_synchronize_expedited().

v3: deal with CONFIG_NET_NS=n

Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Jesse Brandeburg <jbrandeburg@cloudflare.com>
Link: https://patch.msgid.link/20250114205531.967841-2-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
include/net/net_namespace.h
net/core/dev.c
net/core/net_namespace.c

index 5a2a0df8ad91b677b515b392869c6c755be5c868..0f5eb9db0c6264efc1ac83ab577511fd6823f4fe 100644 (file)
@@ -210,6 +210,8 @@ void net_ns_barrier(void);
 
 struct ns_common *get_net_ns(struct ns_common *ns);
 struct net *get_net_ns_by_fd(int fd);
+extern struct task_struct *cleanup_net_task;
+
 #else /* CONFIG_NET_NS */
 #include <linux/sched.h>
 #include <linux/nsproxy.h>
index 47e6b0f73cfc790b55252c554e6f194eb5d1fdfc..115a7a0a110425d5fd3eaf68f7b0e63122a92165 100644 (file)
@@ -10099,6 +10099,15 @@ static void dev_index_release(struct net *net, int ifindex)
        WARN_ON(xa_erase(&net->dev_by_index, ifindex));
 }
 
+static bool from_cleanup_net(void)
+{
+#ifdef CONFIG_NET_NS
+       return current == cleanup_net_task;
+#else
+       return false;
+#endif
+}
+
 /* Delayed registration/unregisteration */
 LIST_HEAD(net_todo_list);
 DECLARE_WAIT_QUEUE_HEAD(netdev_unregistering_wq);
@@ -11474,7 +11483,7 @@ EXPORT_SYMBOL_GPL(alloc_netdev_dummy);
 void synchronize_net(void)
 {
        might_sleep();
-       if (rtnl_is_locked())
+       if (from_cleanup_net() || rtnl_is_locked())
                synchronize_rcu_expedited();
        else
                synchronize_rcu();
index b5cd3ae4f04cf28d43f8401a3dafebac4a297123..cb39a12b2f8295c605f08b5589932932150a1644 100644 (file)
@@ -588,6 +588,8 @@ static void unhash_nsid(struct net *net, struct net *last)
 
 static LLIST_HEAD(cleanup_list);
 
+struct task_struct *cleanup_net_task;
+
 static void cleanup_net(struct work_struct *work)
 {
        const struct pernet_operations *ops;
@@ -596,6 +598,8 @@ static void cleanup_net(struct work_struct *work)
        LIST_HEAD(net_exit_list);
        LIST_HEAD(dev_kill_list);
 
+       cleanup_net_task = current;
+
        /* Atomically snapshot the list of namespaces to cleanup */
        net_kill_list = llist_del_all(&cleanup_list);
 
@@ -670,6 +674,7 @@ static void cleanup_net(struct work_struct *work)
                put_user_ns(net->user_ns);
                net_free(net);
        }
+       cleanup_net_task = NULL;
 }
 
 /**