mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	net: expedite synchronize_net() for cleanup_net()
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>
This commit is contained in:
		
							parent
							
								
									0b6f6593aa
								
							
						
					
					
						commit
						0734d7c3d9
					
				
					 3 changed files with 17 additions and 1 deletions
				
			
		| 
						 | 
					@ -210,6 +210,8 @@ void net_ns_barrier(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct ns_common *get_net_ns(struct ns_common *ns);
 | 
					struct ns_common *get_net_ns(struct ns_common *ns);
 | 
				
			||||||
struct net *get_net_ns_by_fd(int fd);
 | 
					struct net *get_net_ns_by_fd(int fd);
 | 
				
			||||||
 | 
					extern struct task_struct *cleanup_net_task;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#else /* CONFIG_NET_NS */
 | 
					#else /* CONFIG_NET_NS */
 | 
				
			||||||
#include <linux/sched.h>
 | 
					#include <linux/sched.h>
 | 
				
			||||||
#include <linux/nsproxy.h>
 | 
					#include <linux/nsproxy.h>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10099,6 +10099,15 @@ static void dev_index_release(struct net *net, int ifindex)
 | 
				
			||||||
	WARN_ON(xa_erase(&net->dev_by_index, 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 */
 | 
					/* Delayed registration/unregisteration */
 | 
				
			||||||
LIST_HEAD(net_todo_list);
 | 
					LIST_HEAD(net_todo_list);
 | 
				
			||||||
DECLARE_WAIT_QUEUE_HEAD(netdev_unregistering_wq);
 | 
					DECLARE_WAIT_QUEUE_HEAD(netdev_unregistering_wq);
 | 
				
			||||||
| 
						 | 
					@ -11474,7 +11483,7 @@ EXPORT_SYMBOL_GPL(alloc_netdev_dummy);
 | 
				
			||||||
void synchronize_net(void)
 | 
					void synchronize_net(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	might_sleep();
 | 
						might_sleep();
 | 
				
			||||||
	if (rtnl_is_locked())
 | 
						if (from_cleanup_net() || rtnl_is_locked())
 | 
				
			||||||
		synchronize_rcu_expedited();
 | 
							synchronize_rcu_expedited();
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		synchronize_rcu();
 | 
							synchronize_rcu();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -588,6 +588,8 @@ static void unhash_nsid(struct net *net, struct net *last)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static LLIST_HEAD(cleanup_list);
 | 
					static LLIST_HEAD(cleanup_list);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct task_struct *cleanup_net_task;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void cleanup_net(struct work_struct *work)
 | 
					static void cleanup_net(struct work_struct *work)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const struct pernet_operations *ops;
 | 
						const struct pernet_operations *ops;
 | 
				
			||||||
| 
						 | 
					@ -596,6 +598,8 @@ static void cleanup_net(struct work_struct *work)
 | 
				
			||||||
	LIST_HEAD(net_exit_list);
 | 
						LIST_HEAD(net_exit_list);
 | 
				
			||||||
	LIST_HEAD(dev_kill_list);
 | 
						LIST_HEAD(dev_kill_list);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cleanup_net_task = current;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Atomically snapshot the list of namespaces to cleanup */
 | 
						/* Atomically snapshot the list of namespaces to cleanup */
 | 
				
			||||||
	net_kill_list = llist_del_all(&cleanup_list);
 | 
						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);
 | 
							put_user_ns(net->user_ns);
 | 
				
			||||||
		net_free(net);
 | 
							net_free(net);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						cleanup_net_task = NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue