[PATCH 3/4] kernfs: Avoid namespace dereference in d_revalidate()

Shakeel Butt <[email protected]>
Newsgroups org.kernel.vger.cgroups,dev.linux.lists.driver-core,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
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 <[email protected]>
---
 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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.