* [PATCH] fs/dcache: annotate the lockless d_unhashed() check in retain_dentry()
@ 2026-10-12 13:22 Nguyen Ngoc Thang
2026-10-12 14:03 ` Jan Kara
2026-10-21 11:57 ` Christian Brauner
0 siblings, 2 replies; 3+ messages in thread
From: Nguyen Ngoc Thang @ 2026-10-12 13:22 UTC (permalink / raw)
To: viro, brauner, jack
Cc: linux-fsdevel, linux-kernel, Nguyen Ngoc Thang,
syzbot+1cfd29c242c7cd26da02
KCSAN reports a data race between __d_drop() clearing d_hash.pprev
and the d_unhashed() test in retain_dentry(), reached from fast_dput()
without ->d_lock held:
BUG: KCSAN: data-race in dentry_kill / fast_dput
write to 0xffff888107394e50 of 8 bytes by task 3667 on cpu 0:
__d_drop fs/dcache.c:578 [inline]
dentry_kill+0x139/0x500 fs/dcache.c:824
finish_dput+0x16/0x1d0 fs/dcache.c:1001
dput+0x48/0x50 fs/dcache.c:1042
lookup_one_qstr_excl+0x156/0x240
filename_unlinkat+0x149/0x410
read to 0xffff888107394e50 of 8 bytes by task 3668 on cpu 1:
hlist_bl_unhashed include/linux/list_bl.h:54 [inline]
d_unhashed include/linux/dcache.h:396 [inline]
retain_dentry fs/dcache.c:872 [inline]
fast_dput+0x64/0x300 fs/dcache.c:971
dput+0x1f/0x50 fs/dcache.c:1040
handle_mounts fs/namei.c:1753 [inline]
step_into_slowpath+0x38c/0x4c0 fs/namei.c:2104
path_lookupat+0x2eb/0x4c0
do_readlinkat+0x74/0x2f0
value changed: 0xffff8882376dc230 -> 0x0000000000000000
The race is intentional. As the comment above retain_dentry() says,
without ->d_lock the predicates are not stable, and it is enough that
the dentry was hashed at some point after the reference was dropped.
If the lockless reader sees a stale "hashed" value, the dentry is kept
with a zero refcount, exactly as if it had been dropped just after the
check. If it sees "unhashed", it takes ->d_lock and rechecks. A single
aligned pointer load cannot tear, so neither outcome is harmful.
Mark the read with data_race() to document this and silence KCSAN.
No functional change.
Reproduced with the syzbot C reproducer on a KCSAN kernel in QEMU;
with this patch the dentry_kill race no longer shows up.
Reported-by: syzbot+1cfd29c242c7cd26da02@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=1cfd29c242c7cd26da02
Signed-off-by: Nguyen Ngoc Thang <ngocthang2710.1999@gmail.com>
---
fs/dcache.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/fs/dcache.c b/fs/dcache.c
index 1b1a81f10da6..3eb3d7e7ab0f 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -868,8 +868,9 @@ static inline bool retain_dentry(struct dentry *dentry, bool locked)
smp_rmb();
d_flags = READ_ONCE(dentry->d_flags);
- // Unreachable? Nobody would be able to look it up, no point retaining
- if (unlikely(d_unhashed(dentry)))
+ // Unreachable? Nobody would be able to look it up, no point retaining.
+ // Racy when !locked: a stale answer only costs a recheck under ->d_lock.
+ if (unlikely(data_race(d_unhashed(dentry))))
return false;
// Same if it's disconnected
--
2.43.0
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] fs/dcache: annotate the lockless d_unhashed() check in retain_dentry()
2026-10-12 13:22 [PATCH] fs/dcache: annotate the lockless d_unhashed() check in retain_dentry() Nguyen Ngoc Thang
@ 2026-10-12 14:03 ` Jan Kara
2026-10-21 11:57 ` Christian Brauner
1 sibling, 0 replies; 3+ messages in thread
From: Jan Kara @ 2026-10-12 14:03 UTC (permalink / raw)
To: Nguyen Ngoc Thang
Cc: viro, brauner, jack, linux-fsdevel, linux-kernel,
syzbot+1cfd29c242c7cd26da02
On Mon 12-10-26 20:22:18, Nguyen Ngoc Thang wrote:
> KCSAN reports a data race between __d_drop() clearing d_hash.pprev
> and the d_unhashed() test in retain_dentry(), reached from fast_dput()
> without ->d_lock held:
>
> BUG: KCSAN: data-race in dentry_kill / fast_dput
>
> write to 0xffff888107394e50 of 8 bytes by task 3667 on cpu 0:
> __d_drop fs/dcache.c:578 [inline]
> dentry_kill+0x139/0x500 fs/dcache.c:824
> finish_dput+0x16/0x1d0 fs/dcache.c:1001
> dput+0x48/0x50 fs/dcache.c:1042
> lookup_one_qstr_excl+0x156/0x240
> filename_unlinkat+0x149/0x410
>
> read to 0xffff888107394e50 of 8 bytes by task 3668 on cpu 1:
> hlist_bl_unhashed include/linux/list_bl.h:54 [inline]
> d_unhashed include/linux/dcache.h:396 [inline]
> retain_dentry fs/dcache.c:872 [inline]
> fast_dput+0x64/0x300 fs/dcache.c:971
> dput+0x1f/0x50 fs/dcache.c:1040
> handle_mounts fs/namei.c:1753 [inline]
> step_into_slowpath+0x38c/0x4c0 fs/namei.c:2104
> path_lookupat+0x2eb/0x4c0
> do_readlinkat+0x74/0x2f0
>
> value changed: 0xffff8882376dc230 -> 0x0000000000000000
>
> The race is intentional. As the comment above retain_dentry() says,
> without ->d_lock the predicates are not stable, and it is enough that
> the dentry was hashed at some point after the reference was dropped.
> If the lockless reader sees a stale "hashed" value, the dentry is kept
> with a zero refcount, exactly as if it had been dropped just after the
> check. If it sees "unhashed", it takes ->d_lock and rechecks. A single
> aligned pointer load cannot tear, so neither outcome is harmful.
>
> Mark the read with data_race() to document this and silence KCSAN.
> No functional change.
>
> Reproduced with the syzbot C reproducer on a KCSAN kernel in QEMU;
> with this patch the dentry_kill race no longer shows up.
>
> Reported-by: syzbot+1cfd29c242c7cd26da02@syzkaller.appspotmail.com
> Closes: https://syzkaller.appspot.com/bug?extid=1cfd29c242c7cd26da02
> Signed-off-by: Nguyen Ngoc Thang <ngocthang2710.1999@gmail.com>
Looks good. Feel free to add:
Reviewed-by: Jan Kara <jack@suse.cz>
Honza
> ---
> fs/dcache.c | 5 +++--
> 1 file changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/fs/dcache.c b/fs/dcache.c
> index 1b1a81f10da6..3eb3d7e7ab0f 100644
> --- a/fs/dcache.c
> +++ b/fs/dcache.c
> @@ -868,8 +868,9 @@ static inline bool retain_dentry(struct dentry *dentry, bool locked)
> smp_rmb();
> d_flags = READ_ONCE(dentry->d_flags);
>
> - // Unreachable? Nobody would be able to look it up, no point retaining
> - if (unlikely(d_unhashed(dentry)))
> + // Unreachable? Nobody would be able to look it up, no point retaining.
> + // Racy when !locked: a stale answer only costs a recheck under ->d_lock.
> + if (unlikely(data_race(d_unhashed(dentry))))
> return false;
>
> // Same if it's disconnected
> --
> 2.43.0
>
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] fs/dcache: annotate the lockless d_unhashed() check in retain_dentry()
2026-10-12 13:22 [PATCH] fs/dcache: annotate the lockless d_unhashed() check in retain_dentry() Nguyen Ngoc Thang
2026-10-12 14:03 ` Jan Kara
@ 2026-10-21 11:57 ` Christian Brauner
1 sibling, 0 replies; 3+ messages in thread
From: Christian Brauner @ 2026-10-21 11:57 UTC (permalink / raw)
To: viro, jack, Nguyen Ngoc Thang
Cc: linux-fsdevel, linux-kernel, syzbot+1cfd29c242c7cd26da02
On Mon, 12 Oct 2026 20:22:18 +0700, Nguyen Ngoc Thang wrote:
> fs/dcache: annotate the lockless d_unhashed() check in retain_dentry()
Applied to the vfs-7.5.misc branch of the vfs/vfs.git tree.
Patches in the vfs-7.5.misc branch should appear in linux-next soon.
Please report any outstanding bugs that were missed during review in a
new review to the original patch series allowing us to drop it.
It's encouraged to provide Acked-bys and Reviewed-bys even though the
patch has now been applied. If possible patch trailers will be updated.
Note that commit hashes shown below are subject to change due to rebase,
trailer updates or similar. If in doubt, please check the listed branch.
tree: https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git
branch: vfs-7.5.misc
[1/1] fs/dcache: annotate the lockless d_unhashed() check in retain_dentry()
https://git.kernel.org/vfs/vfs/c/5a298355d8e2
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-10-21 11:57 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-12 13:22 [PATCH] fs/dcache: annotate the lockless d_unhashed() check in retain_dentry() Nguyen Ngoc Thang
2026-10-12 14:03 ` Jan Kara
2026-10-21 11:57 ` Christian Brauner
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®