[PATCH 3/4] kernfs: Avoid namespace dereference in d_revalidate()
From: Shakeel Butt
Date: Fri Aug 21 2026 - 01:09:10 EST
Commit 1fe989e1c42a ("kernfs: use namespace id instead of pointer for
hashing and comparison") changed dentry revalidation to compare namespace
IDs along with the comparisons that determine visible directory ordering.
Dereferencing a namespace tag that kernfs_rename_ns() can replace is not
suitable once dentry revalidation stops taking kernfs_rwsem. Use pointer
equality for this non-user-visible equality check instead. Namespace IDs
uniquely identify namespace objects, so pointer and ID equality cannot
disagree for valid tags. Hashing and directory ordering continue to use
IDs.
kn->ns becomes a lockless read in the next commit, so mark both sides of
it now. The read is in kernfs_dop_revalidate(); the stores that can run
while the node is visible are the two in kernfs_rename_ns(). The remaining
stores, in kernfs_create_dir_ns(), kernfs_create_empty_dir() and
kernfs_create_link(), all precede kernfs_add_one() and need no marking.
Signed-off-by: Shakeel Butt <shakeel.butt@xxxxxxxxx>
---
fs/kernfs/dir.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index 541bb5525437..27949b0e027c 100644
--- a/fs/kernfs/dir.c
+++ b/fs/kernfs/dir.c
@@ -1226,7 +1226,7 @@ static int kernfs_dop_revalidate(struct inode *dir, const struct qstr *name,
/* The kernfs node has been moved to a different namespace */
if (kn_parent && kernfs_ns_enabled(kn_parent) &&
- kernfs_ns_id(kernfs_info(dir->i_sb)->ns) != kernfs_ns_id(kn->ns))
+ kernfs_info(dir->i_sb)->ns != READ_ONCE(kn->ns))
goto out_bad;
up_read(&root->kernfs_rwsem);
@@ -1873,7 +1873,7 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent,
rcu_assign_pointer(kn->__parent, new_parent);
- kn->ns = new_ns;
+ WRITE_ONCE(kn->ns, new_ns);
if (new_name)
rcu_assign_pointer(kn->name, new_name);
@@ -1881,7 +1881,7 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent,
kernfs_put(old_parent);
} else {
/* name assignment is RCU protected, parent is the same */
- kn->ns = new_ns;
+ WRITE_ONCE(kn->ns, new_ns);
if (new_name)
rcu_assign_pointer(kn->name, new_name);
}
--
2.53.0-Meta