[PATCH 2/4] locking/lockdep: Use hashtable.h for classhash_table

Sasha Levin
2025-03-20T14:31:34Z

Convert classhash_table in lockdep.c to use the generic hashtable
implementation from hashtable.h instead of the manual hlist_head array
implementation.

This simplifies the code and makes it more maintainable by using the
standard hashtable API and removes the need for custom hash lookup
functions.

Signed-off-by: Sasha Levin <sashal@kernel.org>
---
kernel/locking/lockdep.c | 69 ++++++++++++++--------------------------
1 file changed, 24 insertions(+), 45 deletions(-)

diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c
index 160cf8310eda0..b071bbf0d955c 100644
--- a/kernel/locking/lockdep.c
+++ b/kernel/locking/lockdep.c
@@ -404,12 +404,8 @@ static struct delayed_free {
/*
* The lockdep classes are in a hash-table as well, for fast lookup:
*/
-#define CLASSHASH_BITS (MAX_LOCKDEP_KEYS_BITS - 1)
-#define CLASSHASH_SIZE (1UL << CLASSHASH_BITS)
-#define __classhashfn(key) hash_long((unsigned long)key, CLASSHASH_BITS)
-#define classhashentry(key) (classhash_table + __classhashfn((key)))
-
-static struct hlist_head classhash_table[CLASSHASH_SIZE];
+#define CLASSHASH_BITS (MAX_LOCKDEP_KEYS_BITS-1)
+static DEFINE_HASHTABLE(classhash_table, CLASSHASH_BITS);

/*
* We put the lock dependency chains into a hash-table as well, to cache
@@ -886,8 +882,8 @@ static noinstr struct lock_class *
look_up_lock_class(const struct lockdep_map *lock, unsigned int subclass)
{
struct lockdep_subclass_key *key;
- struct hlist_head *hash_head;
struct lock_class *class;
+ unsigned long hash;

if (unlikely(subclass >= MAX_LOCKDEP_SUBCLASSES)) {
instrumentation_begin();
@@ -920,8 +916,7 @@ look_up_lock_class(const struct lockdep_map *lock, unsigned int subclass)
sizeof(struct lockdep_map));

key = lock->key->subkeys + subclass;
-
- hash_head = classhashentry(key);
+ hash = (unsigned long)key;

/*
* We do an RCU walk of the hash, see lockdep_free_key_range().
@@ -929,7 +924,7 @@ look_up_lock_class(const struct lockdep_map *lock, unsigned int subclass)
if (DEBUG_LOCKS_WARN_ON(!irqs_disabled()))
return NULL;

- hlist_for_each_entry_rcu_notrace(class, hash_head, hash_entry) {
+ hash_for_each_possible_rcu_notrace(classhash_table, class, hash_entry, hash) {
if (class->key == key) {
/*
* Huh! same key, different name? Did someone trample
@@ -1084,7 +1079,6 @@ static bool __check_data_structures(void)
{
struct lock_class *class;
struct lock_chain *chain;
- struct hlist_head *head;
struct lock_list *e;
int i;

@@ -1110,12 +1104,9 @@ static bool __check_data_structures(void)
}

/* Check the chain_key of all lock chains. */
- for (i = 0; i < ARRAY_SIZE(chainhash_table); i++) {
- head = chainhash_table + i;
- hlist_for_each_entry_rcu(chain, head, entry) {
- if (!check_lock_chain_key(chain))
- return false;
- }
+ hash_for_each_rcu(chainhash_table, i, chain, entry) {
+ if (!check_lock_chain_key(chain))
+ return false;
}

/*
@@ -1279,8 +1270,8 @@ static struct lock_class *
register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force)
{
struct lockdep_subclass_key *key;
- struct hlist_head *hash_head;
struct lock_class *class;
+ unsigned long hash;
int idx;

DEBUG_LOCKS_WARN_ON(!irqs_disabled());
@@ -1297,7 +1288,7 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force)
}

key = lock->key->subkeys + subclass;
- hash_head = classhashentry(key);
+ hash = (unsigned long)key;

if (!graph_lock()) {
return NULL;
@@ -1306,7 +1297,7 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force)
* We have to do the hash-walk again, to avoid races
* with another CPU:
*/
- hlist_for_each_entry_rcu(class, hash_head, hash_entry) {
+ hash_for_each_possible_rcu(classhash_table, class, hash_entry, hash) {
if (class->key == key)
goto out_unlock_set;
}
@@ -1343,7 +1334,7 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force)
* We use RCU's safe list-add method to make
* parallel walking of the hash-list safe:
*/
- hlist_add_head_rcu(&class->hash_entry, hash_head);
+ hash_add_rcu(classhash_table, &class->hash_entry, hash);
/*
* Remove the class from the free list and add it to the global list
* of classes.
@@ -6206,14 +6197,10 @@ static void remove_class_from_lock_chains(struct pending_free *pf,
struct lock_class *class)
{
struct lock_chain *chain;
- struct hlist_head *head;
int i;

- for (i = 0; i < ARRAY_SIZE(chainhash_table); i++) {
- head = chainhash_table + i;
- hlist_for_each_entry_rcu(chain, head, entry) {
- remove_class_from_lock_chain(pf, chain, class);
- }
+ hash_for_each_rcu(chainhash_table, i, chain, entry) {
+ remove_class_from_lock_chain(pf, chain, class);
}
}

@@ -6370,18 +6357,14 @@ static void __lockdep_free_key_range(struct pending_free *pf, void *start,
unsigned long size)
{
struct lock_class *class;
- struct hlist_head *head;
int i;

/* Unhash all classes that were created by a module. */
- for (i = 0; i < CLASSHASH_SIZE; i++) {
- head = classhash_table + i;
- hlist_for_each_entry_rcu(class, head, hash_entry) {
- if (!within(class->key, start, size) &&
- !within(class->name, start, size))
- continue;
- zap_class(pf, class);
- }
+ hash_for_each_rcu(classhash_table, i, class, hash_entry) {
+ if (!within(class->key, start, size) &&
+ !within(class->name, start, size))
+ continue;
+ zap_class(pf, class);
}
}

@@ -6454,16 +6437,12 @@ void lockdep_free_key_range(void *start, unsigned long size)
static bool lock_class_cache_is_registered(struct lockdep_map *lock)
{
struct lock_class *class;
- struct hlist_head *head;
int i, j;

- for (i = 0; i < CLASSHASH_SIZE; i++) {
- head = classhash_table + i;
- hlist_for_each_entry_rcu(class, head, hash_entry) {
- for (j = 0; j < NR_LOCKDEP_CACHING_CLASSES; j++)
- if (lock->class_cache[j] == class)
- return true;
- }
+ hash_for_each_rcu(classhash_table, i, class, hash_entry) {
+ for (j = 0; j < NR_LOCKDEP_CACHING_CLASSES; j++)
+ if (lock->class_cache[j] == class)
+ return true;
}
return false;
}
@@ -6605,7 +6584,7 @@ void __init lockdep_init(void)
pr_info("... MAX_LOCKDEP_SUBCLASSES: %lu\n", MAX_LOCKDEP_SUBCLASSES);
pr_info("... MAX_LOCK_DEPTH: %lu\n", MAX_LOCK_DEPTH);
pr_info("... MAX_LOCKDEP_KEYS: %lu\n", MAX_LOCKDEP_KEYS);
- pr_info("... CLASSHASH_SIZE: %lu\n", CLASSHASH_SIZE);
+ pr_info("... CLASSHASH_SIZE: %lu\n", HASH_SIZE(classhash_table));
pr_info("... MAX_LOCKDEP_ENTRIES: %lu\n", MAX_LOCKDEP_ENTRIES);
pr_info("... MAX_LOCKDEP_CHAINS: %lu\n", MAX_LOCKDEP_CHAINS);
pr_info("... CHAINHASH_SIZE: %lu\n", CHAINHASH_SIZE);
--
2.39.5