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);
next prev 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®