[PATCH 0/1] rhashtable: fix fs_reclaim circular dep in free_and_destroy

From: Mikhail Gavrilov

Date: Wed Apr 22 2026 - 17:39:14 EST


Hi all,

This fixes a lockdep "possible circular locking dependency detected"
between fs_reclaim and the rhashtable &ht->mutex class that surfaces
on kernels built from vfs-7.1-rc1.xattr or later. The cycle is created
by the simple_xattrs rhashtable conversion (commit b32c4a213698
"xattr: add rhashtable-based simple_xattr infrastructure") and its
per-subsystem adaptations in shmem (52b364fed6e1), kernfs (5bd97f5c5f24),
and pidfs (50704c391fbf), which made rhashtable_free_and_destroy()
reachable from evict() under the dcache shrinker. The deferred rehash
worker provides the forward edge (&ht->mutex -> fs_reclaim), and the
teardown path under fs_reclaim provides the reverse edge
(fs_reclaim -> &ht->mutex). Full splat and analysis are in the patch's
commit message.

The fix is in rhashtable_free_and_destroy() rather than in the three
simple_xattrs callers because:

(a) three callers are affected, a library fix closes all of them at
once;

(b) after cancel_work_sync() returns, the rehash worker is quiesced
and the function's documented contract already requires the
caller to guarantee no concurrent operations -- so the mutex
protects nothing and can just be removed.

A review of lib/rhashtable.c confirms that this is the only site
where &ht->mutex is acquired from a path reachable under fs_reclaim;
the deferred worker is the only other acquisition site and it is the
forward edge. Removing the acquisition therefore eliminates the class
cycle entirely.

The splat was observed organically on my workstation at ~35h uptime
under normal mixed workload with CONFIG_PROVE_LOCKING=y. Attempts at
synthetic reproduction within a few-minute window (tmpfs and kernfs
zombies, ~60k reclaim-path executions of simple_xattr_ht_free()) did
not trip lockdep, consistent with the rare coincidence-of-edges
profile of the bug; the forward edge is already present in
/proc/lockdep on idle systems via rht_deferred_worker, so verification
of the fix is by absence of the splat on a patched kernel under
extended normal workload.

Thanks,
Mikhail

Mikhail Gavrilov (1):
rhashtable: drop ht->mutex in rhashtable_free_and_destroy()

lib/rhashtable.c | 23 +++++++++++++++++------
1 file changed, 17 insertions(+), 6 deletions(-)

--
2.54.0