]> www.infradead.org Git - users/hch/misc.git/commitdiff
net: revert RTNL changes in unregister_netdevice_many_notify()
authorEric Dumazet <edumazet@google.com>
Wed, 29 Jan 2025 14:27:26 +0000 (14:27 +0000)
committerJakub Kicinski <kuba@kernel.org>
Thu, 30 Jan 2025 16:57:18 +0000 (08:57 -0800)
This patch reverts following changes:

83419b61d187 net: reduce RTNL hold duration in unregister_netdevice_many_notify() (part 2)
ae646f1a0bb9 net: reduce RTNL hold duration in unregister_netdevice_many_notify() (part 1)
cfa579f66656 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: cfa579f66656 ("net: no longer hold RTNL while calling flush_all_backlogs()")
Fixes: ae646f1a0bb9 ("net: reduce RTNL hold duration in unregister_netdevice_many_notify() (part 1)")
Fixes: 83419b61d187 ("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>
net/core/dev.c

index 02cd75b512f9277b2cdfabd51bca056b2ee69639..c0021cbd28fc11e4c4eb6184d98a2505fa674871 100644 (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);