mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Kirill Tkhai <tkhai@ya.ru>
To: netdev@vger.kernel.org, linux-kernel@vger.kernel.org
Cc: tkhai@ya.ru
Subject: [PATCH NET-PREV 08/51] net: Initially attaching and detaching nd_lock
Date: Sat, 22 Mar 2025 17:38:54 +0300	[thread overview]
Message-ID: <174265433421.356712.3881511284479009706.stgit@pro.pro> (raw)
In-Reply-To: <174265415457.356712.10472727127735290090.stgit@pro.pro>

To start convertation devices one by one, we need
defaults assigned to rest of devices.

Here we add default lock assignment and a branch
for already converted drivers in register_netdevice.

Signed-off-by: Kirill Tkhai <tkhai@ya.ru>
---
 include/linux/netdevice.h |    8 +++
 net/core/dev.c            |  127 +++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 123 insertions(+), 12 deletions(-)

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index e36e64310bd4..2e9052e808a4 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -3122,14 +3122,22 @@ extern struct nd_lock fallback_nd_lock;
 
 void nd_lock_transfer_devices(struct nd_lock **p_lock, struct nd_lock **p_lock2);
 
+int __register_netdevice(struct net_device *dev);
 int register_netdevice(struct net_device *dev);
 void unregister_netdevice_queue(struct net_device *dev, struct list_head *head);
 void unregister_netdevice_many(struct list_head *head);
+/* XXX: This will be converted to take nd_lock after drivers are ready */
 static inline void unregister_netdevice(struct net_device *dev)
 {
 	unregister_netdevice_queue(dev, NULL);
 }
 
+/* XXX: This will be used in places, where nd_lock is already taken */
+static inline void __unregister_netdevice(struct net_device *dev)
+{
+	unregister_netdevice_queue(dev, NULL);
+}
+
 int netdev_refcnt_read(const struct net_device *dev);
 void free_netdev(struct net_device *dev);
 void init_dummy_netdev(struct net_device *dev);
diff --git a/net/core/dev.c b/net/core/dev.c
index 9d98ab1e76bd..63ece39c9286 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -10651,7 +10651,7 @@ struct nd_lock *attach_new_nd_lock(struct net_device *dev)
 EXPORT_SYMBOL(attach_new_nd_lock);
 
 /**
- * register_netdevice() - register a network device
+ * __register_netdevice() - register a network device
  * @dev: device to register
  *
  * Take a prepared network device structure and make it externally accessible.
@@ -10659,7 +10659,7 @@ EXPORT_SYMBOL(attach_new_nd_lock);
  * Callers must hold the rtnl lock - you may want register_netdev()
  * instead of this.
  */
-int register_netdevice(struct net_device *dev)
+int __register_netdevice(struct net_device *dev)
 {
 	int ret;
 	struct net *net = dev_net(dev);
@@ -10675,6 +10675,9 @@ int register_netdevice(struct net_device *dev)
 	BUG_ON(dev->reg_state != NETREG_UNINITIALIZED);
 	BUG_ON(!net);
 
+	if (WARN_ON(!rcu_access_pointer(dev->nd_lock)))
+		return -ENOLCK;
+
 	ret = ethtool_check_ops(dev->ethtool_ops);
 	if (ret)
 		return ret;
@@ -10837,6 +10840,40 @@ int register_netdevice(struct net_device *dev)
 	netdev_name_node_free(dev->name_node);
 	goto out;
 }
