Skip to content

Commit 8ea7c1b

Browse files
committed
Merge branch 'net-hold-instance-lock-during-netdev_up-register'
Stanislav Fomichev says: ==================== net: hold instance lock during NETDEV_UP/REGISTER Solving the issue reported by Cosmin in [0] requires consistent lock during NETDEV_UP/REGISTER notifiers. This series addresses that (along with some other fixes in net/ipv4/devinet.c and net/ipv6/addrconf.c) and appends the patches from Jakub that were conditional on consistent locking in NETDEV_UNREGISTER. 0: https://lore.kernel.org/700fa36b94cbd57cfea2622029b087643c80cbc9.camel@nvidia.com ==================== Link: https://patch.msgid.link/20250401163452.622454-1-sdf@fomichev.me Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2 parents 09bccf5 + 56c8a23 commit 8ea7c1b

File tree

16 files changed

+125
-36
lines changed

16 files changed

+125
-36
lines changed

Documentation/networking/netdevices.rst

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,29 @@ there are two sets of interfaces: ``dev_xxx`` and ``netif_xxx`` (e.g.,
343343
acquiring the instance lock themselves, while the ``netif_xxx`` functions
344344
assume that the driver has already acquired the instance lock.
345345

346+
Notifiers and netdev instance lock
347+
==================================
348+
349+
For device drivers that implement shaping or queue management APIs,
350+
some of the notifiers (``enum netdev_cmd``) are running under the netdev
351+
instance lock.
352+
353+
For devices with locked ops, currently only the following notifiers are
354+
running under the lock:
355+
* ``NETDEV_REGISTER``
356+
* ``NETDEV_UP``
357+
358+
The following notifiers are running without the lock:
359+
* ``NETDEV_UNREGISTER``
360+
361+
There are no clear expectations for the remaining notifiers. Notifiers not on
362+
the list may run with or without the instance lock, potentially even invoking
363+
the same notifier type with and without the lock from different code paths.
364+
The goal is to eventually ensure that all (or most, with a few documented
365+
exceptions) notifiers run under the instance lock. Please extend this
366+
documentation whenever you make explicit assumption about lock being held
367+
from a notifier.
368+
346369
NETDEV_INTERNAL symbol namespace
347370
================================
348371

drivers/net/dummy.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ static void dummy_setup(struct net_device *dev)
105105
dev->netdev_ops = &dummy_netdev_ops;
106106
dev->ethtool_ops = &dummy_ethtool_ops;
107107
dev->needs_free_netdev = true;
108+
dev->request_ops_lock = true;
108109

109110
/* Fill in device structure with ethernet-generic values. */
110111
dev->flags |= IFF_NOARP;

drivers/net/netdevsim/netdev.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -939,6 +939,7 @@ static int nsim_init_netdevsim(struct netdevsim *ns)
939939
ns->netdev->netdev_ops = &nsim_netdev_ops;
940940
ns->netdev->stat_ops = &nsim_stat_ops;
941941
ns->netdev->queue_mgmt_ops = &nsim_queue_mgmt_ops;
942+
netdev_lockdep_set_classes(ns->netdev);
942943

943944
err = nsim_udp_tunnels_info_create(ns->nsim_dev, ns->netdev);
944945
if (err)
@@ -960,6 +961,14 @@ static int nsim_init_netdevsim(struct netdevsim *ns)
960961
if (err)
961962
goto err_ipsec_teardown;
962963
rtnl_unlock();
964+
965+
if (IS_ENABLED(CONFIG_DEBUG_NET)) {
966+
ns->nb.notifier_call = netdev_debug_event;
967+
if (register_netdevice_notifier_dev_net(ns->netdev, &ns->nb,
968+
&ns->nn))
969+
ns->nb.notifier_call = NULL;
970+
}
971+
963972
return 0;
964973

965974
err_ipsec_teardown:
@@ -1043,6 +1052,10 @@ void nsim_destroy(struct netdevsim *ns)
10431052
debugfs_remove(ns->qr_dfs);
10441053
debugfs_remove(ns->pp_dfs);
10451054

1055+
if (ns->nb.notifier_call)
1056+
unregister_netdevice_notifier_dev_net(ns->netdev, &ns->nb,
1057+
&ns->nn);
1058+
10461059
rtnl_lock();
10471060
peer = rtnl_dereference(ns->peer);
10481061
if (peer)

drivers/net/netdevsim/netdevsim.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,9 @@ struct netdevsim {
144144

145145
struct nsim_ethtool ethtool;
146146
struct netdevsim __rcu *peer;
147+
148+
struct notifier_block nb;
149+
struct netdev_net_notifier nn;
147150
};
148151

149152
struct netdevsim *

include/linux/netdevice.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4192,7 +4192,7 @@ int dev_change_flags(struct net_device *dev, unsigned int flags,
41924192
int netif_set_alias(struct net_device *dev, const char *alias, size_t len);
41934193
int dev_set_alias(struct net_device *, const char *, size_t);
41944194
int dev_get_alias(const struct net_device *, char *, size_t);
4195-
int netif_change_net_namespace(struct net_device *dev, struct net *net,
4195+
int __dev_change_net_namespace(struct net_device *dev, struct net *net,
41964196
const char *pat, int new_ifindex,
41974197
struct netlink_ext_ack *extack);
41984198
int dev_change_net_namespace(struct net_device *dev, struct net *net,

include/net/ip.h

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -667,14 +667,6 @@ static inline void ip_ipgre_mc_map(__be32 naddr, const unsigned char *broadcast,
667667
memcpy(buf, &naddr, sizeof(naddr));
668668
}
669669

670-
#if IS_MODULE(CONFIG_IPV6)
671-
#define EXPORT_IPV6_MOD(X) EXPORT_SYMBOL(X)
672-
#define EXPORT_IPV6_MOD_GPL(X) EXPORT_SYMBOL_GPL(X)
673-
#else
674-
#define EXPORT_IPV6_MOD(X)
675-
#define EXPORT_IPV6_MOD_GPL(X)
676-
#endif
677-
678670
#if IS_ENABLED(CONFIG_IPV6)
679671
#include <linux/ipv6.h>
680672
#endif
@@ -694,6 +686,14 @@ static __inline__ void inet_reset_saddr(struct sock *sk)
694686

695687
#endif
696688

689+
#if IS_MODULE(CONFIG_IPV6)
690+
#define EXPORT_IPV6_MOD(X) EXPORT_SYMBOL(X)
691+
#define EXPORT_IPV6_MOD_GPL(X) EXPORT_SYMBOL_GPL(X)
692+
#else
693+
#define EXPORT_IPV6_MOD(X)
694+
#define EXPORT_IPV6_MOD_GPL(X)
695+
#endif
696+
697697
static inline unsigned int ipv4_addr_hash(__be32 ip)
698698
{
699699
return (__force unsigned int) ip;

include/net/netdev_lock.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,4 +98,7 @@ static inline int netdev_lock_cmp_fn(const struct lockdep_map *a,
9898
&qdisc_xmit_lock_key); \
9999
}
100100

101+
int netdev_debug_event(struct notifier_block *nb, unsigned long event,
102+
void *ptr);
103+
101104
#endif

net/core/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,5 +45,5 @@ obj-$(CONFIG_BPF_SYSCALL) += bpf_sk_storage.o
4545
obj-$(CONFIG_OF) += of_net.o
4646
obj-$(CONFIG_NET_TEST) += net_test.o
4747
obj-$(CONFIG_NET_DEVMEM) += devmem.o
48-
obj-$(CONFIG_DEBUG_NET_SMALL_RTNL) += rtnl_net_debug.o
48+
obj-$(CONFIG_DEBUG_NET) += lock_debug.o
4949
obj-$(CONFIG_FAIL_SKB_REALLOC) += skb_fault_injection.o

net/core/dev.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1771,6 +1771,7 @@ void netif_disable_lro(struct net_device *dev)
17711771
netdev_unlock_ops(lower_dev);
17721772
}
17731773
}
1774+
EXPORT_IPV6_MOD(netif_disable_lro);
17741775

17751776
/**
17761777
* dev_disable_gro_hw - disable HW Generic Receive Offload on a device
@@ -1858,7 +1859,9 @@ static int call_netdevice_register_net_notifiers(struct notifier_block *nb,
18581859
int err;
18591860

18601861
for_each_netdev(net, dev) {
1862+
netdev_lock_ops(dev);
18611863
err = call_netdevice_register_notifiers(nb, dev);
1864+
netdev_unlock_ops(dev);
18621865
if (err)
18631866
goto rollback;
18641867
}
@@ -11047,7 +11050,9 @@ int register_netdevice(struct net_device *dev)
1104711050
memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
1104811051

1104911052
/* Notify protocols, that a new device appeared. */
11053+
netdev_lock_ops(dev);
1105011054
ret = call_netdevice_notifiers(NETDEV_REGISTER, dev);
11055+
netdev_unlock_ops(dev);
1105111056
ret = notifier_to_errno(ret);
1105211057
if (ret) {
1105311058
/* Expect explicit free_netdev() on failure */
@@ -12059,7 +12064,7 @@ void unregister_netdev(struct net_device *dev)
1205912064
}
1206012065
EXPORT_SYMBOL(unregister_netdev);
1206112066

12062-
int netif_change_net_namespace(struct net_device *dev, struct net *net,
12067+
int __dev_change_net_namespace(struct net_device *dev, struct net *net,
1206312068
const char *pat, int new_ifindex,
1206412069
struct netlink_ext_ack *extack)
1206512070
{
@@ -12144,11 +12149,12 @@ int netif_change_net_namespace(struct net_device *dev, struct net *net,
1214412149
* And now a mini version of register_netdevice unregister_netdevice.
1214512150
*/
1214612151

12152+
netdev_lock_ops(dev);
1214712153
/* If device is running close it first. */
1214812154
netif_close(dev);
12149-
1215012155
/* And unlink it from device chain */
1215112156
unlist_netdevice(dev);
12157+
netdev_unlock_ops(dev);
1215212158

1215312159
synchronize_net();
1215412160

@@ -12210,11 +12216,12 @@ int netif_change_net_namespace(struct net_device *dev, struct net *net,
1221012216
err = netdev_change_owner(dev, net_old, net);
1221112217
WARN_ON(err);
1221212218

12219+
netdev_lock_ops(dev);
1221312220
/* Add the device back in the hashes */
1221412221
list_netdevice(dev);
12215-
1221612222
/* Notify protocols, that a new device appeared. */
1221712223
call_netdevice_notifiers(NETDEV_REGISTER, dev);
12224+
netdev_unlock_ops(dev);
1221812225

1221912226
/*
1222012227
* Prevent userspace races by waiting until the network

net/core/dev_api.c

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -117,13 +117,7 @@ EXPORT_SYMBOL(dev_set_mac_address_user);
117117
int dev_change_net_namespace(struct net_device *dev, struct net *net,
118118
const char *pat)
119119
{
120-
int ret;
121-
122-
netdev_lock_ops(dev);
123-
ret = netif_change_net_namespace(dev, net, pat, 0, NULL);
124-
netdev_unlock_ops(dev);
125-
126-
return ret;
120+
return __dev_change_net_namespace(dev, net, pat, 0, NULL);
127121
}
128122
EXPORT_SYMBOL_GPL(dev_change_net_namespace);
129123

0 commit comments

Comments
 (0)