Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

netdev: fix the locking for netdev notifications

Kuniyuki reports that the assert for netdev lock fires when
there are netdev event listeners (otherwise we skip the netlink
event generation).

Correct the locking when coming from the notifier.

The NETDEV_XDP_FEAT_CHANGE notifier is already fully locked,
it's the documentation that's incorrect.

Fixes: 99e44f39a8f7 ("netdev: depend on netdev->lock for xdp features")
Reported-by: syzkaller <syzkaller@googlegroups.com>
Reported-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Link: https://lore.kernel.org/20250410171019.62128-1-kuniyu@amazon.com
Acked-by: Stanislav Fomichev <sdf@fomichev.me>
Link: https://patch.msgid.link/20250416030447.1077551-1-kuba@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+27 -3
+3 -1
Documentation/networking/netdevices.rst
··· 387 387 some of the notifiers (``enum netdev_cmd``) are running under the netdev 388 388 instance lock. 389 389 390 + The following netdev notifiers are always run under the instance lock: 391 + * ``NETDEV_XDP_FEAT_CHANGE`` 392 + 390 393 For devices with locked ops, currently only the following notifiers are 391 394 running under the lock: 392 395 * ``NETDEV_CHANGE`` 393 396 * ``NETDEV_REGISTER`` 394 397 * ``NETDEV_UP`` 395 - * ``NETDEV_XDP_FEAT_CHANGE`` 396 398 397 399 The following notifiers are running without the lock: 398 400 * ``NETDEV_UNREGISTER``
+1 -1
include/linux/netdevice.h
··· 2520 2520 * @net_shaper_hierarchy, @reg_state, @threaded 2521 2521 * 2522 2522 * Double protects: 2523 - * @up, @moving_ns, @nd_net, @xdp_flags 2523 + * @up, @moving_ns, @nd_net, @xdp_features 2524 2524 * 2525 2525 * Double ops protects: 2526 2526 * @real_num_rx_queues, @real_num_tx_queues
+16
include/net/netdev_lock.h
··· 48 48 netdev_unlock(dev); 49 49 } 50 50 51 + static inline void netdev_lock_ops_to_full(struct net_device *dev) 52 + { 53 + if (netdev_need_ops_lock(dev)) 54 + netdev_assert_locked(dev); 55 + else 56 + netdev_lock(dev); 57 + } 58 + 59 + static inline void netdev_unlock_full_to_ops(struct net_device *dev) 60 + { 61 + if (netdev_need_ops_lock(dev)) 62 + netdev_assert_locked(dev); 63 + else 64 + netdev_unlock(dev); 65 + } 66 + 51 67 static inline void netdev_ops_assert_locked(const struct net_device *dev) 52 68 { 53 69 if (netdev_need_ops_lock(dev))
+3 -1
net/core/lock_debug.c
··· 18 18 19 19 /* Keep enum and don't add default to trigger -Werror=switch */ 20 20 switch (cmd) { 21 + case NETDEV_XDP_FEAT_CHANGE: 22 + netdev_assert_locked(dev); 23 + fallthrough; 21 24 case NETDEV_CHANGE: 22 25 case NETDEV_REGISTER: 23 26 case NETDEV_UP: 24 - case NETDEV_XDP_FEAT_CHANGE: 25 27 netdev_ops_assert_locked(dev); 26 28 fallthrough; 27 29 case NETDEV_DOWN:
+4
net/core/netdev-genl.c
··· 963 963 964 964 switch (event) { 965 965 case NETDEV_REGISTER: 966 + netdev_lock_ops_to_full(netdev); 966 967 netdev_genl_dev_notify(netdev, NETDEV_CMD_DEV_ADD_NTF); 968 + netdev_unlock_full_to_ops(netdev); 967 969 break; 968 970 case NETDEV_UNREGISTER: 971 + netdev_lock(netdev); 969 972 netdev_genl_dev_notify(netdev, NETDEV_CMD_DEV_DEL_NTF); 973 + netdev_unlock(netdev); 970 974 break; 971 975 case NETDEV_XDP_FEAT_CHANGE: 972 976 netdev_genl_dev_notify(netdev, NETDEV_CMD_DEV_CHANGE_NTF);