Skip to content

Commit

Permalink
net: revert RTNL changes in unregister_netdevice_many_notify()
Browse files Browse the repository at this point in the history
This patch reverts following changes:

83419b6 net: reduce RTNL hold duration in unregister_netdevice_many_notify() (part 2)
ae646f1 net: reduce RTNL hold duration in unregister_netdevice_many_notify() (part 1)
cfa579f 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: cfa579f ("net: no longer hold RTNL while calling flush_all_backlogs()")
Fixes: ae646f1 ("net: reduce RTNL hold duration in unregister_netdevice_many_notify() (part 1)")
Fixes: 83419b6 ("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>
  • Loading branch information
Eric Dumazet authored and Jakub Kicinski committed Jan 30, 2025
1 parent 0f5697f commit e759e1e
Showing 1 changed file with 3 additions and 30 deletions.
33 changes: 3 additions & 30 deletions net/core/dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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();

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit e759e1e

Please sign in to comment.