net: introduce NETDEV_UNREGISTER_PERNET

This new event is called once for each unique net namespace in batched
unregister operations (with the argument set to a random device from
that namespace) and once per device in non-batched unregister
operations.

It allows us to factorize some device unregister work such as clearing the
routing cache.

Signed-off-by: Octavian Purdila <opurdila@ixiacom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Octavian Purdila 2009-11-16 13:49:35 +00:00 committed by David S. Miller
parent fccaf71011
commit 395264d509
2 changed files with 28 additions and 2 deletions

View File

@ -202,6 +202,7 @@ static inline int notifier_to_errno(int ret)
#define NETDEV_BONDING_OLDTYPE 0x000E #define NETDEV_BONDING_OLDTYPE 0x000E
#define NETDEV_BONDING_NEWTYPE 0x000F #define NETDEV_BONDING_NEWTYPE 0x000F
#define NETDEV_POST_INIT 0x0010 #define NETDEV_POST_INIT 0x0010
#define NETDEV_UNREGISTER_PERNET 0x0011
#define SYS_DOWN 0x0001 /* Notify of system down */ #define SYS_DOWN 0x0001 /* Notify of system down */
#define SYS_RESTART SYS_DOWN #define SYS_RESTART SYS_DOWN

View File

@ -1344,6 +1344,7 @@ rollback:
nb->notifier_call(nb, NETDEV_DOWN, dev); nb->notifier_call(nb, NETDEV_DOWN, dev);
} }
nb->notifier_call(nb, NETDEV_UNREGISTER, dev); nb->notifier_call(nb, NETDEV_UNREGISTER, dev);
nb->notifier_call(nb, NETDEV_UNREGISTER_PERNET, dev);
} }
} }
@ -4721,7 +4722,8 @@ static void net_set_todo(struct net_device *dev)
static void rollback_registered_many(struct list_head *head) static void rollback_registered_many(struct list_head *head)
{ {
struct net_device *dev; struct net_device *dev, *aux, *fdev;
LIST_HEAD(pernet_list);
BUG_ON(dev_boot_phase); BUG_ON(dev_boot_phase);
ASSERT_RTNL(); ASSERT_RTNL();
@ -4779,8 +4781,24 @@ static void rollback_registered_many(struct list_head *head)
synchronize_net(); synchronize_net();
list_for_each_entry(dev, head, unreg_list) list_for_each_entry_safe(dev, aux, head, unreg_list) {
int new_net = 1;
list_for_each_entry(fdev, &pernet_list, unreg_list) {
if (dev_net(dev) == dev_net(fdev)) {
new_net = 0;
dev_put(dev);
break;
}
}
if (new_net)
list_move(&dev->unreg_list, &pernet_list);
}
list_for_each_entry_safe(dev, aux, &pernet_list, unreg_list) {
call_netdevice_notifiers(NETDEV_UNREGISTER_PERNET, dev);
list_move(&dev->unreg_list, head);
dev_put(dev); dev_put(dev);
}
} }
static void rollback_registered(struct net_device *dev) static void rollback_registered(struct net_device *dev)
@ -5074,6 +5092,8 @@ static void netdev_wait_allrefs(struct net_device *dev)
/* Rebroadcast unregister notification */ /* Rebroadcast unregister notification */
call_netdevice_notifiers(NETDEV_UNREGISTER, dev); call_netdevice_notifiers(NETDEV_UNREGISTER, dev);
/* don't resend NETDEV_UNREGISTER_PERNET, _PERNET users
* should have already handle it the first time */
if (test_bit(__LINK_STATE_LINKWATCH_PENDING, if (test_bit(__LINK_STATE_LINKWATCH_PENDING,
&dev->state)) { &dev->state)) {
@ -5385,6 +5405,10 @@ EXPORT_SYMBOL(unregister_netdevice_queue);
* unregister_netdevice_many - unregister many devices * unregister_netdevice_many - unregister many devices
* @head: list of devices * @head: list of devices
* *
* WARNING: Calling this modifies the given list
* (in rollback_registered_many). It may change the order of the elements
* in the list. However, you can assume it does not add or delete elements
* to/from the list.
*/ */
void unregister_netdevice_many(struct list_head *head) void unregister_netdevice_many(struct list_head *head)
{ {
@ -5504,6 +5528,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char
this device. They should clean all the things. this device. They should clean all the things.
*/ */
call_netdevice_notifiers(NETDEV_UNREGISTER, dev); call_netdevice_notifiers(NETDEV_UNREGISTER, dev);
call_netdevice_notifiers(NETDEV_UNREGISTER_PERNET, dev);
/* /*
* Flush the unicast and multicast chains * Flush the unicast and multicast chains