diff options
-rw-r--r-- | include/linux/netdevice.h | 1 | ||||
-rw-r--r-- | net/core/dev.c | 25 | ||||
-rw-r--r-- | net/sched/sch_generic.c | 6 |
3 files changed, 18 insertions, 14 deletions
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index f5cd464271bf..6d77e0f3cc10 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h | |||
@@ -1143,6 +1143,7 @@ struct net_device { | |||
1143 | struct list_head dev_list; | 1143 | struct list_head dev_list; |
1144 | struct list_head napi_list; | 1144 | struct list_head napi_list; |
1145 | struct list_head unreg_list; | 1145 | struct list_head unreg_list; |
1146 | struct list_head close_list; | ||
1146 | 1147 | ||
1147 | /* directly linked devices, like slaves for bonding */ | 1148 | /* directly linked devices, like slaves for bonding */ |
1148 | struct { | 1149 | struct { |
diff --git a/net/core/dev.c b/net/core/dev.c index c25db20a4246..fa0b2b06c1a6 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -1307,7 +1307,7 @@ static int __dev_close_many(struct list_head *head) | |||
1307 | ASSERT_RTNL(); | 1307 | ASSERT_RTNL(); |
1308 | might_sleep(); | 1308 | might_sleep(); |
1309 | 1309 | ||
1310 | list_for_each_entry(dev, head, unreg_list) { | 1310 | list_for_each_entry(dev, head, close_list) { |
1311 | call_netdevice_notifiers(NETDEV_GOING_DOWN, dev); | 1311 | call_netdevice_notifiers(NETDEV_GOING_DOWN, dev); |
1312 | 1312 | ||
1313 | clear_bit(__LINK_STATE_START, &dev->state); | 1313 | clear_bit(__LINK_STATE_START, &dev->state); |
@@ -1323,7 +1323,7 @@ static int __dev_close_many(struct list_head *head) | |||
1323 | 1323 | ||
1324 | dev_deactivate_many(head); | 1324 | dev_deactivate_many(head); |
1325 | 1325 | ||
1326 | list_for_each_entry(dev, head, unreg_list) { | 1326 | list_for_each_entry(dev, head, close_list) { |
1327 | const struct net_device_ops *ops = dev->netdev_ops; | 1327 | const struct net_device_ops *ops = dev->netdev_ops; |
1328 | 1328 | ||
1329 | /* | 1329 | /* |
@@ -1351,7 +1351,7 @@ static int __dev_close(struct net_device *dev) | |||
1351 | /* Temporarily disable netpoll until the interface is down */ | 1351 | /* Temporarily disable netpoll until the interface is down */ |
1352 | netpoll_rx_disable(dev); | 1352 | netpoll_rx_disable(dev); |
1353 | 1353 | ||
1354 | list_add(&dev->unreg_list, &single); | 1354 | list_add(&dev->close_list, &single); |
1355 | retval = __dev_close_many(&single); | 1355 | retval = __dev_close_many(&single); |
1356 | list_del(&single); | 1356 | list_del(&single); |
1357 | 1357 | ||
@@ -1362,21 +1362,20 @@ static int __dev_close(struct net_device *dev) | |||
1362 | static int dev_close_many(struct list_head *head) | 1362 | static int dev_close_many(struct list_head *head) |
1363 | { | 1363 | { |
1364 | struct net_device *dev, *tmp; | 1364 | struct net_device *dev, *tmp; |
1365 | LIST_HEAD(tmp_list); | ||
1366 | 1365 | ||
1367 | list_for_each_entry_safe(dev, tmp, head, unreg_list) | 1366 | /* Remove the devices that don't need to be closed */ |
1367 | list_for_each_entry_safe(dev, tmp, head, close_list) | ||
1368 | if (!(dev->flags & IFF_UP)) | 1368 | if (!(dev->flags & IFF_UP)) |
1369 | list_move(&dev->unreg_list, &tmp_list); | 1369 | list_del_init(&dev->close_list); |
1370 | 1370 | ||
1371 | __dev_close_many(head); | 1371 | __dev_close_many(head); |
1372 | 1372 | ||
1373 | list_for_each_entry(dev, head, unreg_list) { | 1373 | list_for_each_entry_safe(dev, tmp, head, close_list) { |
1374 | rtmsg_ifinfo(RTM_NEWLINK, dev, IFF_UP|IFF_RUNNING); | 1374 | rtmsg_ifinfo(RTM_NEWLINK, dev, IFF_UP|IFF_RUNNING); |
1375 | call_netdevice_notifiers(NETDEV_DOWN, dev); | 1375 | call_netdevice_notifiers(NETDEV_DOWN, dev); |
1376 | list_del_init(&dev->close_list); | ||
1376 | } | 1377 | } |
1377 | 1378 | ||
1378 | /* rollback_registered_many needs the complete original list */ | ||
1379 | list_splice(&tmp_list, head); | ||
1380 | return 0; | 1379 | return 0; |
1381 | } | 1380 | } |
1382 | 1381 | ||
@@ -1397,7 +1396,7 @@ int dev_close(struct net_device *dev) | |||
1397 | /* Block netpoll rx while the interface is going down */ | 1396 | /* Block netpoll rx while the interface is going down */ |
1398 | netpoll_rx_disable(dev); | 1397 | netpoll_rx_disable(dev); |
1399 | 1398 | ||
1400 | list_add(&dev->unreg_list, &single); | 1399 | list_add(&dev->close_list, &single); |
1401 | dev_close_many(&single); | 1400 | dev_close_many(&single); |
1402 | list_del(&single); | 1401 | list_del(&single); |
1403 | 1402 | ||
@@ -5439,6 +5438,7 @@ static void net_set_todo(struct net_device *dev) | |||
5439 | static void rollback_registered_many(struct list_head *head) | 5438 | static void rollback_registered_many(struct list_head *head) |
5440 | { | 5439 | { |
5441 | struct net_device *dev, *tmp; | 5440 | struct net_device *dev, *tmp; |
5441 | LIST_HEAD(close_head); | ||
5442 | 5442 | ||
5443 | BUG_ON(dev_boot_phase); | 5443 | BUG_ON(dev_boot_phase); |
5444 | ASSERT_RTNL(); | 5444 | ASSERT_RTNL(); |
@@ -5461,7 +5461,9 @@ static void rollback_registered_many(struct list_head *head) | |||
5461 | } | 5461 | } |
5462 | 5462 | ||
5463 | /* If device is running, close it first. */ | 5463 | /* If device is running, close it first. */ |
5464 | dev_close_many(head); | 5464 | list_for_each_entry(dev, head, unreg_list) |
5465 | list_add_tail(&dev->close_list, &close_head); | ||
5466 | dev_close_many(&close_head); | ||
5465 | 5467 | ||
5466 | list_for_each_entry(dev, head, unreg_list) { | 5468 | list_for_each_entry(dev, head, unreg_list) { |
5467 | /* And unlink it from device chain. */ | 5469 | /* And unlink it from device chain. */ |
@@ -6257,6 +6259,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name, | |||
6257 | 6259 | ||
6258 | INIT_LIST_HEAD(&dev->napi_list); | 6260 | INIT_LIST_HEAD(&dev->napi_list); |
6259 | INIT_LIST_HEAD(&dev->unreg_list); | 6261 | INIT_LIST_HEAD(&dev->unreg_list); |
6262 | INIT_LIST_HEAD(&dev->close_list); | ||
6260 | INIT_LIST_HEAD(&dev->link_watch_list); | 6263 | INIT_LIST_HEAD(&dev->link_watch_list); |
6261 | INIT_LIST_HEAD(&dev->adj_list.upper); | 6264 | INIT_LIST_HEAD(&dev->adj_list.upper); |
6262 | INIT_LIST_HEAD(&dev->adj_list.lower); | 6265 | INIT_LIST_HEAD(&dev->adj_list.lower); |
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index e7121d29c4bd..7fc899a943a8 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c | |||
@@ -829,7 +829,7 @@ void dev_deactivate_many(struct list_head *head) | |||
829 | struct net_device *dev; | 829 | struct net_device *dev; |
830 | bool sync_needed = false; | 830 | bool sync_needed = false; |
831 | 831 | ||
832 | list_for_each_entry(dev, head, unreg_list) { | 832 | list_for_each_entry(dev, head, close_list) { |
833 | netdev_for_each_tx_queue(dev, dev_deactivate_queue, | 833 | netdev_for_each_tx_queue(dev, dev_deactivate_queue, |
834 | &noop_qdisc); | 834 | &noop_qdisc); |
835 | if (dev_ingress_queue(dev)) | 835 | if (dev_ingress_queue(dev)) |
@@ -848,7 +848,7 @@ void dev_deactivate_many(struct list_head *head) | |||
848 | synchronize_net(); | 848 | synchronize_net(); |
849 | 849 | ||
850 | /* Wait for outstanding qdisc_run calls. */ | 850 | /* Wait for outstanding qdisc_run calls. */ |
851 | list_for_each_entry(dev, head, unreg_list) | 851 | list_for_each_entry(dev, head, close_list) |
852 | while (some_qdisc_is_busy(dev)) | 852 | while (some_qdisc_is_busy(dev)) |
853 | yield(); | 853 | yield(); |
854 | } | 854 | } |
@@ -857,7 +857,7 @@ void dev_deactivate(struct net_device *dev) | |||
857 | { | 857 | { |
858 | LIST_HEAD(single); | 858 | LIST_HEAD(single); |
859 | 859 | ||
860 | list_add(&dev->unreg_list, &single); | 860 | list_add(&dev->close_list, &single); |
861 | dev_deactivate_many(&single); | 861 | dev_deactivate_many(&single); |
862 | list_del(&single); | 862 | list_del(&single); |
863 | } | 863 | } |