aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2009-11-29 10:45:58 -0500
committerDavid S. Miller <davem@davemloft.net>2009-12-01 19:15:50 -0500
commita5ee155136b4a8f4ab0e4c9c064b661da475e298 (patch)
tree10c113756ff0dcc860735d96ed141701bffa3476
parent5a5b6f6f62ac684a5856121d8cffd3c3253dc890 (diff)
net: NETDEV_UNREGISTER_PERNET -> NETDEV_UNREGISTER_BATCH
The motivation for an additional notifier in batched netdevice notification (rt_do_flush) only needs to be called once per batch not once per namespace. For further batching improvements I need a guarantee that the netdevices are unregistered in order allowing me to unregister an all of the network devices in a network namespace at the same time with the guarantee that the loopback device is really and truly unregistered last. Additionally it appears that we moved the route cache flush after the final synchronize_net, which seems wrong and there was no explanation. So I have restored the original location of the final synchronize_net. Cc: Octavian Purdila <opurdila@ixiacom.com> Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-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 */