rhashtable: Use separate lockdep keys for each lock

Use separate lockdep keys for the different types of locks in
rhashtable (mutex, spin lock, and bucket locks).  They are
separate and not normally nested with respect to each other.

Also move the rhashtable_init/rhltable_init kdoc to the header
file as that's where the macros are defined.

Fixes: 4333ab90aa ("rhashtable: use private lockdep class for all locks.")
Reported-by: syzbot+4d0e4d2db6dfde01b52f@syzkaller.appspotmail.com
Assisted-by: Gemini:gemini-3.6-flash
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Reviewed-by: NeilBrown <neil@brown.name>
Tested-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
This commit is contained in:
Herbert Xu committed 2026-09-23 18:38:39 +10:00
1 parent eeaf1ccd4c
commit 9fa551ef51
4 files changed
+75 -71

No files matched your search

+65 -6
View File
@@ -70,6 +70,12 @@ struct rhashtable_params {
rht_obj_cmpfn_t obj_cmpfn;
};
struct rhashtable_lockdep_keys {
struct lock_class_key lock_key;
struct lock_class_key mutex_key;
struct lock_class_key bucket_key;
};
/**
* struct rhashtable - Hash table handle
* @tbl: Bucket table
@@ -141,24 +147,77 @@ struct rhashtable_iter {
int __rhashtable_init_noprof(struct rhashtable *ht,
const struct rhashtable_params *params,
struct lock_class_key *key);
struct rhashtable_lockdep_keys *keys);
#define rhashtable_init_noprof(ht, params) \
({ \
static struct lock_class_key __key; \
static struct rhashtable_lockdep_keys __keys; \
\
__rhashtable_init_noprof(ht, params, &__key); \
__rhashtable_init_noprof(ht, params, &__keys); \
})
/**
* rhashtable_init - initialize a new hash table
* @ht: hash table to be initialized
* @params: configuration parameters
*
* Initializes a new hash table based on the provided configuration
* parameters. A table can be configured either with a variable or
* fixed length key:
*
* Configuration Example 1: Fixed length keys
* struct test_obj {
* int key;
* void * my_member;
* struct rhash_head node;
* };
*
* struct rhashtable_params params = {
* .head_offset = offsetof(struct test_obj, node),
* .key_offset = offsetof(struct test_obj, key),
* .key_len = sizeof(int),
* .hashfn = jhash,
* };
*
* Configuration Example 2: Variable length keys
* struct test_obj {
* [...]
* struct rhash_head node;
* };
*
* u32 my_hash_fn(const void *data, u32 len, u32 seed)
* {
* struct test_obj *obj = data;
*
* return [... hash ...];
* }
*
* struct rhashtable_params params = {
* .head_offset = offsetof(struct test_obj, node),
* .hashfn = jhash,
* .obj_hashfn = my_hash_fn,
* };
*/
#define rhashtable_init(...) alloc_hooks(rhashtable_init_noprof(__VA_ARGS__))
int __rhltable_init_noprof(struct rhltable *hlt,
const struct rhashtable_params *params,
struct lock_class_key *key);
struct rhashtable_lockdep_keys *keys);
#define rhltable_init_noprof(hlt, params) \
({ \
static struct lock_class_key __key; \
static struct rhashtable_lockdep_keys __keys; \
\
__rhltable_init_noprof(hlt, params, &__key); \
__rhltable_init_noprof(hlt, params, &__keys); \
})
/**
* rhltable_init - initialize a new hash list table
* @hlt: hash list table to be initialized
* @params: configuration parameters
*
* Initializes a new hash list table.
*
* See documentation for rhashtable_init.
*/
#define rhltable_init(...) alloc_hooks(rhltable_init_noprof(__VA_ARGS__))
#endif /* _LINUX_RHASHTABLE_TYPES_H */
+1 -2
View File
@@ -328,8 +328,7 @@ static inline unsigned long rht_lock_nested(struct bucket_table *tbl,
local_irq_save(flags);
bit_spin_lock(0, (unsigned long *)bucket);
/* subclass 0 is used for ->lock and 1 for ->mutex. 2+ for bitlocks */
lock_acquire_exclusive(&tbl->dep_map, subclass+2, 0, NULL, _THIS_IP_);
lock_acquire_exclusive(&tbl->dep_map, subclass, 0, NULL, _THIS_IP_);
return flags;
}
+8 -62
View File
@@ -207,7 +207,6 @@ static struct bucket_table *bucket_table_alloc(struct rhashtable *ht,
return NULL;
#ifdef CONFIG_LOCKDEP
/* bitlocks must use nesting level 2 or more */
lockdep_init_map(&tbl->dep_map, "rhashtable_bucket", ht->lockdep_key, 0);
#endif
@@ -432,7 +431,7 @@ static void rht_deferred_worker(struct work_struct *work)
int err = 0;
ht = container_of(work, struct rhashtable, run_work);
mutex_lock_nested(&ht->mutex, 1);
mutex_lock(&ht->mutex);
tbl = rht_dereference(ht->tbl, ht);
tbl = rhashtable_last_table(ht, tbl);
@@ -1122,51 +1121,9 @@ static u32 rhashtable_jhash2(const void *key, u32 length, u32 seed)
return jhash2(key, length, seed);
}
/**
* rhashtable_init - initialize a new hash table
* @ht: hash table to be initialized
* @params: configuration parameters
*
* Initializes a new hash table based on the provided configuration
* parameters. A table can be configured either with a variable or
* fixed length key:
*
* Configuration Example 1: Fixed length keys
* struct test_obj {
* int key;
* void * my_member;
* struct rhash_head node;
* };
*
* struct rhashtable_params params = {
* .head_offset = offsetof(struct test_obj, node),
* .key_offset = offsetof(struct test_obj, key),
* .key_len = sizeof(int),
* .hashfn = jhash,
* };
*
* Configuration Example 2: Variable length keys
* struct test_obj {
* [...]
* struct rhash_head node;
* };
*
* u32 my_hash_fn(const void *data, u32 len, u32 seed)
* {
* struct test_obj *obj = data;
*
* return [... hash ...];
* }
*
* struct rhashtable_params params = {
* .head_offset = offsetof(struct test_obj, node),
* .hashfn = jhash,
* .obj_hashfn = my_hash_fn,
* };
*/
int __rhashtable_init_noprof(struct rhashtable *ht,
const struct rhashtable_params *params,
struct lock_class_key *key)
const struct rhashtable_params *params,
struct rhashtable_lockdep_keys *keys)
{
struct bucket_table *tbl;
size_t size;
@@ -1176,13 +1133,11 @@ int __rhashtable_init_noprof(struct rhashtable *ht,
return -EINVAL;
memset(ht, 0, sizeof(*ht));
/* mutex_lock must use nesting level 1 */
mutex_init_with_key(&ht->mutex, key);
mutex_init_with_key(&ht->mutex, &keys->mutex_key);
spin_lock_init(&ht->lock);
/* spin_lock can use nesting level 0 */
lockdep_set_class(&ht->lock, key);
lockdep_set_class(&ht->lock, &keys->lock_key);
#ifdef CONFIG_LOCKDEP
ht->lockdep_key = key;
ht->lockdep_key = &keys->bucket_key;
#endif
memcpy(&ht->p, params, sizeof(*params));
@@ -1236,22 +1191,13 @@ int __rhashtable_init_noprof(struct rhashtable *ht,
}
EXPORT_SYMBOL_GPL(__rhashtable_init_noprof);
/**
* rhltable_init - initialize a new hash list table
* @hlt: hash list table to be initialized
* @params: configuration parameters
*
* Initializes a new hash list table.
*
* See documentation for rhashtable_init.
*/
int __rhltable_init_noprof(struct rhltable *hlt,
const struct rhashtable_params *params,
struct lock_class_key *key)
struct rhashtable_lockdep_keys *keys)
{
int err;
err = __rhashtable_init_noprof(&hlt->ht, params, key);
err = __rhashtable_init_noprof(&hlt->ht, params, keys);
hlt->ht.rhlist = true;
return err;
}
+1 -1
View File
@@ -477,7 +477,7 @@ static unsigned int __init print_ht(struct rhltable *rhlt)
ht = &rhlt->ht;
/* Take the mutex to avoid RCU warning */
mutex_lock_nested(&ht->mutex, 1);
mutex_lock(&ht->mutex);
tbl = rht_dereference(ht->tbl, ht);
for (i = 0; i < tbl->size; i++) {
struct rhash_head *pos, *next;