Skip to content

Commit a052122

Browse files
edumazetmehmetb0
authored andcommitted
net: add exit_batch_rtnl() method
BugLink: https://bugs.launchpad.net/bugs/2097298 [ Upstream commit fd4f101 ] Many (struct pernet_operations)->exit_batch() methods have to acquire rtnl. In presence of rtnl mutex pressure, this makes cleanup_net() very slow. This patch adds a new exit_batch_rtnl() method to reduce number of rtnl acquisitions from cleanup_net(). exit_batch_rtnl() handlers are called while rtnl is locked, and devices to be killed can be queued in a list provided as their second argument. A single unregister_netdevice_many() is called right before rtnl is released. exit_batch_rtnl() handlers are called before ->exit() and ->exit_batch() handlers. Signed-off-by: Eric Dumazet <edumazet@google.com> Reviewed-by: Antoine Tenart <atenart@kernel.org> Link: https://lore.kernel.org/r/20240206144313.2050392-2-edumazet@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org> Stable-dep-of: 46841c7 ("gtp: Use for_each_netdev_rcu() in gtp_genl_dump_pdp().") Signed-off-by: Sasha Levin <sashal@kernel.org> Signed-off-by: Noah Wager <noah.wager@canonical.com> Signed-off-by: Koichiro Den <koichiro.den@canonical.com>
1 parent 7d19db2 commit a052122

File tree

2 files changed

+33
-1
lines changed

2 files changed

+33
-1
lines changed

include/net/net_namespace.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,9 @@ struct pernet_operations {
389389
void (*pre_exit)(struct net *net);
390390
void (*exit)(struct net *net);
391391
void (*exit_batch)(struct list_head *net_exit_list);
392+
/* Following method is called with RTNL held. */
393+
void (*exit_batch_rtnl)(struct list_head *net_exit_list,
394+
struct list_head *dev_kill_list);
392395
unsigned int *id;
393396
size_t size;
394397
};

net/core/net_namespace.c

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,8 +313,9 @@ static __net_init int setup_net(struct net *net, struct user_namespace *user_ns)
313313
{
314314
/* Must be called with pernet_ops_rwsem held */
315315
const struct pernet_operations *ops, *saved_ops;
316-
int error = 0;
317316
LIST_HEAD(net_exit_list);
317+
LIST_HEAD(dev_kill_list);
318+
int error = 0;
318319

319320
refcount_set(&net->ns.count, 1);
320321
refcount_set(&net->passive, 1);
@@ -350,6 +351,15 @@ static __net_init int setup_net(struct net *net, struct user_namespace *user_ns)
350351

351352
synchronize_rcu();
352353

354+
ops = saved_ops;
355+
rtnl_lock();
356+
list_for_each_entry_continue_reverse(ops, &pernet_list, list) {
357+
if (ops->exit_batch_rtnl)
358+
ops->exit_batch_rtnl(&net_exit_list, &dev_kill_list);
359+
}
360+
unregister_netdevice_many(&dev_kill_list);
361+
rtnl_unlock();
362+
353363
ops = saved_ops;
354364
list_for_each_entry_continue_reverse(ops, &pernet_list, list)
355365
ops_exit_list(ops, &net_exit_list);
@@ -554,6 +564,7 @@ static void cleanup_net(struct work_struct *work)
554564
struct net *net, *tmp, *last;
555565
struct llist_node *net_kill_list;
556566
LIST_HEAD(net_exit_list);
567+
LIST_HEAD(dev_kill_list);
557568

558569
/* Atomically snapshot the list of namespaces to cleanup */
559570
net_kill_list = llist_del_all(&cleanup_list);
@@ -594,6 +605,14 @@ static void cleanup_net(struct work_struct *work)
594605
*/
595606
synchronize_rcu();
596607

608+
rtnl_lock();
609+
list_for_each_entry_reverse(ops, &pernet_list, list) {
610+
if (ops->exit_batch_rtnl)
611+
ops->exit_batch_rtnl(&net_exit_list, &dev_kill_list);
612+
}
613+
unregister_netdevice_many(&dev_kill_list);
614+
rtnl_unlock();
615+
597616
/* Run all of the network namespace exit methods */
598617
list_for_each_entry_reverse(ops, &pernet_list, list)
599618
ops_exit_list(ops, &net_exit_list);
@@ -1134,7 +1153,17 @@ static void free_exit_list(struct pernet_operations *ops, struct list_head *net_
11341153
{
11351154
ops_pre_exit_list(ops, net_exit_list);
11361155
synchronize_rcu();
1156+
1157+
if (ops->exit_batch_rtnl) {
1158+
LIST_HEAD(dev_kill_list);
1159+
1160+
rtnl_lock();
1161+
ops->exit_batch_rtnl(net_exit_list, &dev_kill_list);
1162+
unregister_netdevice_many(&dev_kill_list);
1163+
rtnl_unlock();
1164+
}
11371165
ops_exit_list(ops, net_exit_list);
1166+
11381167
ops_free_list(ops, net_exit_list);
11391168
}
11401169

0 commit comments

Comments
 (0)