Commit 8ea7c1b3 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

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: default avatarJakub Kicinski <kuba@kernel.org>
parents 09bccf56 56c8a23f
Loading
Loading
Loading
Loading
+23 −0
Original line number Diff line number Diff line
@@ -343,6 +343,29 @@ there are two sets of interfaces: ``dev_xxx`` and ``netif_xxx`` (e.g.,
acquiring the instance lock themselves, while the ``netif_xxx`` functions
assume that the driver has already acquired the instance lock.

Notifiers and netdev instance lock
==================================

For device drivers that implement shaping or queue management APIs,
some of the notifiers (``enum netdev_cmd``) are running under the netdev
instance lock.

For devices with locked ops, currently only the following notifiers are
running under the lock:
* ``NETDEV_REGISTER``
* ``NETDEV_UP``

The following notifiers are running without the lock:
* ``NETDEV_UNREGISTER``

There are no clear expectations for the remaining notifiers. Notifiers not on
the list may run with or without the instance lock, potentially even invoking
the same notifier type with and without the lock from different code paths.
The goal is to eventually ensure that all (or most, with a few documented
exceptions) notifiers run under the instance lock. Please extend this
documentation whenever you make explicit assumption about lock being held
from a notifier.

NETDEV_INTERNAL symbol namespace
================================

+1 −0
Original line number Diff line number Diff line
@@ -105,6 +105,7 @@ static void dummy_setup(struct net_device *dev)
	dev->netdev_ops = &dummy_netdev_ops;
	dev->ethtool_ops = &dummy_ethtool_ops;
	dev->needs_free_netdev = true;
	dev->request_ops_lock = true;

	/* Fill in device structure with ethernet-generic values. */
	dev->flags |= IFF_NOARP;
+13 −0
Original line number Diff line number Diff line
@@ -939,6 +939,7 @@ static int nsim_init_netdevsim(struct netdevsim *ns)
	ns->netdev->netdev_ops = &nsim_netdev_ops;
	ns->netdev->stat_ops = &nsim_stat_ops;
	ns->netdev->queue_mgmt_ops = &nsim_queue_mgmt_ops;
	netdev_lockdep_set_classes(ns->netdev);

	err = nsim_udp_tunnels_info_create(ns->nsim_dev, ns->netdev);
	if (err)
@@ -960,6 +961,14 @@ static int nsim_init_netdevsim(struct netdevsim *ns)
	if (err)
		goto err_ipsec_teardown;
	rtnl_unlock();

	if (IS_ENABLED(CONFIG_DEBUG_NET)) {
		ns->nb.notifier_call = netdev_debug_event;
		if (register_netdevice_notifier_dev_net(ns->netdev, &ns->nb,
							&ns->nn))
			ns->nb.notifier_call = NULL;
	}

	return 0;

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

	if (ns->nb.notifier_call)
		unregister_netdevice_notifier_dev_net(ns->netdev, &ns->nb,
						      &ns->nn);

	rtnl_lock();
	peer = rtnl_dereference(ns->peer);
	if (peer)
+3 −0
Original line number Diff line number Diff line
@@ -144,6 +144,9 @@ struct netdevsim {

	struct nsim_ethtool ethtool;
	struct netdevsim __rcu *peer;

	struct notifier_block nb;
	struct netdev_net_notifier nn;
};

struct netdevsim *
+1 −1
Original line number Diff line number Diff line
@@ -4192,7 +4192,7 @@ int dev_change_flags(struct net_device *dev, unsigned int flags,
int netif_set_alias(struct net_device *dev, const char *alias, size_t len);
int dev_set_alias(struct net_device *, const char *, size_t);
int dev_get_alias(const struct net_device *, char *, size_t);
int netif_change_net_namespace(struct net_device *dev, struct net *net,
int __dev_change_net_namespace(struct net_device *dev, struct net *net,
			       const char *pat, int new_ifindex,
			       struct netlink_ext_ack *extack);
int dev_change_net_namespace(struct net_device *dev, struct net *net,
Loading