Skip to content

Commit d01397b

Browse files
Eric Dumazetaloktiwa
authored andcommitted
net: add exit_batch_rtnl() method
[ 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 <[email protected]> Reviewed-by: Antoine Tenart <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]> Stable-dep-of: 46841c7 ("gtp: Use for_each_netdev_rcu() in gtp_genl_dump_pdp().") Signed-off-by: Sasha Levin <[email protected]> (cherry picked from commit 2131315571026a91ecda9a690f68bf1de0f51ccd) Signed-off-by: Alok Tiwari <[email protected]>
1 parent b25ff29 commit d01397b

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
@@ -385,6 +385,9 @@ struct pernet_operations {
385385
void (*pre_exit)(struct net *net);
386386
void (*exit)(struct net *net);
387387
void (*exit_batch)(struct list_head *net_exit_list);
388+
/* Following method is called with RTNL held. */
389+
void (*exit_batch_rtnl)(struct list_head *net_exit_list,
390+
struct list_head *dev_kill_list);
388391
unsigned int *id;
389392
size_t size;
390393
};

net/core/net_namespace.c

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,8 +325,9 @@ static __net_init int setup_net(struct net *net, struct user_namespace *user_ns)
325325
{
326326
/* Must be called with pernet_ops_rwsem held */
327327
const struct pernet_operations *ops, *saved_ops;
328-
int error = 0;
329328
LIST_HEAD(net_exit_list);
329+
LIST_HEAD(dev_kill_list);
330+
int error = 0;
330331

331332
refcount_set(&net->count, 1);
332333
refcount_set(&net->passive, 1);
@@ -359,6 +360,15 @@ static __net_init int setup_net(struct net *net, struct user_namespace *user_ns)
359360

360361
synchronize_rcu();
361362

363+
ops = saved_ops;
364+
rtnl_lock();
365+
list_for_each_entry_continue_reverse(ops, &pernet_list, list) {
366+
if (ops->exit_batch_rtnl)
367+
ops->exit_batch_rtnl(&net_exit_list, &dev_kill_list);
368+
}
369+
unregister_netdevice_many(&dev_kill_list);
370+
rtnl_unlock();
371+
362372
ops = saved_ops;
363373
list_for_each_entry_continue_reverse(ops, &pernet_list, list)
364374
ops_exit_list(ops, &net_exit_list);
@@ -563,6 +573,7 @@ static void cleanup_net(struct work_struct *work)
563573
struct net *net, *tmp, *last;
564574
struct llist_node *net_kill_list;
565575
LIST_HEAD(net_exit_list);
576+
LIST_HEAD(dev_kill_list);
566577

567578
/* Atomically snapshot the list of namespaces to cleanup */
568579
net_kill_list = llist_del_all(&cleanup_list);
@@ -603,6 +614,14 @@ static void cleanup_net(struct work_struct *work)
603614
*/
604615
synchronize_rcu();
605616

617+
rtnl_lock();
618+
list_for_each_entry_reverse(ops, &pernet_list, list) {
619+
if (ops->exit_batch_rtnl)
620+
ops->exit_batch_rtnl(&net_exit_list, &dev_kill_list);
621+
}
622+
unregister_netdevice_many(&dev_kill_list);
623+
rtnl_unlock();
624+
606625
/* Run all of the network namespace exit methods */
607626
list_for_each_entry_reverse(ops, &pernet_list, list)
608627
ops_exit_list(ops, &net_exit_list);
@@ -1150,7 +1169,17 @@ static void free_exit_list(struct pernet_operations *ops, struct list_head *net_
11501169
{
11511170
ops_pre_exit_list(ops, net_exit_list);
11521171
synchronize_rcu();
1172+
1173+
if (ops->exit_batch_rtnl) {
1174+
LIST_HEAD(dev_kill_list);
1175+
1176+
rtnl_lock();
1177+
ops->exit_batch_rtnl(net_exit_list, &dev_kill_list);
1178+
unregister_netdevice_many(&dev_kill_list);
1179+
rtnl_unlock();
1180+
}
11531181
ops_exit_list(ops, net_exit_list);
1182+
11541183
ops_free_list(ops, net_exit_list);
11551184
}
11561185

0 commit comments

Comments
 (0)