diff options
Diffstat (limited to 'net/core/dev.c')
-rw-r--r-- | net/core/dev.c | 52 |
1 files changed, 50 insertions, 2 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index 5c713f2239cc..3430b1ed12e5 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -1917,7 +1917,8 @@ static struct xps_map *expand_xps_map(struct xps_map *map, | |||
1917 | return new_map; | 1917 | return new_map; |
1918 | } | 1918 | } |
1919 | 1919 | ||
1920 | int netif_set_xps_queue(struct net_device *dev, struct cpumask *mask, u16 index) | 1920 | int netif_set_xps_queue(struct net_device *dev, const struct cpumask *mask, |
1921 | u16 index) | ||
1921 | { | 1922 | { |
1922 | struct xps_dev_maps *dev_maps, *new_dev_maps = NULL; | 1923 | struct xps_dev_maps *dev_maps, *new_dev_maps = NULL; |
1923 | struct xps_map *map, *new_map; | 1924 | struct xps_map *map, *new_map; |
@@ -5247,10 +5248,12 @@ static int dev_new_index(struct net *net) | |||
5247 | 5248 | ||
5248 | /* Delayed registration/unregisteration */ | 5249 | /* Delayed registration/unregisteration */ |
5249 | static LIST_HEAD(net_todo_list); | 5250 | static LIST_HEAD(net_todo_list); |
5251 | static DECLARE_WAIT_QUEUE_HEAD(netdev_unregistering_wq); | ||
5250 | 5252 | ||
5251 | static void net_set_todo(struct net_device *dev) | 5253 | static void net_set_todo(struct net_device *dev) |
5252 | { | 5254 | { |
5253 | list_add_tail(&dev->todo_list, &net_todo_list); | 5255 | list_add_tail(&dev->todo_list, &net_todo_list); |
5256 | dev_net(dev)->dev_unreg_count++; | ||
5254 | } | 5257 | } |
5255 | 5258 | ||
5256 | static void rollback_registered_many(struct list_head *head) | 5259 | static void rollback_registered_many(struct list_head *head) |
@@ -5918,6 +5921,12 @@ void netdev_run_todo(void) | |||
5918 | if (dev->destructor) | 5921 | if (dev->destructor) |
5919 | dev->destructor(dev); | 5922 | dev->destructor(dev); |
5920 | 5923 | ||
5924 | /* Report a network device has been unregistered */ | ||
5925 | rtnl_lock(); | ||
5926 | dev_net(dev)->dev_unreg_count--; | ||
5927 | __rtnl_unlock(); | ||
5928 | wake_up(&netdev_unregistering_wq); | ||
5929 | |||
5921 | /* Free network device */ | 5930 | /* Free network device */ |
5922 | kobject_put(&dev->dev.kobj); | 5931 | kobject_put(&dev->dev.kobj); |
5923 | } | 5932 | } |
@@ -6603,6 +6612,34 @@ static void __net_exit default_device_exit(struct net *net) | |||
6603 | rtnl_unlock(); | 6612 | rtnl_unlock(); |
6604 | } | 6613 | } |
6605 | 6614 | ||
6615 | static void __net_exit rtnl_lock_unregistering(struct list_head *net_list) | ||
6616 | { | ||
6617 | /* Return with the rtnl_lock held when there are no network | ||
6618 | * devices unregistering in any network namespace in net_list. | ||
6619 | */ | ||
6620 | struct net *net; | ||
6621 | bool unregistering; | ||
6622 | DEFINE_WAIT(wait); | ||
6623 | |||
6624 | for (;;) { | ||
6625 | prepare_to_wait(&netdev_unregistering_wq, &wait, | ||
6626 | TASK_UNINTERRUPTIBLE); | ||
6627 | unregistering = false; | ||
6628 | rtnl_lock(); | ||
6629 | list_for_each_entry(net, net_list, exit_list) { | ||
6630 | if (net->dev_unreg_count > 0) { | ||
6631 | unregistering = true; | ||
6632 | break; | ||
6633 | } | ||
6634 | } | ||
6635 | if (!unregistering) | ||
6636 | break; | ||
6637 | __rtnl_unlock(); | ||
6638 | schedule(); | ||
6639 | } | ||
6640 | finish_wait(&netdev_unregistering_wq, &wait); | ||
6641 | } | ||
6642 | |||
6606 | static void __net_exit default_device_exit_batch(struct list_head *net_list) | 6643 | static void __net_exit default_device_exit_batch(struct list_head *net_list) |
6607 | { | 6644 | { |
6608 | /* At exit all network devices most be removed from a network | 6645 | /* At exit all network devices most be removed from a network |
@@ -6614,7 +6651,18 @@ static void __net_exit default_device_exit_batch(struct list_head *net_list) | |||
6614 | struct net *net; | 6651 | struct net *net; |
6615 | LIST_HEAD(dev_kill_list); | 6652 | LIST_HEAD(dev_kill_list); |
6616 | 6653 | ||
6617 | rtnl_lock(); | 6654 | /* To prevent network device cleanup code from dereferencing |
6655 | * loopback devices or network devices that have been freed | ||
6656 | * wait here for all pending unregistrations to complete, | ||
6657 | * before unregistring the loopback device and allowing the | ||
6658 | * network namespace be freed. | ||
6659 | * | ||
6660 | * The netdev todo list containing all network devices | ||
6661 | * unregistrations that happen in default_device_exit_batch | ||
6662 | * will run in the rtnl_unlock() at the end of | ||
6663 | * default_device_exit_batch. | ||
6664 | */ | ||
6665 | rtnl_lock_unregistering(net_list); | ||
6618 | list_for_each_entry(net, net_list, exit_list) { | 6666 | list_for_each_entry(net, net_list, exit_list) { |
6619 | for_each_netdev_reverse(net, dev) { | 6667 | for_each_netdev_reverse(net, dev) { |
6620 | if (dev->rtnl_link_ops) | 6668 | if (dev->rtnl_link_ops) |