Skip to content

Commit b6b6145

Browse files
committed
Merge branch 'net-more-factorization-in-cleanup_net-paths'
Eric Dumazet says: ==================== net: more factorization in cleanup_net() paths This series is inspired by recent syzbot reports hinting to RTNL and workqueue abuses. rtnl_lock() is unfair to (single threaded) cleanup_net(), because many threads can cause contention on it. This series adds a new (struct pernet_operations) method, so that cleanup_net() can hold RTNL longer once it finally acquires it. It also factorizes unregister_netdevice_many(), to further reduce stalls in cleanup_net(). Link: https://lore.kernel.org/netdev/CANn89iLJrrJs+6Vc==Un4rVKcpV0Eof4F_4w1_wQGxUCE2FWAg@mail.gmail.com/T/#u https://lore.kernel.org/netdev/170688415193.5216.10499830272732622816@kwain/ ==================== Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
2 parents a1e55f5 + 8962dac commit b6b6145

File tree

20 files changed

+190
-157
lines changed

20 files changed

+190
-157
lines changed

drivers/net/bareudp.c

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -760,23 +760,18 @@ static void bareudp_destroy_tunnels(struct net *net, struct list_head *head)
760760
unregister_netdevice_queue(bareudp->dev, head);
761761
}
762762

763-
static void __net_exit bareudp_exit_batch_net(struct list_head *net_list)
763+
static void __net_exit bareudp_exit_batch_rtnl(struct list_head *net_list,
764+
struct list_head *dev_kill_list)
764765
{
765766
struct net *net;
766-
LIST_HEAD(list);
767767

768-
rtnl_lock();
769768
list_for_each_entry(net, net_list, exit_list)
770-
bareudp_destroy_tunnels(net, &list);
771-
772-
/* unregister the devices gathered above */
773-
unregister_netdevice_many(&list);
774-
rtnl_unlock();
769+
bareudp_destroy_tunnels(net, dev_kill_list);
775770
}
776771

777772
static struct pernet_operations bareudp_net_ops = {
778773
.init = bareudp_init_net,
779-
.exit_batch = bareudp_exit_batch_net,
774+
.exit_batch_rtnl = bareudp_exit_batch_rtnl,
780775
.id = &bareudp_net_id,
781776
.size = sizeof(struct bareudp_net),
782777
};

drivers/net/bonding/bond_main.c

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6416,28 +6416,41 @@ static int __net_init bond_net_init(struct net *net)
64166416
return 0;
64176417
}
64186418

