Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9b5e383c authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller
Browse files

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: default avatarEric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 44a0873d
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1119,6 +1119,7 @@ extern int dev_queue_xmit(struct sk_buff *skb);
extern int		register_netdevice(struct net_device *dev);
extern void		unregister_netdevice_queue(struct net_device *dev,
						   struct list_head *head);
extern void		unregister_netdevice_many(struct list_head *head);
static inline void unregister_netdevice(struct net_device *dev)
{
	unregister_netdevice_queue(dev, NULL);
+65 −32
Original line number Diff line number Diff line
@@ -4637,14 +4637,19 @@ 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. */
	list_for_each_entry(dev, head, unreg_list) {
		/* Some devices call without registering
		 * for initialization unwind.
		 */
		if (dev->reg_state == NETREG_UNINITIALIZED) {
		printk(KERN_DEBUG "unregister_netdevice: device %s/%p never "
			pr_debug("unregister_netdevice: device %s/%p never "
				 "was registered\n", dev->name, dev);

			WARN_ON(1);
@@ -4660,9 +4665,11 @@ static void rollback_registered(struct net_device *dev)
		unlist_netdevice(dev);

		dev->reg_state = NETREG_UNREGISTERING;
	}

	synchronize_net();

	list_for_each_entry(dev, head, unreg_list) {
		/* Shutdown queueing discipline. */
		dev_shutdown(dev);

@@ -4686,12 +4693,22 @@ static void rollback_registered(struct net_device *dev)

		/* Remove entries from kobject tree */
		netdev_unregister_kobject(dev);
	}

	synchronize_net();

	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,
					  struct netdev_queue *dev_queue,
					  void *_unused)
@@ -5271,6 +5288,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