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

net: make dev_unreg_count global



We can use a global dev_unreg_count counter instead
of a per netns one.

As a bonus we can factorize the changes done on it
for bulk device removals.

Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 45a96c40
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ extern int rtnl_lock_killable(void);
extern bool refcount_dec_and_rtnl_lock(refcount_t *r);

extern wait_queue_head_t netdev_unregistering_wq;
extern atomic_t dev_unreg_count;
extern struct rw_semaphore pernet_ops_rwsem;
extern struct rw_semaphore net_rwsem;

+0 −2
Original line number Diff line number Diff line
@@ -67,8 +67,6 @@ struct net {
						 */
	spinlock_t		rules_mod_lock;

	atomic_t		dev_unreg_count;

	unsigned int		dev_base_seq;	/* protected by rtnl_mutex */
	u32			ifindex;

+9 −3
Original line number Diff line number Diff line
@@ -9698,11 +9698,11 @@ static void dev_index_release(struct net *net, int ifindex)
/* Delayed registration/unregisteration */
LIST_HEAD(net_todo_list);
DECLARE_WAIT_QUEUE_HEAD(netdev_unregistering_wq);
atomic_t dev_unreg_count = ATOMIC_INIT(0);

static void net_set_todo(struct net_device *dev)
{
	list_add_tail(&dev->todo_list, &net_todo_list);
	atomic_inc(&dev_net(dev)->dev_unreg_count);
}

static netdev_features_t netdev_sync_upper_features(struct net_device *lower,
@@ -10529,6 +10529,7 @@ void netdev_run_todo(void)
{
	struct net_device *dev, *tmp;
	struct list_head list;
	int cnt;
#ifdef CONFIG_LOCKDEP
	struct list_head unlink_list;

@@ -10565,6 +10566,7 @@ void netdev_run_todo(void)
		linkwatch_sync_dev(dev);
	}

	cnt = 0;
	while (!list_empty(&list)) {
		dev = netdev_wait_allrefs_any(&list);
		list_del(&dev->todo_list);
@@ -10582,12 +10584,13 @@ void netdev_run_todo(void)
		if (dev->needs_free_netdev)
			free_netdev(dev);

		if (atomic_dec_and_test(&dev_net(dev)->dev_unreg_count))
			wake_up(&netdev_unregistering_wq);
		cnt++;

		/* Free network device */
		kobject_put(&dev->dev.kobj);
	}
	if (cnt && atomic_sub_and_test(cnt, &dev_unreg_count))
		wake_up(&netdev_unregistering_wq);
}

/* Convert net_device_stats to rtnl_link_stats64. rtnl_link_stats64 has
@@ -11034,6 +11037,7 @@ void unregister_netdevice_many_notify(struct list_head *head,
{
	struct net_device *dev, *tmp;
	LIST_HEAD(close_head);
	int cnt = 0;

	BUG_ON(dev_boot_phase);
	ASSERT_RTNL();
@@ -11130,7 +11134,9 @@ void unregister_netdevice_many_notify(struct list_head *head,
	list_for_each_entry(dev, head, unreg_list) {
		netdev_put(dev, &dev->dev_registered_tracker);
		net_set_todo(dev);
		cnt++;
	}
	atomic_add(cnt, &dev_unreg_count);

	list_del(head);
}
+1 −10
Original line number Diff line number Diff line
@@ -483,24 +483,15 @@ EXPORT_SYMBOL_GPL(__rtnl_link_unregister);
 */
static void rtnl_lock_unregistering_all(void)
{
	struct net *net;
	bool unregistering;
	DEFINE_WAIT_FUNC(wait, woken_wake_function);

	add_wait_queue(&netdev_unregistering_wq, &wait);
	for (;;) {
		unregistering = false;
		rtnl_lock();
		/* We held write locked pernet_ops_rwsem, and parallel
		 * setup_net() and cleanup_net() are not possible.
		 */
		for_each_net(net) {
			if (atomic_read(&net->dev_unreg_count) > 0) {
				unregistering = true;
				break;
			}
		}
		if (!unregistering)
		if (!atomic_read(&dev_unreg_count))
			break;
		__rtnl_unlock();