+EXPORT_SYMBOL(__register_netdevice);
+
+int register_netdevice(struct net_device *dev)
+{
+	struct nd_lock *nd_lock;
+	int err;
+
+	/* XXX: This "if" is to start one by one convertation
+	 * to use __register_netdevice() in devices, that
+	 * want to attach nd_lock themself (e.g., having newlink).
+	 * After all of them are converted, we remove this.
+	 */
+	if (rcu_access_pointer(dev->nd_lock))
+		return __register_netdevice(dev);
+
+	nd_lock = alloc_nd_lock();
+	if (!nd_lock)
+		return -ENOMEM;
+
+	/* This may be called from netdevice notifier, which is not converted
+	 * yet. The context is unknown: either some nd_lock is locked or not.
+	 * Sometimes here is nested mutex and sometimes is not. We use trylock
+	 * to silence lockdep assert about that.
+	 * It will be replaced by mutex_lock(), see next patches.
+	 */
+	BUG_ON(!mutex_trylock(&nd_lock->mutex));
+	attach_nd_lock(dev, nd_lock);
+	err = __register_netdevice(dev);
+	if (err)
+		detach_nd_lock(dev);
+	mutex_unlock(&nd_lock->mutex);
+	put_nd_lock(nd_lock);
+	return err;
+}
 EXPORT_SYMBOL(register_netdevice);
 
 /* Initialize the core of a dummy net device.
@@ -10907,7 +10944,23 @@ int register_netdev(struct net_device *dev)
 
 	if (rtnl_lock_killable())
 		return -EINTR;
-	err = register_netdevice(dev);
+
+	/* Since this function is called without rtnl_lock(),
+	 * nested registration is not possible here (compare
+	 * to .newlink). So it's not interesting for us as
+	 * much as register_netdevice(). Here are possible some
+	 * real cross-device links between devices related
+	 * to specific driver family, and they are handled by
+	 * using fallback_nd_lock for all devices.
+	 * Also, see comment in nd_lock_transfer_devices().
+	 */
+	mutex_lock(&fallback_nd_lock.mutex);
+	attach_nd_lock(dev, &fallback_nd_lock);
+	err = __register_netdevice(dev);
+	if (err)
+		detach_nd_lock(dev);
+	mutex_unlock(&fallback_nd_lock.mutex);
+
 	rtnl_unlock();
 	return err;
 }
@@ -11474,6 +11527,54 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
 }
 EXPORT_SYMBOL(alloc_netdev_mqs);
 
+static DEFINE_SPINLOCK(put_lock);
+static LIST_HEAD(put_list);
+
+static void put_work_func(struct work_struct *unused)
+{
+	struct nd_lock *nd_lock;
+	struct net_device *dev;
+	LIST_HEAD(list);
+
+	spin_lock(&put_lock);
+	list_replace_init(&put_list, &list);
+	spin_unlock(&put_lock);
+
+	while (!list_empty(&list)) {
+		dev = list_first_entry(&list,
+				       struct net_device,
+				       todo_list);
+		list_del_init(&dev->todo_list);
+
+		/* XXX: this nd_lock finaly should be held during
+		 * the whole unregistering. Since not all of devices
+		 * are converted yet, we place the detach_nd_lock here
+		 * to be able to start attaching nd_lock to every device
+		 * one by one in separate patches of this series.
+		 * Then, it will be moved to callers (unregister_netdevice()
+		 * and others).
+		 *
+		 * Note, we can't place the below to free_netdev(), because
+		 * of free_netdev() currently may be called locked and unlocked
+		 * from different callers.
+		 *
+		 * Also note, that lock may be detached here in case of
+		 * this is cleanup after failed __register_netdevice().
+		 */
+		if (lock_netdev(dev, &nd_lock)) {
+			detach_nd_lock(dev);
+			unlock_netdev(nd_lock);
+		}
+
+		if (dev->reg_state == NETREG_RELEASED)
+			put_device(&dev->dev); /* free via device release */
+		else /* Compatibility with error handling in drivers */
+			kvfree(dev);
+	}
+}
+
+static DECLARE_WORK(put_work, put_work_func);
+
 /**
  * free_netdev - free network device
  * @dev: device
@@ -11486,6 +11587,7 @@ EXPORT_SYMBOL(alloc_netdev_mqs);
 void free_netdev(struct net_device *dev)
 {
 	struct napi_struct *p, *n;
+	bool work;
 
 	might_sleep();
 
@@ -11521,18 +11623,19 @@ void free_netdev(struct net_device *dev)
 	free_percpu(dev->xdp_bulkq);
 	dev->xdp_bulkq = NULL;
 
-	/*  Compatibility with error handling in drivers */
-	if (dev->reg_state == NETREG_UNINITIALIZED ||
-	    dev->reg_state == NETREG_DUMMY) {
-		kvfree(dev);
-		return;
+	if (dev->reg_state != NETREG_UNINITIALIZED &&
+	    dev->reg_state != NETREG_DUMMY) {
+		BUG_ON(dev->reg_state != NETREG_UNREGISTERED);
+		WRITE_ONCE(dev->reg_state, NETREG_RELEASED);
 	}
 
-	BUG_ON(dev->reg_state != NETREG_UNREGISTERED);
-	WRITE_ONCE(dev->reg_state, NETREG_RELEASED);
+	spin_lock(&put_lock);
+	list_add_tail(&dev->todo_list, &put_list);
+	work = list_is_singular(&put_list);
+	spin_unlock(&put_lock);
 
-	/* will free via device release */
-	put_device(&dev->dev);
+	if (work)
+		schedule_work(&put_work);
 }
 EXPORT_SYMBOL(free_netdev);
 


  parent reply	other threads:[~2025-03-22 14:38 UTC|newest]

