aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2009-10-27 03:04:19 -0400
committerDavid S. Miller <davem@davemloft.net>2009-10-28 05:22:06 -0400
commit9b5e383c11b08784eb0087617f880077982ef769 (patch)
tree090e01601641c39bfb160aa6772336e363628503
parent44a0873d52282f24b1894c58c0f157e0f626ddc9 (diff)
net: Introduce unregister_netdevice_many()
Introduce rollback_registered_many() and unregister_netdevice_many() rollback_registered_many() is able to perform necessary steps at device dismantle time, factorizing two expensive synchronize_net() calls. Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/netdevice.h1
-rw-r--r--net/core/dev.c97
2 files changed, 66 insertions, 32 deletions
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 0ded0a4768a0..e7c227d7cb98 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1119,6 +1119,7 @@ extern int dev_queue_xmit(struct sk_buff *skb);
1119extern int register_netdevice(struct net_device *dev); 1119extern int register_netdevice(struct net_device *dev);
1120extern void unregister_netdevice_queue(struct net_device *dev, 1120extern void unregister_netdevice_queue(struct net_device *dev,
1121 struct list_head *head); 1121 struct list_head *head);
1122extern void unregister_netdevice_many(struct list_head *head);
1122static inline void unregister_netdevice(struct net_device *dev) 1123static inline void unregister_netdevice(struct net_device *dev)
1123{ 1124{
1124 unregister_netdevice_queue(dev, NULL); 1125 unregister_netdevice_queue(dev, NULL);
diff --git a/net/core/dev.c b/net/core/dev.c
index ff94e2b8df7f..04d3e3014020 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4637,59 +4637,76 @@ static void net_set_todo(struct net_device *dev)
4637 list_add_tail(&dev->todo_list, &net_todo_list); 4637 list_add_tail(&dev->todo_list, &net_todo_list);
4638} 4638}
4639 4639
4640static void rollback_registered(struct net_device *dev) 4640static void rollback_registered_many(struct list_head *head)
4641{ 4641{
4642 struct net_device *dev;
4643
4642 BUG_ON(dev_boot_phase); 4644 BUG_ON(dev_boot_phase);
4643 ASSERT_RTNL(); 4645 ASSERT_RTNL();
4644 4646
4645 /* Some devices call without registering for initialization unwind. */ 4647 list_for_each_entry(dev, head, unreg_list) {
4646 if (dev->reg_state == NETREG_UNINITIALIZED) { 4648 /* Some devices call without registering
4647 printk(KERN_DEBUG "unregister_netdevice: device %s/%p never " 4649 * for initialization unwind.
4648 "was registered\n", dev->name, dev); 4650 */
4651 if (dev->reg_state == NETREG_UNINITIALIZED) {
4652 pr_debug("unregister_netdevice: device %s/%p never "
4653 "was registered\n", dev->name, dev);
4649 4654
4650 WARN_ON(1); 4655 WARN_ON(1);
4651 return; 4656 return;
4652 } 4657 }
4653 4658
4654 BUG_ON(dev->reg_state != NETREG_REGISTERED); 4659 BUG_ON(dev->reg_state != NETREG_REGISTERED);
4655 4660
4656 /* If device is running, close it first. */ 4661 /* If device is running, close it first. */
4657 dev_close(dev); 4662 dev_close(dev);
4658 4663
4659 /* And unlink it from device chain. */ 4664 /* And unlink it from device chain. */
4660 unlist_netdevice(dev); 4665 unlist_netdevice(dev);
4661 4666
4662 dev->reg_state = NETREG_UNREGISTERING; 4667 dev->reg_state = NETREG_UNREGISTERING;
4668 }
4663 4669
4664 synchronize_net(); 4670 synchronize_net();
4665 4671
4666 /* Shutdown queueing discipline. */ 4672 list_for_each_entry(dev, head, unreg_list) {
4667 dev_shutdown(dev); 4673 /* Shutdown queueing discipline. */
4674 dev_shutdown(dev);
4668 4675
4669 4676
4670 /* Notify protocols, that we are about to destroy 4677 /* Notify protocols, that we are about to destroy
4671 this device. They should clean all the things. 4678 this device. They should clean all the things.
4672 */ 4679 */
4673 call_netdevice_notifiers(NETDEV_UNREGISTER, dev); 4680 call_netdevice_notifiers(NETDEV_UNREGISTER, dev);
4674 4681
4675 /* 4682 /*
4676 * Flush the unicast and multicast chains 4683 * Flush the unicast and multicast chains
4677 */ 4684 */
4678 dev_unicast_flush(dev); 4685 dev_unicast_flush(dev);
4679 dev_addr_discard(dev); 4686 dev_addr_discard(dev);
4680 4687
4681 if (dev->netdev_ops->ndo_uninit) 4688 if (dev->netdev_ops->ndo_uninit)
4682 dev->netdev_ops->ndo_uninit(dev); 4689 dev->netdev_ops->ndo_uninit(dev);
4683 4690
4684 /* Notifier chain MUST detach us from master device. */ 4691 /* Notifier chain MUST detach us from master device. */
4685 WARN_ON(dev->master); 4692 WARN_ON(dev->master);
4686 4693
4687 /* Remove entries from kobject tree */ 4694 /* Remove entries from kobject tree */
4688 netdev_unregister_kobject(dev); 4695 netdev_unregister_kobject(dev);
4696 }
4689 4697
4690 synchronize_net(); 4698 synchronize_net();
4691 4699
4692 dev_put(dev); 4700 list_for_each_entry(dev, head, unreg_list)
4701 dev_put(dev);
4702}
4703
4704static void rollback_registered(struct net_device *dev)
4705{
4706 LIST_HEAD(single);
4707
4708 list_add(&dev->unreg_list, &single);
4709 rollback_registered_many(&single);
4693} 4710}
4694 4711
4695static void __netdev_init_queue_locks_one(struct net_device *dev, 4712static void __netdev_init_queue_locks_one(struct net_device *dev,
@@ -5272,6 +5289,22 @@ void unregister_netdevice_queue(struct net_device *dev, struct list_head *head)
5272EXPORT_SYMBOL(unregister_netdevice_queue); 5289EXPORT_SYMBOL(unregister_netdevice_queue);
5273 5290
5274/** 5291/**
5292 * unregister_netdevice_many - unregister many devices
5293 * @head: list of devices
5294 *
5295 */
5296void unregister_netdevice_many(struct list_head *head)
5297{
5298 struct net_device *dev;
5299
5300 if (!list_empty(head)) {
5301 rollback_registered_many(head);
5302 list_for_each_entry(dev, head, unreg_list)
5303 net_set_todo(dev);
5304 }
5305}
5306
5307/**
5275 * unregister_netdev - remove device from the kernel 5308 * unregister_netdev - remove device from the kernel
5276 * @dev: device 5309 * @dev: device
5277 * 5310 *