net: revert RTNL changes in unregister_netdevice_many_notify()
This patch reverts following changes:83419b61d1net: reduce RTNL hold duration in unregister_netdevice_many_notify() (part 2)ae646f1a0bnet: reduce RTNL hold duration in unregister_netdevice_many_notify() (part 1)cfa579f666net: 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:
committed by
Jakub Kicinski
parent
0f5697f1a3
commit
e759e1e4a4
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user