diff options
-rw-r--r-- | include/linux/notifier.h | 1 | ||||
-rw-r--r-- | net/core/dev.c | 29 |
2 files changed, 28 insertions, 2 deletions
diff --git a/include/linux/notifier.h b/include/linux/notifier.h index 29714b8441b1..b0c3671d463c 100644 --- a/include/linux/notifier.h +++ b/include/linux/notifier.h | |||
@@ -202,6 +202,7 @@ static inline int notifier_to_errno(int ret) | |||
202 | #define NETDEV_BONDING_OLDTYPE 0x000E | 202 | #define NETDEV_BONDING_OLDTYPE 0x000E |
203 | #define NETDEV_BONDING_NEWTYPE 0x000F | 203 | #define NETDEV_BONDING_NEWTYPE 0x000F |
204 | #define NETDEV_POST_INIT 0x0010 | 204 | #define NETDEV_POST_INIT 0x0010 |
205 | #define NETDEV_UNREGISTER_PERNET 0x0011 | ||
205 | 206 | ||
206 | #define SYS_DOWN 0x0001 /* Notify of system down */ | 207 | #define SYS_DOWN 0x0001 /* Notify of system down */ |
207 | #define SYS_RESTART SYS_DOWN | 208 | #define SYS_RESTART SYS_DOWN |
diff --git a/net/core/dev.c b/net/core/dev.c index c3e0578d29d1..e25fe5d9343b 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -1344,6 +1344,7 @@ rollback: | |||
1344 | nb->notifier_call(nb, NETDEV_DOWN, dev); | 1344 | nb->notifier_call(nb, NETDEV_DOWN, dev); |
1345 | } | 1345 | } |
1346 | nb->notifier_call(nb, NETDEV_UNREGISTER, dev); | 1346 | nb->notifier_call(nb, NETDEV_UNREGISTER, dev); |
1347 | nb->notifier_call(nb, NETDEV_UNREGISTER_PERNET, dev); | ||
1347 | } | 1348 | } |
1348 | } | 1349 | } |
1349 | 1350 | ||
@@ -4721,7 +4722,8 @@ static void net_set_todo(struct net_device *dev) | |||
4721 | 4722 | ||
4722 | static void rollback_registered_many(struct list_head *head) | 4723 | static void rollback_registered_many(struct list_head *head) |
4723 | { | 4724 | { |
4724 | struct net_device *dev; | 4725 | struct net_device *dev, *aux, *fdev; |
4726 | LIST_HEAD(pernet_list); | ||
4725 | 4727 | ||
4726 | BUG_ON(dev_boot_phase); | 4728 | BUG_ON(dev_boot_phase); |
4727 | ASSERT_RTNL(); | 4729 | ASSERT_RTNL(); |
@@ -4779,8 +4781,24 @@ static void rollback_registered_many(struct list_head *head) | |||
4779 | 4781 | ||
4780 | synchronize_net(); | 4782 | synchronize_net(); |
4781 | 4783 | ||
4782 | list_for_each_entry(dev, head, unreg_list) | 4784 | list_for_each_entry_safe(dev, aux, head, unreg_list) { |
4785 | int new_net = 1; | ||
4786 | list_for_each_entry(fdev, &pernet_list, unreg_list) { | ||
4787 | if (dev_net(dev) == dev_net(fdev)) { | ||
4788 | new_net = 0; | ||
4789 | dev_put(dev); | ||
4790 | break; | ||
4791 | } | ||
4792 | } | ||
4793 | if (new_net) | ||
4794 | list_move(&dev->unreg_list, &pernet_list); | ||
4795 | } | ||
4796 | |||
4797 | list_for_each_entry_safe(dev, aux, &pernet_list, unreg_list) { | ||
4798 | call_netdevice_notifiers(NETDEV_UNREGISTER_PERNET, dev); | ||
4799 | list_move(&dev->unreg_list, head); | ||
4783 | dev_put(dev); | 4800 | dev_put(dev); |
4801 | } | ||
4784 | } | 4802 | } |
4785 | 4803 | ||
4786 | static void rollback_registered(struct net_device *dev) | 4804 | static void rollback_registered(struct net_device *dev) |
@@ -5074,6 +5092,8 @@ static void netdev_wait_allrefs(struct net_device *dev) | |||
5074 | 5092 | ||
5075 | /* Rebroadcast unregister notification */ | 5093 | /* Rebroadcast unregister notification */ |
5076 | call_netdevice_notifiers(NETDEV_UNREGISTER, dev); | 5094 | call_netdevice_notifiers(NETDEV_UNREGISTER, dev); |
5095 | /* don't resend NETDEV_UNREGISTER_PERNET, _PERNET users | ||
5096 | * should have already handle it the first time */ | ||
5077 | 5097 | ||
5078 | if (test_bit(__LINK_STATE_LINKWATCH_PENDING, | 5098 | if (test_bit(__LINK_STATE_LINKWATCH_PENDING, |
5079 | &dev->state)) { | 5099 | &dev->state)) { |
@@ -5385,6 +5405,10 @@ EXPORT_SYMBOL(unregister_netdevice_queue); | |||
5385 | * unregister_netdevice_many - unregister many devices | 5405 | * unregister_netdevice_many - unregister many devices |
5386 | * @head: list of devices | 5406 | * @head: list of devices |
5387 | * | 5407 | * |
5408 | * WARNING: Calling this modifies the given list | ||
5409 | * (in rollback_registered_many). It may change the order of the elements | ||
5410 | * in the list. However, you can assume it does not add or delete elements | ||
5411 | * to/from the list. | ||
5388 | */ | 5412 | */ |
5389 | void unregister_netdevice_many(struct list_head *head) | 5413 | void unregister_netdevice_many(struct list_head *head) |
5390 | { | 5414 | { |
@@ -5504,6 +5528,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char | |||
5504 | this device. They should clean all the things. | 5528 | this device. They should clean all the things. |
5505 | */ | 5529 | */ |
5506 | call_netdevice_notifiers(NETDEV_UNREGISTER, dev); | 5530 | call_netdevice_notifiers(NETDEV_UNREGISTER, dev); |
5531 | call_netdevice_notifiers(NETDEV_UNREGISTER_PERNET, dev); | ||
5507 | 5532 | ||
5508 | /* | 5533 | /* |
5509 | * Flush the unicast and multicast chains | 5534 | * Flush the unicast and multicast chains |