1
0

net: revert RTNL changes in unregister_netdevice_many_notify()

This patch reverts following changes:

83419b61d1 net: reduce RTNL hold duration in unregister_netdevice_many_notify() (part 2)
ae646f1a0b net: reduce RTNL hold duration in unregister_netdevice_many_notify() (part 1)
cfa579f666 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: cfa579f666 ("net: no longer hold RTNL while calling flush_all_backlogs()")
Fixes: ae646f1a0b ("net: reduce RTNL hold duration in unregister_netdevice_many_notify() (part 1)")
Fixes: 83419b61d1 ("net: reduce RTNL hold duration in unregister_netdevice_many_notify() (part 2)")
Reported-by: syzbot+5b9196ecf74447172a9a@syzkaller.appspotmail.com
Closes: https://lore.kernel.org/netdev/6789d55f.050a0220.20d369.004e.GAE@google.com/
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Link: https://patch.msgid.link/20250129142726.747726-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Eric Dumazet
2025-01-29 14:27:26 +00:00
committed by Jakub Kicinski
parent 0f5697f1a3
commit e759e1e4a4

View File

@@ -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);