[PATCH] rhashtable: use per-init-site lockdep classes for bucket locks

quanyeyang via B4 Relay posted 1 patch 2 months ago
include/linux/rhashtable-types.h | 20 ++++++++++++++------
lib/rhashtable.c                 | 19 +++++++++++++------
2 files changed, 27 insertions(+), 12 deletions(-)
[PATCH] rhashtable: use per-init-site lockdep classes for bucket locks
Posted by quanyeyang via B4 Relay 2 months ago
From: quanyeyang <quanyemostima@gmail.com>

All bucket tables currently share a single lockdep class. This makes
lockdep conflate bucket locks from unrelated rhashtable instances.

A BPF program attached to lock_release can expose this when pidfs
inserts a pid. The tracepoint runs before lockdep removes the pidfs
bucket lock from the task's held-lock stack. Deleting an element from
a BPF RHASH map then acquires a bucket lock belonging to a different
rhashtable. Since both tables use the same class, lockdep reports
possible recursive locking.

Declare a separate bucket lock class key at each rhashtable_init() and
rhltable_init() call site, alongside the mutex class key. Store the
bucket key in struct rhashtable so tables created during resize keep
using the same class.

A targeted reproducer triggers the warning reliably before this change.
After the change, the nested BPF RHASH deletion still executes, but
lockdep no longer reports recursive locking.

Fixes: 149212f07856 ("rhashtable: add lockdep tracking to bucket bit-spin-locks.")
Reported-by: syzbot+ef8d17bae14efb960935@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=ef8d17bae14efb960935
Assisted-by: Cursor:GPT-5.6 Sol
Signed-off-by: quanyeyang <quanyemostima@gmail.com>
---
 include/linux/rhashtable-types.h | 20 ++++++++++++++------
 lib/rhashtable.c                 | 19 +++++++++++++------
 2 files changed, 27 insertions(+), 12 deletions(-)

