Commit e759e1e4 authored by Eric Dumazet's avatar Eric Dumazet Committed by Jakub Kicinski
Browse files

net: revert RTNL changes in unregister_netdevice_many_notify()



This patch reverts following changes:

83419b61 net: reduce RTNL hold duration in unregister_netdevice_many_notify() (part 2)
ae646f1a net: reduce RTNL hold duration in unregister_netdevice_many_notify() (part 1)
cfa579f6 net: no longer hold RTNL while calling flush_all_backlogs()

This caused issues in layers holding a private mutex:

cleanup_net()
  rtnl_lock();
	mutex_lock(subsystem_mutex);

	unregister_netdevice();

	   rtnl_unlock();		// LOCKDEP violation
	   rtnl_lock();

I will revisit this in next cycle, opt-in for the new behavior
from safe contexts only.

Fixes: cfa579f6 ("net: no longer hold RTNL while calling flush_all_backlogs()")
Fixes: ae646f1a ("net: reduce RTNL hold duration in unregister_netdevice_many_notify() (part 1)")
Fixes: 83419b61 ("net: reduce RTNL hold duration in unregister_netdevice_many_notify() (part 2)")
Reported-by: default avatar <syzbot+5b9196ecf74447172a9a@syzkaller.appspotmail.com>
Closes: https://lore.kernel.org/netdev/6789d55f.050a0220.20d369.004e.GAE@google.com/


Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Reviewed-by: default avatarKuniyuki Iwashima <kuniyu@amazon.com>
Link: https://patch.msgid.link/20250129142726.747726-1-edumazet@google.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 0f5697f1
Loading
Loading
Loading
Loading
+3 −30
Original line number Diff line number Diff line
@@ -10264,37 +10264,14 @@ static bool from_cleanup_net(void)
#endif
}

static void rtnl_drop_if_cleanup_net(void)
{
	if (from_cleanup_net())
		__rtnl_unlock();
}

static void rtnl_acquire_if_cleanup_net(void)
{
	if (from_cleanup_net())
		rtnl_lock();
}

/* Delayed registration/unregisteration */
LIST_HEAD(net_todo_list);
static LIST_HEAD(net_todo_list_for_cleanup_net);

/* TODO: net_todo_list/net_todo_list_for_cleanup_net should probably
 * be provided by callers, instead of being static, rtnl protected.
 */
static struct list_head *todo_list(void)
{
	return from_cleanup_net() ? &net_todo_list_for_cleanup_net :
				    &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, todo_list());
	list_add_tail(&dev->todo_list, &net_todo_list);
}

static netdev_features_t netdev_sync_upper_features(struct net_device *lower,
@@ -11144,7 +11121,7 @@ void netdev_run_todo(void)
#endif

	/* Snapshot list, allow later requests */
	list_replace_init(todo_list(), &list);
	list_replace_init(&net_todo_list, &list);

	__rtnl_unlock();

@@ -11789,11 +11766,9 @@ void unregister_netdevice_many_notify(struct list_head *head,
		WRITE_ONCE(dev->reg_state, NETREG_UNREGISTERING);
		netdev_unlock(dev);
	}

	rtnl_drop_if_cleanup_net();
	flush_all_backlogs();

	synchronize_net();
	rtnl_acquire_if_cleanup_net();

	list_for_each_entry(dev, head, unreg_list) {
		struct sk_buff *skb = NULL;
@@ -11853,9 +11828,7 @@ void unregister_netdevice_many_notify(struct list_head *head,
#endif
	}

	rtnl_drop_if_cleanup_net();
	synchronize_net();
	rtnl_acquire_if_cleanup_net();

	list_for_each_entry(dev, head, unreg_list) {
		netdev_put(dev, &dev->dev_registered_tracker);