6419-
static void __net_exit bond_net_exit_batch(struct list_head *net_list)
6419+
/* According to commit 69b0216ac255 ("bonding: fix bonding_masters
6420+
* race condition in bond unloading") we need to remove sysfs files
6421+
* before we remove our devices (done later in bond_net_exit_batch_rtnl())
6422+
*/
6423+
static void __net_exit bond_net_pre_exit(struct net *net)
6424+
{
6425+
struct bond_net *bn = net_generic(net, bond_net_id);
6426+
6427+
bond_destroy_sysfs(bn);
6428+
}
6429+
6430+
static void __net_exit bond_net_exit_batch_rtnl(struct list_head *net_list,
6431+
struct list_head *dev_kill_list)
64206432
{
64216433
struct bond_net *bn;
64226434
struct net *net;
6423-
LIST_HEAD(list);
6424-
6425-
list_for_each_entry(net, net_list, exit_list) {
6426-
bn = net_generic(net, bond_net_id);
6427-
bond_destroy_sysfs(bn);
6428-
}
64296435

64306436
/* Kill off any bonds created after unregistering bond rtnl ops */
6431-
rtnl_lock();
64326437
list_for_each_entry(net, net_list, exit_list) {
64336438
struct bonding *bond, *tmp_bond;
64346439

64356440
bn = net_generic(net, bond_net_id);
64366441
list_for_each_entry_safe(bond, tmp_bond, &bn->dev_list, bond_list)
6437-
unregister_netdevice_queue(bond->dev, &list);
6442+
unregister_netdevice_queue(bond->dev, dev_kill_list);
64386443
}
6439-
unregister_netdevice_many(&list);
6440-
rtnl_unlock();
6444+
}
6445+
6446+
/* According to commit 23fa5c2caae0 ("bonding: destroy proc directory
6447+
* only after all bonds are gone") bond_destroy_proc_dir() is called
6448+
* after bond_net_exit_batch_rtnl() has completed.
6449+
*/
6450+
static void __net_exit bond_net_exit_batch(struct list_head *net_list)
6451+
{
6452+
struct bond_net *bn;
6453+
struct net *net;
64416454

64426455
list_for_each_entry(net, net_list, exit_list) {
64436456
bn = net_generic(net, bond_net_id);
@@ -6447,6 +6460,8 @@ static void __net_exit bond_net_exit_batch(struct list_head *net_list)
64476460

64486461
static struct pernet_operations bond_net_ops = {
64496462
.init = bond_net_init,
6463+
.pre_exit = bond_net_pre_exit,
6464+
.exit_batch_rtnl = bond_net_exit_batch_rtnl,
64506465
.exit_batch = bond_net_exit_batch,
64516466
.id = &bond_net_id,
64526467
.size = sizeof(struct bond_net),

drivers/net/geneve.c

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1900,29 +1900,26 @@ static void geneve_destroy_tunnels(struct net *net, struct list_head *head)
19001900
}
19011901
}
19021902

1903-
static void __net_exit geneve_exit_batch_net(struct list_head *net_list)
1903+
static void __net_exit geneve_exit_batch_rtnl(struct list_head *net_list,
1904+
struct list_head *dev_to_kill)
19041905
{
19051906
struct net *net;
1906-
LIST_HEAD(list);
19071907

1908-
rtnl_lock();
19091908
list_for_each_entry(net, net_list, exit_list)
1910-
geneve_destroy_tunnels(net, &list);
1911-
1912-
/* unregister the devices gathered above */
1913-
unregister_netdevice_many(&list);
1914-
rtnl_unlock();
1909+
geneve_destroy_tunnels(net, dev_to_kill);
1910+
}
19151911

1916-
list_for_each_entry(net, net_list, exit_list) {
1917-
const struct geneve_net *gn = net_generic(net, geneve_net_id);
1912+
static void __net_exit geneve_exit_net(struct net *net)
1913+
{
1914+
const struct geneve_net *gn = net_generic(net, geneve_net_id);
19181915

1919-
WARN_ON_ONCE(!list_empty(&gn->sock_list));
1920-
}
1916+
WARN_ON_ONCE(!list_empty(&gn->sock_list));
19211917
}
19221918

19231919
static struct pernet_operations geneve_net_ops = {
19241920
.init = geneve_init_net,
1925-
.exit_batch = geneve_exit_batch_net,
1921+
.exit_batch_rtnl = geneve_exit_batch_rtnl,
1922+
.exit = geneve_exit_net,
19261923
.id = &geneve_net_id,
19271924
.size = sizeof(struct geneve_net),
19281925
};

drivers/net/gtp.c

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1876,23 +1876,23 @@ static int __net_init gtp_net_init(struct net *net)
18761876
return 0;
18771877
}
18781878

1879-
static void __net_exit gtp_net_exit(struct net *net)
1879+
static void __net_exit gtp_net_exit_batch_rtnl(struct list_head *net_list,
1880+
struct list_head *dev_to_kill)
18801881
{
1881-
struct gtp_net *gn = net_generic(net, gtp_net_id);
1882-
struct gtp_dev *gtp;
1883-
LIST_HEAD(list);
1882+
struct net *net;
18841883

1885-
rtnl_lock();
1886-
list_for_each_entry(gtp, &gn->gtp_dev_list, list)
1887-
gtp_dellink(gtp->dev, &list);
1884+
list_for_each_entry(net, net_list, exit_list) {
1885+
struct gtp_net *gn = net_generic(net, gtp_net_id);
1886+
struct gtp_dev *gtp;
18881887

1889-
unregister_netdevice_many(&list);
1890-
rtnl_unlock();
1888+
list_for_each_entry(gtp, &gn->gtp_dev_list, list)
1889+
gtp_dellink(gtp->dev, dev_to_kill);
1890+
}
18911891
}
18921892

18931893
static struct pernet_operations gtp_net_ops = {
18941894
.init = gtp_net_init,
1895-
.exit = gtp_net_exit,
1895+
.exit_batch_rtnl = gtp_net_exit_batch_rtnl,
18961896
.id = &gtp_net_id,
18971897
.size = sizeof(struct gtp_net),
18981898
};

drivers/net/vxlan/vxlan_core.c

Lines changed: 19 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4826,55 +4826,43 @@ static __net_init int vxlan_init_net(struct net *net)
48264826
NULL);
48274827
}
48284828

