@@ -565,4 +565,6 @@ void net_ns_init(void);
static inline void net_ns_init(void) {}
#endif
+extern struct task_struct *cleanup_net_task;
+
#endif /* __NET_NET_NAMESPACE_H */
@@ -11423,7 +11423,7 @@ EXPORT_SYMBOL_GPL(alloc_netdev_dummy);
void synchronize_net(void)
{
might_sleep();
- if (rtnl_is_locked())
+ if (current == cleanup_net_task || rtnl_is_locked())
synchronize_rcu_expedited();
else
synchronize_rcu();
@@ -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;
}
/**
cleanup_net() is the single thread responsible for netns dismantles, and a potential bottleneck. Before we can get per-netns RTNL, make sure all synchronize_net() called from this thread are using rcu_synchronize_expedited(). Signed-off-by: Eric Dumazet <edumazet@google.com> --- include/net/net_namespace.h | 2 ++ net/core/dev.c | 2 +- net/core/net_namespace.c | 5 +++++ 3 files changed, 8 insertions(+), 1 deletion(-)