Skip to content

Commit 5fda3f3

Browse files
committed
net: make netdev_lock() protect netdev->reg_state
Protect writes to netdev->reg_state with netdev_lock(). From now on holding netdev_lock() is sufficient to prevent the net_device from getting unregistered, so code which wants to hold just a single netdev around no longer needs to hold rtnl_lock. We do not protect the NETREG_UNREGISTERED -> NETREG_RELEASED transition. We'd need to move mutex_destroy(netdev->lock) to .release, but the real reason is that trying to stop the unregistration process mid-way would be unsafe / crazy. Taking references on such devices is not safe, either. So the intended semantics are to lock REGISTERED devices. Reviewed-by: Joe Damato <[email protected]> Reviewed-by: Eric Dumazet <[email protected]> Reviewed-by: Kuniyuki Iwashima <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent ebda2f0 commit 5fda3f3

File tree

2 files changed

+7
-1
lines changed

2 files changed

+7
-1
lines changed

include/linux/netdevice.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2448,7 +2448,7 @@ struct net_device {
24482448
* Should always be taken using netdev_lock() / netdev_unlock() helpers.
24492449
* Drivers are free to use it for other protection.
24502450
*
2451-
* Protects: @net_shaper_hierarchy.
2451+
* Protects: @reg_state, @net_shaper_hierarchy.
24522452
* Ordering: take after rtnl_lock.
24532453
*/
24542454
struct mutex lock;

net/core/dev.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10695,7 +10695,9 @@ int register_netdevice(struct net_device *dev)
1069510695

1069610696
ret = netdev_register_kobject(dev);
1069710697

10698+
netdev_lock(dev);
1069810699
WRITE_ONCE(dev->reg_state, ret ? NETREG_UNREGISTERED : NETREG_REGISTERED);
10700+
netdev_unlock(dev);
1069910701

1070010702
if (ret)
1070110703
goto err_uninit_notify;
@@ -10969,7 +10971,9 @@ void netdev_run_todo(void)
1096910971
continue;
1097010972
}
1097110973

10974+
netdev_lock(dev);
1097210975
WRITE_ONCE(dev->reg_state, NETREG_UNREGISTERED);
10976+
netdev_unlock(dev);
1097310977
linkwatch_sync_dev(dev);
1097410978
}
1097510979

@@ -11575,7 +11579,9 @@ void unregister_netdevice_many_notify(struct list_head *head,
1157511579
list_for_each_entry(dev, head, unreg_list) {
1157611580
/* And unlink it from device chain. */
1157711581
unlist_netdevice(dev);
11582+
netdev_lock(dev);
1157811583
WRITE_ONCE(dev->reg_state, NETREG_UNREGISTERING);
11584+
netdev_unlock(dev);
1157911585
}
1158011586
flush_all_backlogs();
1158111587

0 commit comments

Comments
 (0)