diff options
| author | Eric Dumazet <eric.dumazet@gmail.com> | 2009-10-27 07:04:19 +0000 | 
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2009-10-28 02:22:06 -0700 | 
| commit | 9b5e383c11b08784eb0087617f880077982ef769 (patch) | |
| tree | 090e01601641c39bfb160aa6772336e363628503 /net | |
| parent | 44a0873d52282f24b1894c58c0f157e0f626ddc9 (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>
Diffstat (limited to 'net')
| -rw-r--r-- | net/core/dev.c | 97 | 
1 files changed, 65 insertions, 32 deletions
| 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)  	list_add_tail(&dev->todo_list, &net_todo_list);  } -static void rollback_registered(struct net_device *dev) +static void rollback_registered_many(struct list_head *head)  { +	struct net_device *dev; +  	BUG_ON(dev_boot_phase);  	ASSERT_RTNL(); -	/* Some devices call without registering for initialization unwind. */ -	if (dev->reg_state == NETREG_UNINITIALIZED) { -		printk(KERN_DEBUG "unregister_netdevice: device %s/%p never " -				  "was registered\n", dev->name, dev); +	list_for_each_entry(dev, head, unreg_list) { +		/* Some devices call without registering +		 * for initialization unwind. +		 */ +		if (dev->reg_state == NETREG_UNINITIALIZED) { +			pr_debug("unregister_netdevice: device %s/%p never " +				 "was registered\n", dev->name, dev); -		WARN_ON(1); -		return; -	} +			WARN_ON(1); +			return; +		} -	BUG_ON(dev->reg_state != NETREG_REGISTERED); +		BUG_ON(dev->reg_state != NETREG_REGISTERED); -	/* If device is running, close it first. */ -	dev_close(dev); +		/* If device is running, close it first. */ +		dev_close(dev); -	/* And unlink it from device chain. */ -	unlist_netdevice(dev); +		/* And unlink it from device chain. */ +		unlist_netdevice(dev); -	dev->reg_state = NETREG_UNREGISTERING; +		dev->reg_state = NETREG_UNREGISTERING; +	}  	synchronize_net(); -	/* Shutdown queueing discipline. */ -	dev_shutdown(dev); +	list_for_each_entry(dev, head, unreg_list) { +		/* Shutdown queueing discipline. */ +		dev_shutdown(dev); -	/* Notify protocols, that we are about to destroy -	   this device. They should clean all the things. -	*/ -	call_netdevice_notifiers(NETDEV_UNREGISTER, dev); +		/* Notify protocols, that we are about to destroy +		   this device. They should clean all the things. +		*/ +		call_netdevice_notifiers(NETDEV_UNREGISTER, dev); -	/* -	 *	Flush the unicast and multicast chains -	 */ -	dev_unicast_flush(dev); -	dev_addr_discard(dev); +		/* +		 *	Flush the unicast and multicast chains +		 */ +		dev_unicast_flush(dev); +		dev_addr_discard(dev); -	if (dev->netdev_ops->ndo_uninit) -		dev->netdev_ops->ndo_uninit(dev); +		if (dev->netdev_ops->ndo_uninit) +			dev->netdev_ops->ndo_uninit(dev); -	/* Notifier chain MUST detach us from master device. */ -	WARN_ON(dev->master); +		/* Notifier chain MUST detach us from master device. */ +		WARN_ON(dev->master); -	/* Remove entries from kobject tree */ -	netdev_unregister_kobject(dev); +		/* Remove entries from kobject tree */ +		netdev_unregister_kobject(dev); +	}  	synchronize_net(); -	dev_put(dev); +	list_for_each_entry(dev, head, unreg_list) +		dev_put(dev); +} + +static void rollback_registered(struct net_device *dev) +{ +	LIST_HEAD(single); + +	list_add(&dev->unreg_list, &single); +	rollback_registered_many(&single);  }  static 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)  EXPORT_SYMBOL(unregister_netdevice_queue);  /** + *	unregister_netdevice_many - unregister many devices + *	@head: list of devices + * + */ +void unregister_netdevice_many(struct list_head *head) +{ +	struct net_device *dev; + +	if (!list_empty(head)) { +		rollback_registered_many(head); +		list_for_each_entry(dev, head, unreg_list) +			net_set_todo(dev); +	} +} + +/**   *	unregister_netdev - remove device from the kernel   *	@dev: device   * | 
