On Tue, 15 Sep 2026, Herbert Xu wrote:
> On Mon, Sep 14, 2026 at 09:06:49PM -0700, Eric Dumazet wrote:
> >
> > Try to revert 4333ab90aaae ("rhashtable: use private lockdep class for
> > all locks.")
> 
> Yes this is indeed buggy.  I know nothing about lockdep but Gemini
> reckons that it should use separate keys instead of different
> depths which seems fair enough:
> 
> ---8<---
> 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: 4333ab90aaae ("rhashtable: use private lockdep class for all locks.")
> Reported-by: [email protected]
> Assisted-by: Gemini:gemini-3.6-flash
> Signed-off-by: Herbert Xu <[email protected]>

That's a much better approach - thanks for that.

Reviewed-by: NeilBrown <[email protected]>

Thanks,
NeilBrown


> 
> diff --git a/include/linux/rhashtable-types.h 
> b/include/linux/rhashtable-types.h
> index 0e1b172a4f6c..afbc12ba71f5 100644
> --- a/include/linux/rhashtable-types.h
> +++ b/include/linux/rhashtable-types.h
> @@ -70,6 +70,14 @@ struct rhashtable_params {
>       rht_obj_cmpfn_t         obj_cmpfn;
>  };
>  
> +struct rhashtable_lockdep_keys {
> +#ifdef CONFIG_LOCKDEP
> +     struct lock_class_key lock_key;
> +     struct lock_class_key mutex_key;
> +     struct lock_class_key bucket_key;
> +#endif
> +};
> +
>  /**
>   * struct rhashtable - Hash table handle
>   * @tbl: Bucket table
> @@ -141,24 +149,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 */
> diff --git a/include/linux/rhashtable.h b/include/linux/rhashtable.h
> index 6c5e6d9accba..ec853c1b9af3 100644
> --- a/include/linux/rhashtable.h
> +++ b/include/linux/rhashtable.h
> @@ -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;
>  }
>  
> diff --git a/lib/rhashtable.c b/lib/rhashtable.c
> index 5da0e53a8d42..918f15a2ac69 100644
> --- a/lib/rhashtable.c
> +++ b/lib/rhashtable.c
> @@ -432,7 +432,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 +1122,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 +1134,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 +1192,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;
>  }
> diff --git a/lib/test_rhashtable.c b/lib/test_rhashtable.c
> index 85a615e74591..b767a38a74f9 100644
> --- a/lib/test_rhashtable.c
> +++ b/lib/test_rhashtable.c
> @@ -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;
> -- 
> Email: Herbert Xu <[email protected]>
> Home Page: http://gondor.apana.org.au/~herbert/
> PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
> 


Reply via email to