Thread overview: 54+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-03-22 14:37 [PATCH NET-PREV 00/51] Kill rtnl_lock using fine-grained nd_lock Kirill Tkhai
2025-03-22 14:37 ` [PATCH NET-PREV 01/51] net: Move some checks from __rtnl_newlink() to caller Kirill Tkhai
2025-03-22 14:38 ` [PATCH NET-PREV 02/51] net: Add nlaattr check to rtnl_link_get_net_capable() Kirill Tkhai
2025-03-22 14:38 ` [PATCH NET-PREV 03/51] net: do_setlink() refactoring: move target_net acquiring to callers Kirill Tkhai
2025-03-22 14:38 ` [PATCH NET-PREV 04/51] net: Extract some code from __rtnl_newlink() to separate func Kirill Tkhai
2025-03-22 14:38 ` [PATCH NET-PREV 05/51] net: Move dereference of tb[IFLA_MASTER] up Kirill Tkhai
2025-03-22 14:38 ` [PATCH NET-PREV 06/51] net: Use unregister_netdevice_many() for both error cases in rtnl_newlink_create() Kirill Tkhai
2025-03-22 14:38 ` [PATCH NET-PREV 07/51] net: Introduce nd_lock and primitives to work with it Kirill Tkhai
2025-03-22 14:38 ` Kirill Tkhai [this message]
2025-03-22 14:39 ` [PATCH NET-PREV 09/51] net: Use register_netdevice() in loopback() Kirill Tkhai
2025-03-22 14:39 ` [PATCH NET-PREV 10/51] net: Underline newlink and changelink dependencies Kirill Tkhai
2025-03-22 14:39 ` [PATCH NET-PREV 11/51] net: Make master and slaves (any dependent devices) share the same nd_lock in .setlink etc Kirill Tkhai
2025-03-22 14:39 ` [PATCH NET-PREV 12/51] net: Use __register_netdevice in trivial .newlink cases Kirill Tkhai
2025-03-22 14:39 ` [PATCH NET-PREV 13/51] infiniband_ipoib: Use __register_netdevice in .newlink Kirill Tkhai
2025-03-22 14:39 ` [PATCH NET-PREV 14/51] vxcan: " Kirill Tkhai
2025-03-22 14:39 ` [PATCH NET-PREV 15/51] iavf: Use __register_netdevice() Kirill Tkhai
2025-03-22 14:39 ` [PATCH NET-PREV 16/51] geneve: Use __register_netdevice in .newlink Kirill Tkhai
2025-03-22 14:40 ` [PATCH NET-PREV 17/51] netkit: " Kirill Tkhai
2025-03-22 14:40 ` [PATCH NET-PREV 18/51] qmi_wwan: " Kirill Tkhai
2025-03-22 14:40 ` [PATCH NET-PREV 19/51] bpqether: Provide determined context in __register_netdevice() Kirill Tkhai
2025-03-22 14:40 ` [PATCH NET-PREV 20/51] ppp: Use __register_netdevice in .newlink Kirill Tkhai
2025-03-22 14:40 ` [PATCH NET-PREV 21/51] veth: " Kirill Tkhai
2025-03-22 14:40 ` [PATCH NET-PREV 22/51] vxlan: " Kirill Tkhai
2025-03-22 14:40 ` [PATCH NET-PREV 23/51] hdlc_fr: Use __register_netdevice Kirill Tkhai
2025-03-22 14:40 ` [PATCH NET-PREV 24/51] lapbeth: Provide determined context in __register_netdevice() Kirill Tkhai
2025-03-22 14:41 ` [PATCH NET-PREV 25/51] wwan: Use __register_netdevice in .newlink Kirill Tkhai
2025-03-22 14:41 ` [PATCH NET-PREV 26/51] 6lowpan: " Kirill Tkhai
2025-03-22 14:41 ` [PATCH NET-PREV 27/51] vlan: " Kirill Tkhai
2025-03-22 14:41 ` [PATCH NET-PREV 28/51] dsa: Use __register_netdevice() Kirill Tkhai
2025-03-22 14:41 ` [PATCH NET-PREV 29/51] ip6gre: Use __register_netdevice() in .changelink Kirill Tkhai
2025-03-22 14:41 ` [PATCH NET-PREV 30/51] ip6_tunnel: Use __register_netdevice() in .newlink and .changelink Kirill Tkhai
2025-03-22 14:41 ` [PATCH NET-PREV 31/51] ip6_vti: " Kirill Tkhai
2025-03-22 14:41 ` [PATCH NET-PREV 32/51] ip6_sit: " Kirill Tkhai
2025-03-22 14:41 ` [PATCH NET-PREV 33/51] net: Now check nobody calls register_netdevice() with nd_lock attached Kirill Tkhai
2025-03-22 14:42 ` [PATCH NET-PREV 34/51] dsa: Make all switch tree ports relate to same nd_lock Kirill Tkhai
2025-03-22 14:42 ` [PATCH NET-PREV 35/51] cfg80211: Use fallback_nd_lock for registered devices Kirill Tkhai
2025-03-22 14:42 ` [PATCH NET-PREV 36/51] ieee802154: " Kirill Tkhai
2025-03-22 14:42 ` [PATCH NET-PREV 37/51] net: Introduce delayed event work Kirill Tkhai
2025-03-22 14:42 ` [PATCH NET-PREV 38/51] failover: Link master and slave under nd_lock Kirill Tkhai
2025-03-22 14:42 ` [PATCH NET-PREV 39/51] netvsc: Make joined device to share master's nd_lock Kirill Tkhai
2025-03-22 14:42 ` [PATCH NET-PREV 40/51] openvswitch: Make ports share nd_lock of master device Kirill Tkhai
2025-03-22 14:42 ` [PATCH NET-PREV 41/51] bridge: Make port to have the same nd_lock as bridge Kirill Tkhai
2025-03-22 14:43 ` [PATCH NET-PREV 42/51] bond: Make master and slave relate to the same nd_lock Kirill Tkhai
2025-03-22 14:43 ` [PATCH NET-PREV 43/51] net: Now check nobody calls netdev_master_upper_dev_link() without nd_lock attached Kirill Tkhai
2025-03-22 14:43 ` [PATCH NET-PREV 44/51] net: Call dellink with nd_lock is held Kirill Tkhai
2025-03-22 14:43 ` [PATCH NET-PREV 45/51] t7xx: Use __unregister_netdevice() Kirill Tkhai
2025-03-22 14:43 ` [PATCH NET-PREV 46/51] 6lowpan: " Kirill Tkhai
2025-03-22 14:43 ` [PATCH NET-PREV 47/51] netvsc: Call dev_change_net_namespace() under nd_lock Kirill Tkhai
2025-03-22 14:43 ` [PATCH NET-PREV 48/51] default_device: " Kirill Tkhai
2025-03-22 14:43 ` [PATCH NET-PREV 49/51] ieee802154: " Kirill Tkhai
2025-03-22 14:44 ` [PATCH NET-PREV 50/51] cfg80211: " Kirill Tkhai
2025-03-22 14:44 ` [PATCH NET-PREV 51/51] net: Make all NETDEV_REGISTER events to be called " Kirill Tkhai
2025-03-24  2:51 ` [PATCH NET-PREV 00/51] Kill rtnl_lock using fine-grained nd_lock Stanislav Fomichev
2025-03-25 11:15 ` Jakub Kicinski

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=174265433421.356712.3881511284479009706.stgit@pro.pro \
    --to=tkhai@ya.ru \
    --cc=linux-kernel@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®