Skip to content

Commit 346b341

Browse files
committed
Merge branch 'gtp-geneve-suppress-list_del-splat-during-exit_batch_rtnl'
Kuniyuki Iwashima says: ==================== gtp/geneve: Suppress list_del() splat during ->exit_batch_rtnl(). The common pattern in tunnel device's ->exit_batch_rtnl() is iterating two netdev lists for each netns: (i) for_each_netdev() to clean up devices in the netns, and (ii) the device type specific list to clean up devices in other netns. list_for_each_entry(net, net_list, exit_list) { for_each_netdev_safe(net, dev, next) { /* (i) call unregister_netdevice_queue(dev, list) */ } list_for_each_entry_safe(xxx, xxx_next, &net->yyy, zzz) { /* (ii) call unregister_netdevice_queue(xxx->dev, list) */ } } Then, ->exit_batch_rtnl() could touch the same device twice. Say we have two netns A & B and device B that is created in netns A and moved to netns B. 1. cleanup_net() processes netns A and then B. 2. ->exit_batch_rtnl() finds the device B while iterating netns A's (ii) [ device B is not yet unlinked from netns B as unregister_netdevice_many() has not been called. ] 3. ->exit_batch_rtnl() finds the device B while iterating netns B's (i) gtp and geneve calls ->dellink() at 2. and 3. that calls list_del() for (ii) and unregister_netdevice_queue(). Calling unregister_netdevice_queue() twice is fine because it uses list_move_tail(), but the 2nd list_del() triggers a splat when CONFIG_DEBUG_LIST is enabled. Possible solution is either of (a) Use list_del_init() in ->dellink() (b) Iterate dev with empty ->unreg_list for (i) like #define for_each_netdev_alive(net, d) \ list_for_each_entry(d, &(net)->dev_base_head, dev_list) \ if (list_empty(&d->unreg_list)) (c) Remove (i) and delegate it to default_device_exit_batch(). This series avoids the 2nd ->dellink() by (c) to suppress the splat for gtp and geneve. Note that IPv4/IPv6 tunnels calls just unregister_netdevice() during ->exit_batch_rtnl() and dev is unlinked from (ii) later in ->ndo_uninit(), so they are safe. Also, pfcp has the same pattern but is safe because unregister_netdevice_many() is called for each netns. ==================== Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
2 parents a92c322 + 62fab6e commit 346b341

File tree

2 files changed

+0
-12
lines changed

2 files changed

+0
-12
lines changed

drivers/net/geneve.c

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1902,14 +1902,7 @@ static void geneve_destroy_tunnels(struct net *net, struct list_head *head)
19021902
{
19031903
struct geneve_net *gn = net_generic(net, geneve_net_id);
19041904
struct geneve_dev *geneve, *next;
1905-
struct net_device *dev, *aux;
19061905

1907-
/* gather any geneve devices that were moved into this ns */
1908-
for_each_netdev_safe(net, dev, aux)
1909-
if (dev->rtnl_link_ops == &geneve_link_ops)
1910-
geneve_dellink(dev, head);
1911-
1912-
/* now gather any other geneve devices that were created in this ns */
19131906
list_for_each_entry_safe(geneve, next, &gn->geneve_list, next)
19141907
geneve_dellink(geneve->dev, head);
19151908
}

drivers/net/gtp.c

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2481,11 +2481,6 @@ static void __net_exit gtp_net_exit_batch_rtnl(struct list_head *net_list,
24812481
list_for_each_entry(net, net_list, exit_list) {
24822482
struct gtp_net *gn = net_generic(net, gtp_net_id);
24832483
struct gtp_dev *gtp, *gtp_next;
2484-
struct net_device *dev;
2485-
2486-
for_each_netdev(net, dev)
2487-
if (dev->rtnl_link_ops == &gtp_link_ops)
2488-
gtp_dellink(dev, dev_to_kill);
24892484

24902485
list_for_each_entry_safe(gtp, gtp_next, &gn->gtp_dev_list, list)
24912486
gtp_dellink(gtp->dev, dev_to_kill);

0 commit comments

Comments
 (0)