lockdep_unregister_key() waits for is_dynamic_key() callers with synchronize_rcu_expedited(), which sends IPIs to every online CPU. Have is_dynamic_key() mark the hash bucket with a hazard pointer and use hazptr_synchronize() to wait specifically for those traversals.
The hash bucket address from keyhashentry() is stable, making it a suitable hazptr synchronize target. The rest of the key hashlist lifetime (hlist_del_rcu/call_rcu) remains RCU-based. This adapts the lockdep use case from Boqun Feng's hazard-pointer series to the current hazptr API. Signed-off-by: Kunwu Chan <[email protected]> --- kernel/locking/lockdep.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c index c56a7f91d72e..f67d847f9abf 100644 --- a/kernel/locking/lockdep.c +++ b/kernel/locking/lockdep.c @@ -58,6 +58,7 @@ #include <linux/context_tracking.h> #include <linux/console.h> #include <linux/kasan.h> +#include <linux/hazptr.h> #include <asm/sections.h> @@ -1280,14 +1281,24 @@ static bool is_dynamic_key(const struct lock_class_key *key) hash_head = keyhashentry(key); - rcu_read_lock(); - hlist_for_each_entry_rcu(k, hash_head, hash_entry) { - if (k == key) { - found = true; - break; + /* + * The traversal is protected by a hazard pointer rather + * than an RCU read-side critical section. + */ + { + struct hazptr_ctx ctx; + void *bucket = hash_head; + void *addr; + + addr = hazptr_acquire(&ctx, &bucket); + hlist_for_each_entry_rcu(k, hash_head, hash_entry, 1) { + if (k == key) { + found = true; + break; + } } + hazptr_release(&ctx, addr); } - rcu_read_unlock(); return found; } @@ -6683,11 +6694,10 @@ void lockdep_unregister_key(struct lock_class_key *key) * * 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. + * the delay of the wait matters in debugging cases. Replace the + * expedited RCU wait with hazptr_synchronize(). */ - synchronize_rcu_expedited(); + hazptr_synchronize(keyhashentry(key)); } EXPORT_SYMBOL_GPL(lockdep_unregister_key); -- 2.43.0

