From: Vlad Poenaru <vlad.wing@gmail.com>
To: netdev@vger.kernel.org, Jamal Hadi Salim <jhs@mojatatu.com>,
Jiri Pirko <jiri@resnulli.us>,
"David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@kernel.org>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
Simon Horman <horms@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>,
Ingo Molnar <mingo@redhat.com>, Will Deacon <will@kernel.org>,
Boqun Feng <boqun@kernel.org>, Waiman Long <longman@redhat.com>,
Bart Van Assche <bvanassche@acm.org>,
Davide Caratti <dcaratti@redhat.com>,
Breno Leitao <leitao@debian.org>,
Nilay Shroff <nilay@linux.ibm.com>,
linux-kernel@vger.kernel.org
Subject: [PATCH net-next 1/2] lockdep: Introduce lockdep_unregister_key_nosync()
Date: Mon, 19 Oct 2026 10:02:24 -0700 [thread overview]
Message-ID: <20261019170225.729789-2-vlad.wing@gmail.com> (raw)
In-Reply-To: <20261019170225.729789-1-vlad.wing@gmail.com>
From: Bart Van Assche <bvanassche@acm.org>
Add a variant of lockdep_unregister_key() that neither sleeps nor waits
for an RCU grace period. Instead the caller must make sure that a grace
period elapses after the call before the memory holding the key is
freed or reused.
That lets callers that already free the key's memory with call_rcu() or
kfree_rcu() avoid waiting for a second grace period. The qdisc code is
such a caller: all qdiscs except ingress, clsact and noqueue embed a
dynamic lockdep key and are freed with call_rcu(), and replacing an mq
root on a multi-queue NIC destroys one qdisc per TX queue under RTNL,
each currently waiting for its own expedited grace period.
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Will Deacon <will@kernel.org>
Cc: Waiman Long <longman@redhat.com>
Cc: Boqun Feng <boqun@kernel.org>
Link: https://lore.kernel.org/all/20250203175939.3133477-2-bvanassche@acm.org/
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
[vlad: rebase onto synchronize_rcu_expedited(), spell out the grace
period requirement in the comments and changelog, describe the qdisc
use case]
Signed-off-by: Vlad Poenaru <vlad.wing@gmail.com>
---
include/linux/lockdep.h | 5 +++++
kernel/locking/lockdep.c | 36 +++++++++++++++++++++++++-----------
2 files changed, 30 insertions(+), 11 deletions(-)
diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h
index a6451ecbbe9a0..80b27973b7f72 100644
--- a/include/linux/lockdep.h
+++ b/include/linux/lockdep.h
@@ -117,6 +117,7 @@ do { \
} while (0)
extern void lockdep_register_key(struct lock_class_key *key);
+extern void lockdep_unregister_key_nosync(struct lock_class_key *key);
extern void lockdep_unregister_key(struct lock_class_key *key);
/*
@@ -375,6 +376,10 @@ static inline void lockdep_register_key(struct lock_class_key *key)
{
}
+static inline void lockdep_unregister_key_nosync(struct lock_class_key *key)
+{
+}
+
static inline void lockdep_unregister_key(struct lock_class_key *key)
{
}
diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c
index c3dc84a7cef26..16c8480e282e3 100644
--- a/kernel/locking/lockdep.c
+++ b/kernel/locking/lockdep.c
@@ -6669,13 +6669,19 @@ void lockdep_reset_lock(struct lockdep_map *lock)
}
/*
- * Unregister a dynamically allocated key.
+ * Unregister a dynamically allocated key without waiting for RCU readers.
*
* Unlike lockdep_register_key(), a search is always done to find a matching
* key irrespective of debug_locks to avoid potential invalid access to freed
* memory in lock_class entry.
+ *
+ * is_dynamic_key() may still be walking past @key under RCU when this
+ * returns. The memory holding @key must not be freed or reused, including by
+ * registering @key again, until an RCU grace period that starts after this
+ * call has elapsed, e.g. by freeing it with call_rcu() or kfree_rcu() queued
+ * after this call. Does not sleep.
*/
-void lockdep_unregister_key(struct lock_class_key *key)
+void lockdep_unregister_key_nosync(struct lock_class_key *key)
{
struct hlist_head *hash_head = keyhashentry(key);
struct lock_class_key *k;
@@ -6684,8 +6690,6 @@ void lockdep_unregister_key(struct lock_class_key *key)
bool found = false;
bool need_callback = false;
- might_sleep();
-
if (WARN_ON_ONCE(static_obj(key)))
return;
@@ -6711,15 +6715,25 @@ void lockdep_unregister_key(struct lock_class_key *key)
if (need_callback)
call_rcu(&delayed_free.rcu_head, free_zapped_rcu);
+}
+EXPORT_SYMBOL_GPL(lockdep_unregister_key_nosync);
+
+/*
+ * Unregister a dynamically allocated key and wait for is_dynamic_key()
+ * readers, so that the memory holding @key may be freed as soon as this
+ * returns. May sleep.
+ */
+void lockdep_unregister_key(struct lock_class_key *key)
+{
+ might_sleep();
+
+ lockdep_unregister_key_nosync(key);
/*
- * Wait until is_dynamic_key() has finished accessing k->hash_entry.
- *
- * Some operations like __qdisc_destroy() will call this in a debug
- * kernel, and the network traffic is disabled while waiting, hence
- * the delay of the wait matters in debugging cases. Currently use a
- * synchronize_rcu_expedited() to speed up the wait at the cost of
- * system IPIs. TODO: Replace RCU with hazptr for this.
+ * Expedited to keep the wait short, at the cost of IPIs. Callers that
+ * free @key after a grace period anyway should use
+ * lockdep_unregister_key_nosync() instead.
+ * TODO: Replace RCU with hazptr for this.
*/
synchronize_rcu_expedited();
}
--
2.53.0-Meta
next prev parent reply other threads:[~2026-10-19 17:02 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-19 17:02 [PATCH net-next 0/2] net/sched: don't wait for RCU when destroying qdisc lockdep keys Vlad Poenaru
2026-10-19 17:02 ` Vlad Poenaru [this message]
2026-10-19 17:38 ` [PATCH net-next 1/2] lockdep: Introduce lockdep_unregister_key_nosync() Eric Dumazet
2026-10-19 17:02 ` [PATCH net-next 2/2] net/sched: Don't wait for RCU when unregistering the qdisc lockdep key Vlad Poenaru
2026-10-19 17:37 ` Eric Dumazet
2026-10-19 19:20 ` [PATCH net-next 0/2] net/sched: don't wait for RCU when destroying qdisc lockdep keys Boqun Feng
2026-10-20 12:53 ` Vlad Poenaru
2026-10-20 17:15 ` Boqun Feng
2026-10-20 17:26 ` Bart Van Assche
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=20261019170225.729789-2-vlad.wing@gmail.com \
--to=vlad.wing@gmail.com \
--cc=boqun@kernel.org \
--cc=bvanassche@acm.org \
--cc=davem@davemloft.net \
--cc=dcaratti@redhat.com \
--cc=edumazet@kernel.org \
--cc=horms@kernel.org \
--cc=jhs@mojatatu.com \
--cc=jiri@resnulli.us \
--cc=kuba@kernel.org \
--cc=leitao@debian.org \
--cc=linux-kernel@vger.kernel.org \
--cc=longman@redhat.com \
--cc=mingo@redhat.com \
--cc=netdev@vger.kernel.org \
--cc=nilay@linux.ibm.com \
--cc=pabeni@redhat.com \
--cc=peterz@infradead.org \
--cc=will@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.