4829-
static void vxlan_destroy_tunnels(struct net *net, struct list_head *head)
4829+
static void __net_exit vxlan_destroy_tunnels(struct vxlan_net *vn,
4830+
struct list_head *dev_to_kill)
48304831
{
4831-
struct vxlan_net *vn = net_generic(net, vxlan_net_id);
48324832
struct vxlan_dev *vxlan, *next;
4833-
struct net_device *dev, *aux;
4834-
4835-
for_each_netdev_safe(net, dev, aux)
4836-
if (dev->rtnl_link_ops == &vxlan_link_ops)
4837-
unregister_netdevice_queue(dev, head);
4838-
4839-
list_for_each_entry_safe(vxlan, next, &vn->vxlan_list, next) {
4840-
/* If vxlan->dev is in the same netns, it has already been added
4841-
* to the list by the previous loop.
4842-
*/
4843-
if (!net_eq(dev_net(vxlan->dev), net))
4844-
unregister_netdevice_queue(vxlan->dev, head);
4845-
}
48464833

4834+
list_for_each_entry_safe(vxlan, next, &vn->vxlan_list, next)
4835+
vxlan_dellink(vxlan->dev, dev_to_kill);
48474836
}
48484837

4849-
static void __net_exit vxlan_exit_batch_net(struct list_head *net_list)
4838+
static void __net_exit vxlan_exit_batch_rtnl(struct list_head *net_list,
4839+
struct list_head *dev_to_kill)
48504840
{
48514841
struct net *net;
4852-
LIST_HEAD(list);
4853-
unsigned int h;
48544842

4843+
ASSERT_RTNL();
48554844
list_for_each_entry(net, net_list, exit_list) {
48564845
struct vxlan_net *vn = net_generic(net, vxlan_net_id);
48574846

4858-
unregister_nexthop_notifier(net, &vn->nexthop_notifier_block);
4859-
}
4860-
rtnl_lock();
4861-
list_for_each_entry(net, net_list, exit_list)
4862-
vxlan_destroy_tunnels(net, &list);
4847+
__unregister_nexthop_notifier(net, &vn->nexthop_notifier_block);
48634848

4864-
unregister_netdevice_many(&list);
4865-
rtnl_unlock();
4849+
vxlan_destroy_tunnels(vn, dev_to_kill);
4850+
}
4851+
}
48664852

4867-
list_for_each_entry(net, net_list, exit_list) {
4868-
struct vxlan_net *vn = net_generic(net, vxlan_net_id);
4853+
static void __net_exit vxlan_exit_net(struct net *net)
4854+
{
4855+
struct vxlan_net *vn = net_generic(net, vxlan_net_id);
4856+
unsigned int h;
48694857

4870-
for (h = 0; h < PORT_HASH_SIZE; ++h)
4871-
WARN_ON_ONCE(!hlist_empty(&vn->sock_list[h]));
4872-
}
4858+
for (h = 0; h < PORT_HASH_SIZE; ++h)
4859+
WARN_ON_ONCE(!hlist_empty(&vn->sock_list[h]));
48734860
}
48744861

48754862
static struct pernet_operations vxlan_net_ops = {
48764863
.init = vxlan_init_net,
4877-
.exit_batch = vxlan_exit_batch_net,
4864+
.exit_batch_rtnl = vxlan_exit_batch_rtnl,
4865+
.exit = vxlan_exit_net,
48784866
.id = &vxlan_net_id,
48794867
.size = sizeof(struct vxlan_net),
48804868
};

include/net/ip_tunnels.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,8 @@ int ip_tunnel_init_net(struct net *net, unsigned int ip_tnl_net_id,
284284
struct rtnl_link_ops *ops, char *devname);
285285

286286
void ip_tunnel_delete_nets(struct list_head *list_net, unsigned int id,
287-
struct rtnl_link_ops *ops);
287+
struct rtnl_link_ops *ops,
288+
struct list_head *dev_to_kill);
288289

289290
void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
290291
const struct iphdr *tnl_params, const u8 protocol);

include/net/net_namespace.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,9 @@ struct pernet_operations {
448448
void (*pre_exit)(struct net *net);
449449
void (*exit)(struct net *net);
450450
void (*exit_batch)(struct list_head *net_exit_list);
451+
/* Following method is called with RTNL held. */
452+
void (*exit_batch_rtnl)(struct list_head *net_exit_list,
453+
struct list_head *dev_kill_list);
451454
unsigned int *id;
452455
size_t size;
453456
};