diff --git a/include/linux/rhashtable-types.h b/include/linux/rhashtable-types.h
index 57c11ec9dc64..4dea91a49ec8 100644
--- a/include/linux/rhashtable-types.h
+++ b/include/linux/rhashtable-types.h
@@ -82,6 +82,7 @@ struct rhashtable_params {
  * @mutex: Mutex to protect current/future table swapping
  * @lock: Spin lock to protect walker list
  * @nelems: Number of elements in table
+ * @bucket_lock_key: Per-init-site lockdep class for bucket bit-locks
  */
 struct rhashtable {
 	struct bucket_table __rcu	*tbl;
@@ -94,6 +95,7 @@ struct rhashtable {
 	struct mutex                    mutex;
 	spinlock_t			lock;
 	atomic_t			nelems;
+	struct lock_class_key		*bucket_lock_key;
 #ifdef CONFIG_MEM_ALLOC_PROFILING
 	struct alloc_tag		*alloc_tag;
 #endif
@@ -138,23 +140,29 @@ struct rhashtable_iter {
 
 int __rhashtable_init_noprof(struct rhashtable *ht,
 		    const struct rhashtable_params *params,
-		    struct lock_class_key *key);
+		    struct lock_class_key *mutex_key,
+		    struct lock_class_key *bucket_key);
 #define rhashtable_init_noprof(ht, params)				\
 ({									\
-	static struct lock_class_key __key;				\
+	static struct lock_class_key __mutex_key;			\
+	static struct lock_class_key __bucket_key;			\
 									\
-	__rhashtable_init_noprof(ht, params, &__key);			\
+	__rhashtable_init_noprof(ht, params, &__mutex_key,		\
+				 &__bucket_key);			\
 })
 #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 lock_class_key *mutex_key,
+		  struct lock_class_key *bucket_key);
 #define rhltable_init_noprof(hlt, params)				\
 ({									\
-	static struct lock_class_key __key;				\
+	static struct lock_class_key __mutex_key;			\
+	static struct lock_class_key __bucket_key;			\
 									\
-	__rhltable_init_noprof(hlt, params, &__key);			\
+	__rhltable_init_noprof(hlt, params, &__mutex_key,		\
+			       &__bucket_key);				\
 })
 #define rhltable_init(...)	alloc_hooks(rhltable_init_noprof(__VA_ARGS__))
 
diff --git a/lib/rhashtable.c b/lib/rhashtable.c
index d459bef245f4..e047ad912f0e 100644
--- a/lib/rhashtable.c
+++ b/lib/rhashtable.c
@@ -189,7 +189,6 @@ static struct bucket_table *bucket_table_alloc(struct rhashtable *ht,
 	struct bucket_table *tbl = NULL;
 	size_t size;
 	int i;
-	static struct lock_class_key __key;
 
 	tbl = alloc_hooks_tag(ht->alloc_tag,
 			kvmalloc_node_align_noprof(struct_size(tbl, buckets, nbuckets),
@@ -205,7 +204,12 @@ static struct bucket_table *bucket_table_alloc(struct rhashtable *ht,
 	if (tbl == NULL)
 		return NULL;
 
-	lockdep_init_map(&tbl->dep_map, "rhashtable_bucket", &__key, 0);
+	/*
+	 * Keep all bucket tables belonging to the same rhashtable in the
+	 * per-init-site lock class, including tables created during resize.
+	 */
+	lockdep_init_map(&tbl->dep_map, "rhashtable_bucket",
+			 ht->bucket_lock_key, 0);
 
 	tbl->size = size;
 
@@ -1162,7 +1166,8 @@ static u32 rhashtable_jhash2(const void *key, u32 length, u32 seed)
  */
 int __rhashtable_init_noprof(struct rhashtable *ht,
 		    const struct rhashtable_params *params,
-		    struct lock_class_key *key)
+		    struct lock_class_key *mutex_key,
+		    struct lock_class_key *bucket_key)
 {
 	struct bucket_table *tbl;
 	size_t size;
@@ -1172,7 +1177,8 @@ int __rhashtable_init_noprof(struct rhashtable *ht,
 		return -EINVAL;
 
 	memset(ht, 0, sizeof(*ht));
-	mutex_init_with_key(&ht->mutex, key);
+	mutex_init_with_key(&ht->mutex, mutex_key);
+	ht->bucket_lock_key = bucket_key;
 	spin_lock_init(&ht->lock);
 	memcpy(&ht->p, params, sizeof(*params));
 
@@ -1237,11 +1243,12 @@ EXPORT_SYMBOL_GPL(__rhashtable_init_noprof);
  */
 int __rhltable_init_noprof(struct rhltable *hlt,
 			   const struct rhashtable_params *params,
-			   struct lock_class_key *key)
+			   struct lock_class_key *mutex_key,
+			   struct lock_class_key *bucket_key)
 {
 	int err;
 
-	err = __rhashtable_init_noprof(&hlt->ht, params, key);
+	err = __rhashtable_init_noprof(&hlt->ht, params, mutex_key, bucket_key);
 	hlt->ht.rhlist = true;
 	return err;
 }

---
base-commit: 0131b508c0e2489eac6e121135988f6eeb716f19
change-id: 20260801-fix-rhashtable-bucket-lockdep-95e25abebeea

Best regards,
--  
quanyeyang <quanyemostima@gmail.com>
Re: [PATCH] rhashtable: use per-init-site lockdep classes for bucket locks
Posted by kernel test robot 1 month ago
Hello,

kernel test robot noticed a 12.5% regression of stress-ng.shm-sysv.ops_per_sec on:


commit: 62d8460a4e7a3ee028e5134d86169001490e7a60 ("[PATCH] rhashtable: use per-init-site lockdep classes for bucket locks")
url: https://github.com/intel-lab-lkp/linux/commits/quanyeyang-via-B4-Relay/rhashtable-use-per-init-site-lockdep-classes-for-bucket-locks/20260815-014140
patch link: https://lore.kernel.org/all/20260801-fix-rhashtable-bucket-lockdep-v1-1-15a0f8ae094c@gmail.com/
patch subject: [PATCH] rhashtable: use per-init-site lockdep classes for bucket locks

testcase: stress-ng
config: x86_64-rhel-9.4
compiler: gcc-14
test machine: 224 threads 2 sockets Intel(R) Xeon(R) Platinum 8480CTDX (Sapphire Rapids) with 256G memory
parameters:

	nr_threads: 100%
	testtime: 60s
	test: shm-sysv
	cpufreq_governor: performance


If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <yi1.lai@intel.com>
| Closes: https://lore.kernel.org/oe-lkp/202608280842.861e5949-lkp@intel.com


Details are as below:
-------------------------------------------------------------------------------------------------->


The kernel config and materials to reproduce are available at:
https://download.01.org/0day-ci/archive/20260828/202608280842.861e5949-lkp@intel.com

=========================================================================================
compiler/cpufreq_governor/kconfig/nr_threads/rootfs/tbox_group/test/testcase/testtime:
  gcc-14/performance/x86_64-rhel-9.4/100%/debian-13-x86_64-20250902.cgz/lkp-spr-r02/shm-sysv/stress-ng/60s

commit: 
  0131b508c0 ("Merge tag 'ntfs-for-7.2-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/ntfs")
  62d8460a4e ("[PATCH] rhashtable: use per-init-site lockdep classes for bucket locks")

0131b508c0e2489e 62d8460a4e7a3ee028e5134d861
---------------- --------------------------- 
    192413           +44.1%     277255        stress-ng.shm-sysv.nanosecs_per_shmat_call
    349549           +24.2%     433996        stress-ng.shm-sysv.nanosecs_per_shmdt_call
    174600           +51.9%     265191        stress-ng.shm-sysv.nanosecs_per_shmget_call
    793610           -12.5%     694260        stress-ng.shm-sysv.ops
     13236           -12.5%      11578        stress-ng.shm-sysv.ops_per_sec
     65737           -10.0%      59167 ±  4%  stress-ng.time.involuntary_context_switches
  53645785           -12.0%   47213499 ±  2%  stress-ng.time.minor_page_faults
      4660           +24.6%       5806        stress-ng.time.percent_of_cpu_this_job_got
      2585           +27.8%       3305        stress-ng.time.system_time
    214.61           -14.7%     183.11        stress-ng.time.user_time
  10735595            -7.0%    9986470        stress-ng.time.voluntary_context_switches
 

Disclaimer:
Results have been estimated based on internal Intel analysis and are provided
for informational purposes only. Any difference in system hardware or software
design or configuration may affect actual performance.


-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
Re: [PATCH] rhashtable: use per-init-site lockdep classes for bucket locks
Posted by Quanye Yang 1 month ago
Sent with Proton Mail secure email.

On Friday, August 28th, 2026 at AM 8:54, kernel test robot
<yi1.lai@intel.com> wrote:

>
> Hello,
>
> kernel test robot noticed a 12.5% regression of stress-ng.shm-sysv.ops_per_sec on:
>
>
> commit: 62d8460a4e7a3ee028e5134d86169001490e7a60 ("[PATCH] rhashtable: use per-init-site lockdep classes for bucket locks")
> url: https://github.com/intel-lab-lkp/linux/commits/quanyeyang-via-B4-Relay/rhashtable-use-per-init-site-lockdep-classes-for-bucket-locks/20260815-014140
> patch link: https://lore.kernel.org/all/20260801-fix-rhashtable-bucket-lockdep-v1-1-15a0f8ae094c@gmail.com/
> patch subject: [PATCH] rhashtable: use per-init-site lockdep classes for bucket locks
>
> testcase: stress-ng
> config: x86_64-rhel-9.4
> compiler: gcc-14
> test machine: 224 threads 2 sockets Intel(R) Xeon(R) Platinum 8480CTDX (Sapphire Rapids) with 256G memory
> parameters:
>
> 	nr_threads: 100%
> 	testtime: 60s
> 	test: shm-sysv
> 	cpufreq_governor: performance
>
>
> If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
> | Reported-by: kernel test robot <yi1.lai@intel.com>
> | Closes: https://lore.kernel.org/oe-lkp/202608280842.861e5949-lkp@intel.com
>
>
> Details are as below:
> -------------------------------------------------------------------------------------------------->
>
>
> The kernel config and materials to reproduce are available at:
> https://download.01.org/0day-ci/archive/20260828/202608280842.861e5949-lkp@intel.com
>
> =========================================================================================
> compiler/cpufreq_governor/kconfig/nr_threads/rootfs/tbox_group/test/testcase/testtime:
>   gcc-14/performance/x86_64-rhel-9.4/100%/debian-13-x86_64-20250902.cgz/lkp-spr-r02/shm-sysv/stress-ng/60s
>
> commit:
>   0131b508c0 ("Merge tag 'ntfs-for-7.2-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/ntfs")
>   62d8460a4e ("[PATCH] rhashtable: use per-init-site lockdep classes for bucket locks")
>
> 0131b508c0e2489e 62d8460a4e7a3ee028e5134d861
> ---------------- ---------------------------
>     192413           +44.1%     277255        stress-ng.shm-sysv.nanosecs_per_shmat_call
>     349549           +24.2%     433996        stress-ng.shm-sysv.nanosecs_per_shmdt_call
>     174600           +51.9%     265191        stress-ng.shm-sysv.nanosecs_per_shmget_call
>     793610           -12.5%     694260        stress-ng.shm-sysv.ops
>      13236           -12.5%      11578        stress-ng.shm-sysv.ops_per_sec
>      65737           -10.0%      59167 ±  4%  stress-ng.time.involuntary_context_switches
>   53645785           -12.0%   47213499 ±  2%  stress-ng.time.minor_page_faults
>       4660           +24.6%       5806        stress-ng.time.percent_of_cpu_this_job_got
>       2585           +27.8%       3305        stress-ng.time.system_time
>     214.61           -14.7%     183.11        stress-ng.time.user_time
>   10735595            -7.0%    9986470        stress-ng.time.voluntary_context_switches
>
>
> Disclaimer:
> Results have been estimated based on internal Intel analysis and are provided
> for informational purposes only. Any difference in system hardware or software
> design or configuration may affect actual performance.
>
>
> --
> 0-DAY CI Kernel Test Service
> https://github.com/intel/lkp-tests/wiki
>
>
>
Thanks for the report.

This v1 was withdrawn after the subsequent discussion and was never
merged. I do not plan to resend this approach, so no separate fix will
be submitted.

The regression is likely caused by the unconditional bucket_lock_key
pointer changing the size and cacheline layout of struct rhashtable in
a configuration with CONFIG_DEBUG_LOCK_ALLOC disabled.

Thanks for the testing.
Re: [PATCH] rhashtable: use per-init-site lockdep classes for bucket locks
Posted by kernel test robot 1 month, 2 weeks ago
Hi quanyeyang,

kernel test robot noticed the following build warnings:

[auto build test WARNING on 0131b508c0e2489eac6e121135988f6eeb716f19]

url:    https://github.com/intel-lab-lkp/linux/commits/quanyeyang-via-B4-Relay/rhashtable-use-per-init-site-lockdep-classes-for-bucket-locks/20260815-014140
base:   0131b508c0e2489eac6e121135988f6eeb716f19
patch link:    https://lore.kernel.org/r/20260801-fix-rhashtable-bucket-lockdep-v1-1-15a0f8ae094c%40gmail.com
patch subject: [PATCH] rhashtable: use per-init-site lockdep classes for bucket locks
config: alpha-allmodconfig (https://download.01.org/0day-ci/archive/20260815/202608150357.9LheVOQg-lkp@intel.com/config)
compiler: alpha-linux-gcc (GCC) 16.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260815/202608150357.9LheVOQg-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202608150357.9LheVOQg-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> Warning: lib/rhashtable.c:1170 function parameter 'mutex_key' not described in '__rhashtable_init'
>> Warning: lib/rhashtable.c:1170 function parameter 'bucket_key' not described in '__rhashtable_init'
   Warning: lib/rhashtable.c:1170 expecting prototype for rhashtable_init(). Prototype was for __rhashtable_init() instead
>> Warning: lib/rhashtable.c:1247 function parameter 'mutex_key' not described in '__rhltable_init'
>> Warning: lib/rhashtable.c:1247 function parameter 'bucket_key' not described in '__rhltable_init'
   Warning: lib/rhashtable.c:1247 expecting prototype for rhltable_init(). Prototype was for __rhltable_init() instead

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki