[PATCH 7/9] locking/lockdep: Traverse adjacency lists directly in zap_class()
From: Jim Cromie via B4 Relay
Date: Mon Aug 17 2026 - 13:57:56 EST
From: Jim Cromie <jim.cromie@xxxxxxxxx>
By definition, every dependency involving a lock class resides in either
its locks_after (forward) or locks_before (backward) list.
During module unload (rmmod) cleanup, zap_class() historically took a
shortcut: it scanned the global list_entries_in_use allocator bitmap,
testing every allocated dependency across the entire kernel against a
fixed static array.
That shortcut worked only because all dependencies were confined to a
single compile-time array. It conflates graph topology with allocator
storage layout, and breaks down the moment lockdep needs to scale beyond
static allocations.
Rework zap_class() to traverse class->locks_after and class->locks_before
directly, unlinking each edge and its matching counterpart on the
connected lock class via RCU while clearing the respective allocation
slot bits.
This restores the canonical graph deletion flow, touches only the edges
connected to the zapped class, and allows lockdep to safely support
dynamic allocators.
Signed-off-by: Jim Cromie <jim.cromie@xxxxxxxxx>
---
kernel/locking/lockdep.c | 31 ++++++++++++++++++++++++-------
1 file changed, 24 insertions(+), 7 deletions(-)
diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c
index f0f58db090ff..c8975c9282bb 100644
--- a/kernel/locking/lockdep.c
+++ b/kernel/locking/lockdep.c
@@ -6276,8 +6276,7 @@ static void remove_class_from_lock_chains(struct pending_free *pf,
*/
static void zap_class(struct pending_free *pf, struct lock_class *class)
{
- struct lock_list *entry;
- int i;
+ struct lock_list *entry, *tmp, *other, *other_tmp;
WARN_ON_ONCE(!class->key);
@@ -6285,11 +6284,29 @@ static void zap_class(struct pending_free *pf, struct lock_class *class)
* Remove all dependencies this lock is
* involved in:
*/
- for_each_set_bit(i, list_entries_in_use, ARRAY_SIZE(list_entries)) {
- entry = list_entries + i;
- if (entry->class != class && entry->links_to != class)
- continue;
- __clear_bit(i, list_entries_in_use);
+ list_for_each_entry_safe(entry, tmp, &class->locks_after, entry) {
+ list_for_each_entry_safe(other, other_tmp, &entry->links_to->locks_before, entry) {
+ if (other->links_to == class) {
+ __clear_bit(other - list_entries, list_entries_in_use);
+ nr_list_entries--;
+ list_del_rcu(&other->entry);
+ break;
+ }
+ }
+ __clear_bit(entry - list_entries, list_entries_in_use);
+ nr_list_entries--;
+ list_del_rcu(&entry->entry);
+ }
+ list_for_each_entry_safe(entry, tmp, &class->locks_before, entry) {
+ list_for_each_entry_safe(other, other_tmp, &entry->links_to->locks_after, entry) {
+ if (other->links_to == class) {
+ __clear_bit(other - list_entries, list_entries_in_use);
+ nr_list_entries--;
+ list_del_rcu(&other->entry);
+ break;
+ }
+ }
+ __clear_bit(entry - list_entries, list_entries_in_use);
nr_list_entries--;
list_del_rcu(&entry->entry);
}
--
2.55.0