include/net/nexthop.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ struct nh_notifier_info {
218218

219219
int register_nexthop_notifier(struct net *net, struct notifier_block *nb,
220220
struct netlink_ext_ack *extack);
221+
int __unregister_nexthop_notifier(struct net *net, struct notifier_block *nb);
221222
int unregister_nexthop_notifier(struct net *net, struct notifier_block *nb);
222223
void nexthop_set_hw_flags(struct net *net, u32 id, bool offload, bool trap);
223224
void nexthop_bucket_set_hw_flags(struct net *net, u32 id, u16 bucket_index,

net/bridge/br.c

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -356,26 +356,21 @@ void br_opt_toggle(struct net_bridge *br, enum net_bridge_opts opt, bool on)
356356
clear_bit(opt, &br->options);
357357
}
358358

359-
static void __net_exit br_net_exit_batch(struct list_head *net_list)
359+
static void __net_exit br_net_exit_batch_rtnl(struct list_head *net_list,
360+
struct list_head *dev_to_kill)
360361
{
361362
struct net_device *dev;
362363
struct net *net;
363-
LIST_HEAD(list);
364-
365-
rtnl_lock();
366364

365+
ASSERT_RTNL();
367366
list_for_each_entry(net, net_list, exit_list)
368367
for_each_netdev(net, dev)
369368
if (netif_is_bridge_master(dev))
370-
br_dev_delete(dev, &list);
371-
372-
unregister_netdevice_many(&list);
373-
374-
rtnl_unlock();
369+
br_dev_delete(dev, dev_to_kill);
375370
}
376371

377372
static struct pernet_operations br_net_ops = {
378-
.exit_batch = br_net_exit_batch,
373+
.exit_batch_rtnl = br_net_exit_batch_rtnl,
379374
};
380375

381376
static const struct stp_proto br_stp_proto = {

net/core/net_namespace.c

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,8 +318,9 @@ static __net_init int setup_net(struct net *net, struct user_namespace *user_ns)
318318
{
319319
/* Must be called with pernet_ops_rwsem held */
320320
const struct pernet_operations *ops, *saved_ops;
321-
int error = 0;
322321
LIST_HEAD(net_exit_list);
322+
LIST_HEAD(dev_kill_list);
323+
int error = 0;
323324

324325
refcount_set(&net->ns.count, 1);
325326
ref_tracker_dir_init(&net->refcnt_tracker, 128, "net refcnt");
@@ -357,6 +358,15 @@ static __net_init int setup_net(struct net *net, struct user_namespace *user_ns)
357358

358359
synchronize_rcu();
359360

361+
ops = saved_ops;
362+
rtnl_lock();
363+
list_for_each_entry_continue_reverse(ops, &pernet_list, list) {
364+
if (ops->exit_batch_rtnl)
365+
ops->exit_batch_rtnl(&net_exit_list, &dev_kill_list);
366+
}
367+
unregister_netdevice_many(&dev_kill_list);
368+
rtnl_unlock();
369+
360370
ops = saved_ops;
361371
list_for_each_entry_continue_reverse(ops, &pernet_list, list)
362372
ops_exit_list(ops, &net_exit_list);
@@ -573,6 +583,7 @@ static void cleanup_net(struct work_struct *work)
573583
struct net *net, *tmp, *last;
574584
struct llist_node *net_kill_list;
575585
LIST_HEAD(net_exit_list);
586+
LIST_HEAD(dev_kill_list);
576587

577588
/* Atomically snapshot the list of namespaces to cleanup */
578589
net_kill_list = llist_del_all(&cleanup_list);
@@ -613,6 +624,14 @@ static void cleanup_net(struct work_struct *work)
613624
*/
614625
synchronize_rcu();
615626

627+
rtnl_lock();
628+
list_for_each_entry_reverse(ops, &pernet_list, list) {
629+
if (ops->exit_batch_rtnl)
630+
ops->exit_batch_rtnl(&net_exit_list, &dev_kill_list);
631+
}
632+
unregister_netdevice_many(&dev_kill_list);
633+
rtnl_unlock();
634+
616635
/* Run all of the network namespace exit methods */
617636
list_for_each_entry_reverse(ops, &pernet_list, list)
618637
ops_exit_list(ops, &net_exit_list);
@@ -1193,7 +1212,17 @@ static void free_exit_list(struct pernet_operations *ops, struct list_head *net_
11931212
{
11941213
ops_pre_exit_list(ops, net_exit_list);
11951214
synchronize_rcu();
1215+
1216+
if (ops->exit_batch_rtnl) {
1217+
LIST_HEAD(dev_kill_list);
1218+
1219+
rtnl_lock();
1220+
ops->exit_batch_rtnl(net_exit_list, &dev_kill_list);
1221+
unregister_netdevice_many(&dev_kill_list);
1222+
rtnl_unlock();
1223+
}
11961224
ops_exit_list(ops, net_exit_list);
1225+
11971226
ops_free_list(ops, net_exit_list);
11981227
}
11991228

0 commit comments

Comments
 (0)