aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/notifier.h2
-rw-r--r--include/net/route.h1
-rw-r--r--net/core/dev.c36
-rw-r--r--net/ipv4/fib_frontend.c4
-rw-r--r--net/ipv4/route.c6
5 files changed, 20 insertions, 29 deletions
diff --git a/include/linux/notifier.h b/include/linux/notifier.h
index b0c3671d463c..fee6c2f68075 100644
--- a/include/linux/notifier.h
+++ b/include/linux/notifier.h
@@ -202,7 +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#define NETDEV_UNREGISTER_BATCH 0x0011
206 206
207#define SYS_DOWN 0x0001 /* Notify of system down */ 207#define SYS_DOWN 0x0001 /* Notify of system down */
208#define SYS_RESTART SYS_DOWN 208#define SYS_RESTART SYS_DOWN
diff --git a/include/net/route.h b/include/net/route.h
index cfb4c071a136..bce6dd68d27b 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -108,6 +108,7 @@ extern int ip_rt_init(void);
108extern void ip_rt_redirect(__be32 old_gw, __be32 dst, __be32 new_gw, 108extern void ip_rt_redirect(__be32 old_gw, __be32 dst, __be32 new_gw,
109 __be32 src, struct net_device *dev); 109 __be32 src, struct net_device *dev);
110extern void rt_cache_flush(struct net *net, int how); 110extern void rt_cache_flush(struct net *net, int how);
111extern void rt_cache_flush_batch(void);
111extern int __ip_route_output_key(struct net *, struct rtable **, const struct flowi *flp); 112extern int __ip_route_output_key(struct net *, struct rtable **, const struct flowi *flp);
112extern int ip_route_output_key(struct net *, struct rtable **, struct flowi *flp); 113extern int ip_route_output_key(struct net *, struct rtable **, struct flowi *flp);
113extern int ip_route_output_flow(struct net *, struct rtable **rp, struct flowi *flp, struct sock *sk, int flags); 114extern int ip_route_output_flow(struct net *, struct rtable **rp, struct flowi *flp, struct sock *sk, int flags);
diff --git a/net/core/dev.c b/net/core/dev.c
index 5d131c2f84cc..bb37ee1e0901 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1353,7 +1353,7 @@ rollback:
1353 nb->notifier_call(nb, NETDEV_DOWN, dev); 1353 nb->notifier_call(nb, NETDEV_DOWN, dev);
1354 } 1354 }
1355 nb->notifier_call(nb, NETDEV_UNREGISTER, dev); 1355 nb->notifier_call(nb, NETDEV_UNREGISTER, dev);
1356 nb->notifier_call(nb, NETDEV_UNREGISTER_PERNET, dev); 1356 nb->notifier_call(nb, NETDEV_UNREGISTER_BATCH, dev);
1357 } 1357 }
1358 } 1358 }
1359 1359
@@ -4771,8 +4771,7 @@ static void net_set_todo(struct net_device *dev)
4771 4771
4772static void rollback_registered_many(struct list_head *head) 4772static void rollback_registered_many(struct list_head *head)
4773{ 4773{
4774 struct net_device *dev, *aux, *fdev; 4774 struct net_device *dev;
4775 LIST_HEAD(pernet_list);
4776 4775
4777 BUG_ON(dev_boot_phase); 4776 BUG_ON(dev_boot_phase);
4778 ASSERT_RTNL(); 4777 ASSERT_RTNL();
@@ -4828,26 +4827,14 @@ static void rollback_registered_many(struct list_head *head)
4828 netdev_unregister_kobject(dev); 4827 netdev_unregister_kobject(dev);
4829 } 4828 }
4830 4829
4831 synchronize_net(); 4830 /* Process any work delayed until the end of the batch */
4831 dev = list_entry(head->next, struct net_device, unreg_list);
4832 call_netdevice_notifiers(NETDEV_UNREGISTER_BATCH, dev);
4832 4833
4833 list_for_each_entry_safe(dev, aux, head, unreg_list) { 4834 synchronize_net();
4834 int new_net = 1;
4835 list_for_each_entry(fdev, &pernet_list, unreg_list) {
4836 if (net_eq(dev_net(dev), dev_net(fdev))) {
4837 new_net = 0;
4838 dev_put(dev);
4839 break;
4840 }
4841 }
4842 if (new_net)
4843 list_move(&dev->unreg_list, &pernet_list);
4844 }
4845 4835
4846 list_for_each_entry_safe(dev, aux, &pernet_list, unreg_list) { 4836 list_for_each_entry(dev, head, unreg_list)
4847 call_netdevice_notifiers(NETDEV_UNREGISTER_PERNET, dev);
4848 list_move(&dev->unreg_list, head);
4849 dev_put(dev); 4837 dev_put(dev);
4850 }
4851} 4838}
4852 4839
4853static void rollback_registered(struct net_device *dev) 4840static void rollback_registered(struct net_device *dev)
@@ -5129,7 +5116,7 @@ static void netdev_wait_allrefs(struct net_device *dev)
5129 5116
5130 /* Rebroadcast unregister notification */ 5117 /* Rebroadcast unregister notification */
5131 call_netdevice_notifiers(NETDEV_UNREGISTER, dev); 5118 call_netdevice_notifiers(NETDEV_UNREGISTER, dev);
5132 /* don't resend NETDEV_UNREGISTER_PERNET, _PERNET users 5119 /* don't resend NETDEV_UNREGISTER_BATCH, _BATCH users
5133 * should have already handle it the first time */ 5120 * should have already handle it the first time */
5134 5121
5135 if (test_bit(__LINK_STATE_LINKWATCH_PENDING, 5122 if (test_bit(__LINK_STATE_LINKWATCH_PENDING,
@@ -5442,11 +5429,6 @@ EXPORT_SYMBOL(unregister_netdevice_queue);
5442/** 5429/**
5443 * unregister_netdevice_many - unregister many devices 5430 * unregister_netdevice_many - unregister many devices
5444 * @head: list of devices 5431 * @head: list of devices
5445 *
5446 * WARNING: Calling this modifies the given list
5447 * (in rollback_registered_many). It may change the order of the elements
5448 * in the list. However, you can assume it does not add or delete elements
5449 * to/from the list.
5450 */ 5432 */
5451void unregister_netdevice_many(struct list_head *head) 5433void unregister_netdevice_many(struct list_head *head)
5452{ 5434{
@@ -5555,7 +5537,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char
5555 this device. They should clean all the things. 5537 this device. They should clean all the things.
5556 */ 5538 */
5557 call_netdevice_notifiers(NETDEV_UNREGISTER, dev); 5539 call_netdevice_notifiers(NETDEV_UNREGISTER, dev);
5558 call_netdevice_notifiers(NETDEV_UNREGISTER_PERNET, dev); 5540 call_netdevice_notifiers(NETDEV_UNREGISTER_BATCH, dev);
5559 5541
5560 /* 5542 /*
5561 * Flush the unicast and multicast chains 5543 * Flush the unicast and multicast chains
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index 6c1e56aef1f4..3b373a8b0473 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -959,9 +959,11 @@ static int fib_netdev_event(struct notifier_block *this, unsigned long event, vo
959 break; 959 break;
960 case NETDEV_CHANGEMTU: 960 case NETDEV_CHANGEMTU:
961 case NETDEV_CHANGE: 961 case NETDEV_CHANGE:
962 case NETDEV_UNREGISTER_PERNET:
963 rt_cache_flush(dev_net(dev), 0); 962 rt_cache_flush(dev_net(dev), 0);
964 break; 963 break;
964 case NETDEV_UNREGISTER_BATCH:
965 rt_cache_flush_batch();
966 break;
965 } 967 }
966 return NOTIFY_DONE; 968 return NOTIFY_DONE;
967} 969}
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 9889fbd96487..90cdcfc32937 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -900,6 +900,12 @@ void rt_cache_flush(struct net *net, int delay)
900 rt_do_flush(!in_softirq()); 900 rt_do_flush(!in_softirq());
901} 901}
902 902
903/* Flush previous cache invalidated entries from the cache */
904void rt_cache_flush_batch(void)
905{
906 rt_do_flush(!in_softirq());
907}
908
903/* 909/*
904 * We change rt_genid and let gc do the cleanup 910 * We change rt_genid and let gc do the cleanup
905 */ 911 */