diff --git a/MAINTAINERS b/MAINTAINERS
index 9545555..54b5106 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -14405,6 +14405,7 @@ S:	Supported
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core.git
 F:	fs/kernfs/
 F:	include/linux/kernfs.h
+F:	tools/testing/selftests/filesystems/kernfs_test.c
 
 KEXEC
 M:	Andrew Morton <akpm@linux-foundation.org>
diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index 943d6ee..324d61a 100644
--- a/fs/kernfs/dir.c
+++ b/fs/kernfs/dir.c
@@ -30,6 +30,8 @@ static char kernfs_pr_cont_buf[PATH_MAX];	/* protected by pr_cont_lock */
 
 #define rb_to_kn(X) rb_entry((X), struct kernfs_node, rb)
 
+static void kernfs_activate_one(struct kernfs_node *kn);
+
 static bool __kernfs_active(struct kernfs_node *kn)
 {
 	return atomic_read(&kn->active) >= 0;
@@ -736,13 +738,19 @@ struct kernfs_node *kernfs_new_node(struct kernfs_node *parent,
 {
 	struct kernfs_node *kn;
 
-	if (parent->mode & S_ISGID) {
+	/*
+	 * The mode and the gid below are read unlocked on purpose: they feed
+	 * a node that does not exist yet, so nothing orders a racing chmod or
+	 * chown against this creation.
+	 */
+	if (READ_ONCE(parent->mode) & S_ISGID) {
 		/* this code block imitates inode_init_owner() for
 		 * kernfs
 		 */
+		struct kernfs_iattrs *attrs = READ_ONCE(parent->iattr);
 
-		if (parent->iattr)
-			gid = parent->iattr->ia_gid;
+		if (attrs)
+			gid = READ_ONCE(attrs->ia_gid);
 
 		if (flags & KERNFS_DIR)
 			mode |= S_ISGID;
@@ -855,7 +863,6 @@ int kernfs_add_one(struct kernfs_node *kn)
 	}
 
 	up_write(&root->kernfs_iattr_rwsem);
-	up_write(&root->kernfs_rwsem);
 
 	/*
 	 * Activate the new node unless CREATE_DEACTIVATED is requested.
@@ -863,9 +870,15 @@ int kernfs_add_one(struct kernfs_node *kn)
 	 * activating the node with kernfs_activate().  A node which hasn't
 	 * been activated is not visible to userland and its removal won't
 	 * trigger deactivation.
+	 *
+	 * @kn has no children yet, so kernfs_activate() would walk only @kn.
+	 * Do it here rather than dropping the write lock and taking it again
+	 * for every new node.
 	 */
-	if (!(kernfs_root(kn)->flags & KERNFS_ROOT_CREATE_DEACTIVATED))
-		kernfs_activate(kn);
+	if (!(root->flags & KERNFS_ROOT_CREATE_DEACTIVATED))
+		kernfs_activate_one(kn);
+
+	up_write(&root->kernfs_rwsem);
 	return 0;
 
 out_unlock:
@@ -1171,23 +1184,18 @@ struct kernfs_node *kernfs_create_empty_dir(struct kernfs_node *parent,
 static int kernfs_dop_revalidate(struct inode *dir, const struct qstr *name,
 				 struct dentry *dentry, unsigned int flags)
 {
-	struct kernfs_node *kn, *parent;
-	struct kernfs_root *root;
+	struct kernfs_node *parent = dir->i_private;
+	struct kernfs_node *kn;
+	const char *kn_name;
 
 	if (flags & LOOKUP_RCU)
 		return -ECHILD;
 
 	/* Negative hashed dentry? */
 	if (d_really_is_negative(dentry)) {
-		/* If the kernfs parent node has changed discard and
-		 * proceed to ->lookup.
-		 *
-		 * There's nothing special needed here when getting the
-		 * dentry parent, even if a concurrent rename is in
-		 * progress. That's because the dentry is negative so
-		 * it can only be the target of the rename and it will
-		 * be doing a d_move() not a replace. Consequently the
-		 * dentry d_parent won't change over the d_move().
+		/*
+		 * If the kernfs parent node has changed discard and proceed to
+		 * ->lookup.
 		 *
 		 * Also kernfs negative dentries transitioning from
 		 * negative to positive during revalidate won't happen
@@ -1195,50 +1203,41 @@ static int kernfs_dop_revalidate(struct inode *dir, const struct qstr *name,
 		 * changes and the lookup re-done so that a new positive
 		 * dentry can be properly created.
 		 */
-		root = kernfs_root_from_sb(dentry->d_sb);
-		down_read(&root->kernfs_rwsem);
-		parent = kernfs_dentry_node(dentry->d_parent);
-		if (parent) {
-			if (kernfs_dir_changed(parent, dentry)) {
-				up_read(&root->kernfs_rwsem);
-				return 0;
-			}
-		}
-		up_read(&root->kernfs_rwsem);
-
-		/* The kernfs parent node hasn't changed, leave the
-		 * dentry negative and return success.
-		 */
-		return 1;
+		return !kernfs_dir_changed(parent, dentry);
 	}
 
 	kn = kernfs_dentry_node(dentry);
-	root = kernfs_root(kn);
-	down_read(&root->kernfs_rwsem);
+
+	guard(rcu)();
 
 	/* The kernfs node has been deactivated */
-	if (!kernfs_active(kn))
-		goto out_bad;
+	if (!__kernfs_active(kn))
+		return 0;
 
-	parent = kernfs_parent(kn);
 	/* The kernfs node has been moved? */
-	if (kernfs_dentry_node(dentry->d_parent) != parent)
-		goto out_bad;
+	if (kernfs_parent(kn) != parent)
+		return 0;
 
 	/* The kernfs node has been renamed */
-	if (strcmp(dentry->d_name.name, kernfs_rcu_name(kn)) != 0)
-		goto out_bad;
+	kn_name = kernfs_rcu_name(kn);
+	if (name->len != strlen(kn_name) ||
+	    memcmp(name->name, kn_name, name->len))
+		return 0;
 
-	/* The kernfs node has been moved to a different namespace */
-	if (parent && kernfs_ns_enabled(parent) &&
-	    kernfs_ns_id(kernfs_info(dentry->d_sb)->ns) != kernfs_ns_id(kn->ns))
-		goto out_bad;
+	/*
+	 * The kernfs node has been moved to a different namespace.
+	 *
+	 * KERNFS_NS is set by kernfs_enable_ns() while @parent still has no
+	 * children, so it cannot change while a child of @parent is being
+	 * revalidated. The other bits in that word, KERNFS_ACTIVATED and
+	 * KERNFS_REMOVING, are updated under kernfs_rwsem and are not read
+	 * here, so racing with them is intentional and harmless.
+	 */
+	if (data_race(kernfs_ns_enabled(parent)) &&
+	    kernfs_info(dir->i_sb)->ns != READ_ONCE(kn->ns))
+		return 0;
 
-	up_read(&root->kernfs_rwsem);
 	return 1;
-out_bad:
-	up_read(&root->kernfs_rwsem);
-	return 0;
 }
 
 const struct dentry_operations kernfs_dops = {
@@ -1820,14 +1819,20 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent,
 		     const char *new_name, const struct ns_common *new_ns)
 {
 	struct kernfs_node *old_parent;
+	const char *dup_name = NULL;
+	const char *put_name = NULL;
 	struct kernfs_root *root;
 	const char *old_name;
+	bool reparent;
 	int error;
 
 	/* can't move or rename root */
 	if (!rcu_access_pointer(kn->__parent))
 		return -EINVAL;
 
+	if (new_name)
+		dup_name = kstrdup_const(new_name, GFP_KERNEL);
+
 	root = kernfs_root(kn);
 	down_write(&root->kernfs_rwsem);
 
@@ -1859,9 +1864,10 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent,
 	/* rename kernfs_node */
 	if (strcmp(old_name, new_name) != 0) {
 		error = -ENOMEM;
-		new_name = kstrdup_const(new_name, GFP_KERNEL);
-		if (!new_name)
+		if (!dup_name)
 			goto out;
+		new_name = dup_name;
+		dup_name = NULL;
 	} else {
 		new_name = NULL;
 	}
@@ -1871,35 +1877,39 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent,
 	 */
 	kernfs_unlink_sibling(kn);
 
-	/* rename_lock protects ->parent accessors */
-	if (old_parent != new_parent) {
+	reparent = old_parent != new_parent;
+	if (reparent)
 		kernfs_get(new_parent);
-		write_lock_irq(&root->kernfs_rename_lock);
 
+	/*
+	 * kernfs_rename_lock protects ->__parent, ->ns and ->name, so take it
+	 * even when the parent does not change.
+	 */
+	write_lock_irq(&root->kernfs_rename_lock);
+
+	if (reparent)
 		rcu_assign_pointer(kn->__parent, new_parent);
+	WRITE_ONCE(kn->ns, new_ns);
+	if (new_name)
+		rcu_assign_pointer(kn->name, new_name);
 
-		kn->ns = new_ns;
-		if (new_name)
-			rcu_assign_pointer(kn->name, new_name);
+	write_unlock_irq(&root->kernfs_rename_lock);
 
-		write_unlock_irq(&root->kernfs_rename_lock);
+	if (reparent)
 		kernfs_put(old_parent);
-	} else {
-		/* name assignment is RCU protected, parent is the same */
-		kn->ns = new_ns;
-		if (new_name)
-			rcu_assign_pointer(kn->name, new_name);
-	}
 
 	kn->hash = kernfs_name_hash(new_name ?: old_name, kn->ns);
 	kernfs_link_sibling(kn);
 
 	if (new_name && !is_kernel_rodata((unsigned long)old_name))
-		kfree_rcu_mightsleep(old_name);
+		put_name = old_name;
 
 	error = 0;
  out:
 	up_write(&root->kernfs_rwsem);
+	kfree_const(dup_name);
+	if (put_name)
+		kfree_rcu_mightsleep(put_name);
 	return error;
 }
 
@@ -1909,33 +1919,49 @@ static int kernfs_dir_fop_release(struct inode *inode, struct file *filp)
 	return 0;
 }
 
+/*
+ * Find where a listing left off.  @resumed says whether @pos is still that
+ * entry; if not, the search falls back to @hash, keyed by @name if given.
+ */
 static struct kernfs_node *kernfs_dir_pos(const struct ns_common *ns,
-	struct kernfs_node *parent, loff_t hash, struct kernfs_node *pos)
+	struct kernfs_node *parent, loff_t hash, struct kernfs_node *pos,
+	const char *name, bool *resumed)
 {
+	if (resumed)
+		*resumed = false;
 	if (pos) {
+		/*
+		 * A rename keeps the hash if the new name hashes the same, so
+		 * check @name too.  Otherwise the caller would step over the
+		 * entry now sitting where @pos used to be.
+		 */
 		int valid = kernfs_active(pos) &&
 			rcu_access_pointer(pos->__parent) == parent &&
-			hash == pos->hash;
+			hash == pos->hash &&
+			(!name || !strcmp(name, kernfs_rcu_name(pos)));
 		kernfs_put(pos);
 		if (!valid)
 			pos = NULL;
+		else if (resumed)
+			*resumed = true;
 	}
 	if (!pos && (hash > 1) && (hash < INT_MAX)) {
 		struct rb_node *node = parent->dir.children.rb_node;
-		u64 ns_id = kernfs_ns_id(ns);
+
+		/*
+		 * Keep a node only on the way left, so the search ends on the
+		 * first entry after the key.  An empty @name sorts before all
+		 * entries sharing the hash, so it lands on the first of them.
+		 */
 		while (node) {
-			pos = rb_to_kn(node);
+			struct kernfs_node *kn = rb_to_kn(node);
 
-			if (hash < pos->hash)
+			if (kernfs_name_compare(hash, name ?: "", ns, kn) < 0) {
+				pos = kn;
 				node = node->rb_left;
-			else if (hash > pos->hash)
+			} else {
 				node = node->rb_right;
-			else if (ns_id < kernfs_ns_id(pos->ns))
-				node = node->rb_left;
-			else if (ns_id > kernfs_ns_id(pos->ns))
-				node = node->rb_right;
-			else
-				break;
+			}
 		}
 	}
 	/* Skip over entries which are dying/dead or in the wrong namespace */
@@ -1951,10 +1977,14 @@ static struct kernfs_node *kernfs_dir_pos(const struct ns_common *ns,
 }
 
 static struct kernfs_node *kernfs_dir_next_pos(const struct ns_common *ns,
-	struct kernfs_node *parent, ino_t ino, struct kernfs_node *pos)
+	struct kernfs_node *parent, loff_t hash, struct kernfs_node *pos,
+	const char *name)
 {
-	pos = kernfs_dir_pos(ns, parent, ino, pos);
-	if (pos) {
+	bool resumed;
+
+	pos = kernfs_dir_pos(ns, parent, hash, pos, name, &resumed);
+	/* Step over @pos only if it survived; @name finds the spot if not. */
+	if (pos && resumed) {
 		do {
 			struct rb_node *node = rb_next(&pos->rb);
 			if (!node)
@@ -1972,34 +2002,55 @@ static int kernfs_fop_readdir(struct file *file, struct dir_context *ctx)
 	struct dentry *dentry = file->f_path.dentry;
 	struct kernfs_node *parent = kernfs_dentry_node(dentry);
 	struct kernfs_node *pos = file->private_data;
+	char *name __free(kfree) = NULL;
 	struct kernfs_root *root;
 	const struct ns_common *ns = NULL;
 
 	if (!dir_emit_dots(file, ctx))
 		return 0;
 
+	/*
+	 * One buffer for the call, holding the name of the entry the listing
+	 * is on.  PATH_MAX: kernfs bounds no single name.
+	 */
+	name = kmalloc(PATH_MAX, GFP_KERNEL);
+	if (!name)
+		return -ENOMEM;
+
 	root = kernfs_root(parent);
 	down_read(&root->kernfs_rwsem);
 
 	if (kernfs_ns_enabled(parent))
 		ns = kernfs_info(dentry->d_sb)->ns;
 
-	for (pos = kernfs_dir_pos(ns, parent, ctx->pos, pos);
+	for (pos = kernfs_dir_pos(ns, parent, ctx->pos, pos, NULL, NULL);
 	     pos;
-	     pos = kernfs_dir_next_pos(ns, parent, ctx->pos, pos)) {
-		const char *name = kernfs_rcu_name(pos);
+	     pos = kernfs_dir_next_pos(ns, parent, ctx->pos, pos, name)) {
 		unsigned int type = fs_umode_to_dtype(pos->mode);
-		int len = strlen(name);
 		ino_t ino = kernfs_ino(pos);
+		int len;
+
+		/*
+		 * The copy is also the resume key, so a truncated name would
+		 * resume here again.  getname() caps a path, so only an
+		 * in-kernel caller can get here; end the listing instead.
+		 */
+		len = strscpy(name, kernfs_rcu_name(pos), PATH_MAX);
+		if (WARN_ON_ONCE(len < 0))
+			break;
 
 		ctx->pos = pos->hash;
 		file->private_data = pos;
 		kernfs_get(pos);
 
-		if (!dir_emit(ctx, name, len, ino, type)) {
-			up_read(&root->kernfs_rwsem);
+		/*
+		 * dir_emit() can fault, so run it unlocked.  @pos is pinned
+		 * above and kernfs_dir_pos() rechecks it on the way back.
+		 */
+		up_read(&root->kernfs_rwsem);
+		if (!dir_emit(ctx, name, len, ino, type))
 			return 0;
-		}
+		down_read(&root->kernfs_rwsem);
 	}
 	up_read(&root->kernfs_rwsem);
 	file->private_data = NULL;
diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c
index 8e0e90c..cca9f83 100644
--- a/fs/kernfs/file.c
+++ b/fs/kernfs/file.c
@@ -525,18 +525,31 @@ out_unlock:
 static int kernfs_get_open_node(struct kernfs_node *kn,
 				struct kernfs_open_file *of)
 {
-	struct kernfs_open_node *on;
+	struct kernfs_open_node *on, *new_on = NULL;
 	struct mutex *mutex;
 
+	/*
+	 * Peek without the mutex: if nothing has this open, we will need a
+	 * node and can allocate before taking a mutex shared by every node
+	 * hashing to it.
+	 */
+	if (!rcu_access_pointer(kn->attr.open))
+		new_on = kzalloc_obj(*new_on);
+
 	mutex = kernfs_open_file_mutex_lock(kn);
 	on = kernfs_deref_open_node_locked(kn);
 
 	if (!on) {
 		/* not there, initialize a new one */
-		on = kzalloc_obj(*on);
+		on = new_on;
+		new_on = NULL;
 		if (!on) {
-			mutex_unlock(mutex);
-			return -ENOMEM;
+			/* the peek raced; rare, so allocate here */
+			on = kzalloc_obj(*on);
+			if (!on) {
+				mutex_unlock(mutex);
+				return -ENOMEM;
+			}
 		}
 		atomic_set(&on->event, 1);
 		init_waitqueue_head(&on->poll);
@@ -549,6 +562,7 @@ static int kernfs_get_open_node(struct kernfs_node *kn,
 		on->nr_to_release++;
 
 	mutex_unlock(mutex);
+	kfree(new_on);
 	return 0;
 }
 
@@ -904,9 +918,12 @@ static loff_t kernfs_fop_llseek(struct file *file, loff_t offset, int whence)
 
 static void kernfs_notify_workfn(struct work_struct *work)
 {
-	struct kernfs_node *kn;
+	char name_buf[NAME_MAX + 1];
 	struct kernfs_super_info *info;
+	struct kernfs_node *kn;
 	struct kernfs_root *root;
+	struct qstr name;
+	bool have_name;
 repeat:
 	/* pop one off the notify_list */
 	spin_lock_irq(&kernfs_notify_lock);
@@ -922,14 +939,20 @@ repeat:
 	root = kernfs_root(kn);
 	/* kick fsnotify */
 
+	/*
+	 * Sample the name once so kernfs_rwsem need not be held across the
+	 * loop.  A name that does not fit is reported without one; fsnotify()
+	 * takes the name as optional, so a watcher loses the name and not the
+	 * event.
+	 */
+	have_name = kernfs_name(kn, name_buf, sizeof(name_buf)) >= 0;
+	name = QSTR(name_buf);
+
 	down_read(&root->kernfs_supers_rwsem);
-	down_read(&root->kernfs_rwsem);
-	list_for_each_entry(info, &kernfs_root(kn)->supers, node) {
+	list_for_each_entry(info, &root->supers, node) {
 		struct kernfs_node *parent;
 		struct inode *p_inode = NULL;
-		const char *kn_name;
 		struct inode *inode;
-		struct qstr name;
 
 		/*
 		 * We want fsnotify_modify() on @kn but as the
@@ -941,15 +964,14 @@ repeat:
 		if (!inode)
 			continue;
 
-		kn_name = kernfs_rcu_name(kn);
-		name = QSTR(kn_name);
 		parent = kernfs_get_parent(kn);
 		if (parent) {
 			p_inode = ilookup(info->sb, kernfs_ino(parent));
 			if (p_inode) {
 				fsnotify(FS_MODIFY | FS_EVENT_ON_CHILD,
 					 inode, FSNOTIFY_EVENT_INODE,
-					 p_inode, &name, inode, 0);
+					 p_inode, have_name ? &name : NULL,
+					 inode, 0);
 				iput(p_inode);
 			}
 
@@ -962,7 +984,6 @@ repeat:
 		iput(inode);
 	}
 
-	up_read(&root->kernfs_rwsem);
 	up_read(&root->kernfs_supers_rwsem);
 	kernfs_put(kn);
 	goto repeat;
diff --git a/fs/kernfs/kernfs-internal.h b/fs/kernfs/kernfs-internal.h
index d0c68ec..f1e93b0 100644
--- a/fs/kernfs/kernfs-internal.h
+++ b/fs/kernfs/kernfs-internal.h
@@ -117,7 +117,14 @@ static inline bool kernfs_rename_is_locked(const struct kernfs_node *kn)
 
 static inline const char *kernfs_rcu_name(const struct kernfs_node *kn)
 {
-	return rcu_dereference_check(kn->name, kernfs_root_is_locked(kn));
+	/*
+	 * Like kernfs_node::__parent below, the name is only replaced under
+	 * both kernfs_root::kernfs_rwsem and kernfs_root::kernfs_rename_lock,
+	 * so either one keeps it, and the string it points at, stable.
+	 */
+	return rcu_dereference_check(kn->name,
+				     kernfs_root_is_locked(kn) ||
+				     kernfs_rename_is_locked(kn));
 }
 
 static inline struct kernfs_node *kernfs_parent(const struct kernfs_node *kn)
@@ -147,20 +154,19 @@ static inline struct kernfs_node *kernfs_dentry_node(struct dentry *dentry)
 static inline void kernfs_set_rev(struct kernfs_node *parent,
 				  struct dentry *dentry)
 {
-	dentry->d_time = parent->dir.rev;
+	WRITE_ONCE(dentry->d_time, READ_ONCE(parent->dir.rev));
 }
 
 static inline void kernfs_inc_rev(struct kernfs_node *parent)
 {
-	parent->dir.rev++;
+	lockdep_assert_held_write(&parent->dir.root->kernfs_rwsem);
+	WRITE_ONCE(parent->dir.rev, parent->dir.rev + 1);
 }
 
 static inline bool kernfs_dir_changed(struct kernfs_node *parent,
 				      struct dentry *dentry)
 {
-	if (parent->dir.rev != dentry->d_time)
-		return true;
-	return false;
+	return READ_ONCE(parent->dir.rev) != READ_ONCE(dentry->d_time);
 }
 
 extern const struct super_operations kernfs_sops;
diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c
index a573990..a0be784 100644
--- a/fs/kernfs/mount.c
+++ b/fs/kernfs/mount.c
@@ -124,22 +124,32 @@ static struct dentry *__kernfs_fh_to_dentry(struct super_block *sb,
 		return NULL;
 	}
 
-	kn = kernfs_find_and_get_node_by_id(info->root, id);
-	if (!kn)
-		return ERR_PTR(-ESTALE);
+	/*
+	 * Hold kernfs_rwsem across the lookup as well as kernfs_get_inode().
+	 * __kernfs_remove() deactivates the subtree and clears i_nlink on its
+	 * inodes under the write lock, so under the read lock either
+	 * kernfs_find_and_get_node_by_id() refuses the node, or the inode is
+	 * in the inode hash before the ilookup() pass goes looking for it.
+	 */
+	scoped_guard(rwsem_read, &info->root->kernfs_rwsem) {
+		kn = kernfs_find_and_get_node_by_id(info->root, id);
+		if (!kn)
+			return ERR_PTR(-ESTALE);
 
-	if (get_parent) {
-		struct kernfs_node *parent;
+		if (get_parent) {
+			struct kernfs_node *parent;
 
-		parent = kernfs_get_parent(kn);
+			parent = kernfs_get_parent(kn);
+			kernfs_put(kn);
+			kn = parent;
+			if (!kn)
+				return ERR_PTR(-ESTALE);
+		}
+
+		inode = kernfs_get_inode(sb, kn);
 		kernfs_put(kn);
-		kn = parent;
-		if (!kn)
-			return ERR_PTR(-ESTALE);
 	}
 
-	inode = kernfs_get_inode(sb, kn);
-	kernfs_put(kn);
 	return d_obtain_alias(inode);
 }
 
diff --git a/fs/kernfs/symlink.c b/fs/kernfs/symlink.c
index 90e2b32..3e53105 100644
--- a/fs/kernfs/symlink.c
+++ b/fs/kernfs/symlink.c
@@ -31,9 +31,20 @@ struct kernfs_node *kernfs_create_link(struct kernfs_node *parent,
 	kuid_t uid = GLOBAL_ROOT_UID;
 	kgid_t gid = GLOBAL_ROOT_GID;
 
-	if (target->iattr) {
-		uid = target->iattr->ia_uid;
-		gid = target->iattr->ia_gid;
+	/*
+	 * A symlink takes its owner from its target, so both fields have to
+	 * come from the same moment: read them under kernfs_iattr_rwsem, or
+	 * a chown of the target racing this could leave the link with the
+	 * old uid and the new gid.  The section ends before kernfs_add_one()
+	 * takes kernfs_rwsem.
+	 */
+	scoped_guard(rwsem_read, &kernfs_root(target)->kernfs_iattr_rwsem) {
+		struct kernfs_iattrs *attrs = READ_ONCE(target->iattr);
+
+		if (attrs) {
+			uid = attrs->ia_uid;
+			gid = attrs->ia_gid;
+		}
 	}
 
 	kn = kernfs_new_node(parent, name, S_IFLNK|0777, uid, gid, KERNFS_LINK);
diff --git a/tools/testing/selftests/filesystems/config b/tools/testing/selftests/filesystems/config
new file mode 100644
index 0000000..9f45bc4
--- /dev/null
+++ b/tools/testing/selftests/filesystems/config
@@ -0,0 +1,8 @@
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_PIDS=y
+CONFIG_FHANDLE=y
+CONFIG_NAMESPACES=y
+CONFIG_NET=y
+CONFIG_NET_NS=y
+CONFIG_INET=y
+CONFIG_SYSFS=y
diff --git a/tools/testing/selftests/filesystems/kernfs_test.c b/tools/testing/selftests/filesystems/kernfs_test.c
index 84c2b91..01cd58e 100644
--- a/tools/testing/selftests/filesystems/kernfs_test.c
+++ b/tools/testing/selftests/filesystems/kernfs_test.c
@@ -2,9 +2,23 @@
 #define _GNU_SOURCE
 #define __SANE_USERSPACE_TYPES__
 
+#include <dirent.h>
+#include <errno.h>
 #include <fcntl.h>
+#include <limits.h>
+#include <net/if.h>
+#include <sched.h>
+#include <signal.h>
 #include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/socket.h>
 #include <sys/stat.h>
+#include <sys/syscall.h>
 #include <sys/xattr.h>
 
 #include "kselftest_harness.h"
@@ -34,5 +48,1176 @@ TEST(kernfs_getxattr)
 	EXPECT_EQ(close(fd), 0);
 }
 
-TEST_HARNESS_MAIN
+/*
+ * Exercise the kernfs dentry cache: lookup, revalidation of positive and
+ * negative dentries, readdir and namespace tagging.
+ *
+ * These drive kernfs from kernel context rather than VFS create/unlink,
+ * which is what ->d_revalidate() exists for: writing cgroup.subtree_control
+ * adds and removes files in every child cgroup with no VFS operation
+ * touching those names.
+ */
+
+#define CG_SCRATCH	"kernfs_selftest"
+#define TEST_IFNAME	"kfstest0"
+
+/*
+ * Controllers that add a file to each child cgroup when enabled.  The probe
+ * file must be owned by the controller: cgroup_base_files[] entries such as
+ * cpu.stat exist in every cgroup regardless, and every file the cpu
+ * controller does own is behind a Kconfig symbol, so cpu is not usable here.
+ */
+static const struct {
+	const char *name;
+	const char *probe_file;
+} controllers[] = {
+	{ "memory",	"memory.current" },
+	{ "pids",	"pids.current" },
+};
+
+static int find_cgroup2_root(char *buf, size_t len)
+{
+	char line[PATH_MAX * 2];
+	FILE *f;
+	int ret = -1;
+
+	f = fopen("/proc/self/mounts", "re");
+	if (!f)
+		return -1;
+
+	while (fgets(line, sizeof(line), f)) {
+		char mnt[PATH_MAX], type[64];
+
+		/* Octal escaping can expand a path fourfold; bound both %s. */
+		if (sscanf(line, "%*s %4095s %63s", mnt, type) != 2)
+			continue;
+		if (strcmp(type, "cgroup2"))
+			continue;
+		if (strlen(mnt) >= len)
+			break;
+		strcpy(buf, mnt);
+		ret = 0;
+		break;
+	}
+
+	fclose(f);
+	return ret;
+}
+
+static int write_file(const char *path, const char *val)
+{
+	ssize_t len = strlen(val);
+	int fd, ret;
+
+	fd = open(path, O_WRONLY | O_CLOEXEC);
+	if (fd < 0)
+		return -1;
+	ret = write(fd, val, len) == len ? 0 : -1;
+	close(fd);
+	return ret;
+}
+
+static bool file_has_word(const char *path, const char *word)
+{
+	char buf[4096], *tok, *save;
+	bool found = false;
+	ssize_t n;
+	int fd;
+
+	fd = open(path, O_RDONLY | O_CLOEXEC);
+	if (fd < 0)
+		return false;
+	n = read(fd, buf, sizeof(buf) - 1);
+	close(fd);
+	if (n < 0)
+		return false;
+	buf[n] = '\0';
+
+	for (tok = strtok_r(buf, "\n ", &save); tok;
+	     tok = strtok_r(NULL, "\n ", &save)) {
+		if (!strcmp(tok, word)) {
+			found = true;
+			break;
+		}
+	}
+	return found;
+}
+
+static bool path_is_mounted(const char *path)
+{
+	char line[PATH_MAX * 2];
+	bool found = false;
+	FILE *f;
+
+	f = fopen("/proc/self/mounts", "re");
+	if (!f)
+		return false;
+	while (fgets(line, sizeof(line), f)) {
+		char mnt[PATH_MAX];
+
+		if (sscanf(line, "%*s %4095s", mnt) != 1)
+			continue;
+		if (!strcmp(mnt, path)) {
+			found = true;
+			break;
+		}
+	}
+	fclose(f);
+	return found;
+}
+
+/* Shared by the stress tests below. */
+static bool stress_deadline(const struct timespec *end)
+{
+	struct timespec now;
+
+	clock_gettime(CLOCK_MONOTONIC, &now);
+	return now.tv_sec > end->tv_sec ||
+	       (now.tv_sec == end->tv_sec && now.tv_nsec >= end->tv_nsec);
+}
+
+FIXTURE(kernfs_cgroup)
+{
+	char scratch[PATH_MAX];		/* <cg2>/kernfs_selftest.<pid> */
+	char child[PATH_MAX];		/* <scratch>/child */
+	char probe[PATH_MAX];		/* child's controller file */
+	char scratch_sc[PATH_MAX];	/* scratch's cgroup.subtree_control */
+	char root_sc[PATH_MAX];		/* root's cgroup.subtree_control */
+	char enable[32];		/* "+<controller>" */
+	char disable[32];		/* "-<controller>" */
+	char mnt[PATH_MAX];		/* our own mount, if we made one */
+	bool mounted;
+	bool enabled_at_root;
+};
+
+/* A cgroup stays busy briefly after its last task exits. */
+static void rmdir_retry(const char *path)
+{
+	int i;
+
+	for (i = 0; i < 500; i++) {
+		if (!rmdir(path) || errno != EBUSY)
+			return;
+		usleep(10000);
+	}
+}
+
+/*
+ * Undo whatever SETUP managed to do.  The harness skips TEARDOWN after a
+ * failed or skipped SETUP, so SETUP must call this before returning early.
+ */
+static void kernfs_cgroup_undo(FIXTURE_DATA(kernfs_cgroup) *self)
+{
+	rmdir_retry(self->child);
+	rmdir(self->scratch);
+	if (self->enabled_at_root)
+		write_file(self->root_sc, self->disable);
+	if (self->mounted) {
+		umount2(self->mnt, MNT_DETACH);
+		rmdir(self->mnt);
+	}
+	self->enabled_at_root = false;
+	self->mounted = false;
+}
+
+FIXTURE_SETUP(kernfs_cgroup)
+{
+	char root[PATH_MAX], ctl[PATH_MAX];
+	const char *probe_file = NULL;
+	size_t i;
+
+	if (geteuid())
+		SKIP(return, "test needs to run as root");
+
+	/*
+	 * A private mount namespace stops our mounts leaking, but does not
+	 * isolate the cgroup hierarchy: cgroup2 has one default hierarchy
+	 * however many times it is mounted.  The scratch cgroups live in the
+	 * host's and must be removed, not discarded with the namespace.
+	 */
+	if (unshare(CLONE_NEWNS))
+		SKIP(return, "unshare(CLONE_NEWNS): %s", strerror(errno));
+	if (mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL))
+		SKIP(return, "make / private: %s", strerror(errno));
+
+	/* Use an existing cgroup2 mount if there is one, else make our own. */
+	if (find_cgroup2_root(root, sizeof(root))) {
+		strcpy(self->mnt, "/tmp/kernfs_selftest_cg2.XXXXXX");
+		if (!mkdtemp(self->mnt))
+			SKIP(return, "mkdtemp: %s", strerror(errno));
+		if (mount("none", self->mnt, "cgroup2", 0, NULL)) {
+			rmdir(self->mnt);
+			SKIP(return, "mount cgroup2: %s", strerror(errno));
+		}
+		self->mounted = true;
+		strcpy(root, self->mnt);
+	}
+
+	snprintf(self->root_sc, sizeof(self->root_sc),
+		 "%s/cgroup.subtree_control", root);
+	snprintf(ctl, sizeof(ctl), "%s/cgroup.controllers", root);
+
+	/* Named after our pid so we cannot collide with anything else. */
+	snprintf(self->scratch, sizeof(self->scratch), "%s/%s.%d", root,
+		 CG_SCRATCH, getpid());
+	snprintf(self->child, sizeof(self->child), "%s/child", self->scratch);
+	snprintf(self->scratch_sc, sizeof(self->scratch_sc),
+		 "%s/cgroup.subtree_control", self->scratch);
+
+	for (i = 0; i < ARRAY_SIZE(controllers); i++) {
+		if (!file_has_word(ctl, controllers[i].name))
+			continue;
+		snprintf(self->enable, sizeof(self->enable), "+%s",
+			 controllers[i].name);
+		snprintf(self->disable, sizeof(self->disable), "-%s",
+			 controllers[i].name);
+		probe_file = controllers[i].probe_file;
+
+		/*
+		 * A controller must be in the root's subtree_control before
+		 * it appears in our scratch cgroup.  Note if we enabled it,
+		 * so it can be put back.
+		 */
+		self->enabled_at_root = !file_has_word(self->root_sc,
+						       controllers[i].name);
+		if (self->enabled_at_root &&
+		    write_file(self->root_sc, self->enable)) {
+			self->enabled_at_root = false;
+			probe_file = NULL;
+			continue;
+		}
+		break;
+	}
+	if (!probe_file) {
+		kernfs_cgroup_undo(self);
+		SKIP(return, "no usable cgroup2 controller");
+	}
+
+	snprintf(self->probe, sizeof(self->probe), "%s/%s", self->child,
+		 probe_file);
+
+	/*
+	 * Only an unusable environment may skip.  A scratch cgroup named
+	 * after our own pid should always be creatable, so failing to make
+	 * one is a result -- skipping would let a broken kernel look green.
+	 */
+	if (mkdir(self->scratch, 0755)) {
+		int err = errno;
+
+		kernfs_cgroup_undo(self);
+		if (err == EROFS || err == EACCES || err == EPERM)
+			SKIP(return, "mkdir %s: %s", self->scratch,
+			     strerror(err));
+		ASSERT_EQ(err, 0) TH_LOG("mkdir %s: %s", self->scratch,
+					 strerror(err));
+	}
+	if (mkdir(self->child, 0755)) {
+		int err = errno;
+
+		kernfs_cgroup_undo(self);
+		ASSERT_EQ(err, 0) TH_LOG("mkdir %s: %s", self->child,
+					 strerror(err));
+	}
+
+	/*
+	 * The tests below need the probe file to appear and disappear with
+	 * the controller, so it must be absent now, before anything enables
+	 * it in the scratch cgroup.  Skip rather than fail: a probe file that
+	 * is already there means the table names one the controller does not
+	 * own, not that the kernel is broken.
+	 */
+	if (!access(self->probe, F_OK)) {
+		kernfs_cgroup_undo(self);
+		SKIP(return, "%s is not owned by the %s controller",
+		     probe_file, self->enable + 1);
+	}
+}
+
+FIXTURE_TEARDOWN(kernfs_cgroup)
+{
+	write_file(self->scratch_sc, self->disable);
+	kernfs_cgroup_undo(self);
+}
+
+/*
+ * Walking already-cached dentries must not invalidate them.  Spurious
+ * invalidation is not merely slow: d_invalidate() calls detach_mounts(), so
+ * an unrelated lookup would silently tear down any mount below.
+ */
+TEST_F(kernfs_cgroup, path_walk_does_not_invalidate)
+{
+	char src[] = "/tmp/kernfs_selftest_bind.XXXXXX";
+	char sub[PATH_MAX], probe[PATH_MAX];
+	int i;
+
+	snprintf(sub, sizeof(sub), "%s/sub", self->child);
+	ASSERT_EQ(mkdir(sub, 0755), 0);
+
+	if (!mkdtemp(src)) {
+		rmdir(sub);
+		SKIP(return, "mkdtemp: %s", strerror(errno));
+	}
+	if (mount(src, sub, NULL, MS_BIND, NULL)) {
+		int err = errno;
+
+		rmdir(sub);
+		rmdir(src);
+		SKIP(return, "bind mount onto a cgroup dir: %s", strerror(err));
+	}
+	ASSERT_TRUE(path_is_mounted(sub));
+
+	/* Walk a sibling path through the same directory, repeatedly. */
+	snprintf(probe, sizeof(probe), "%s/cgroup.procs", self->child);
+	for (i = 0; i < 8; i++) {
+		int fd = open(probe, O_RDONLY | O_CLOEXEC);
+
+		if (fd >= 0)
+			close(fd);
+	}
+
+	EXPECT_TRUE(path_is_mounted(sub));
+
+	umount2(sub, MNT_DETACH);
+	rmdir(sub);
+	rmdir(src);
+}
+
+/*
+ * A cached negative dentry must be invalidated when the kernel creates the
+ * name behind the dcache's back.  That is what kernfs_dir_changed() and
+ * kernfs_elem_dir::rev are for.
+ */
+TEST_F(kernfs_cgroup, negative_dentry_invalidated_by_kernel_create)
+{
+	struct stat st;
+
+	/* Caches a negative dentry for the probe file. */
+	ASSERT_EQ(stat(self->probe, &st), -1);
+	ASSERT_EQ(errno, ENOENT);
+
+	/* The kernel now creates it, with no VFS operation on that name. */
+	ASSERT_EQ(write_file(self->scratch_sc, self->enable), 0);
+
+	EXPECT_EQ(stat(self->probe, &st), 0);
+}
+
+/* The mirror image: a cached positive dentry must go when the node does. */
+TEST_F(kernfs_cgroup, positive_dentry_invalidated_by_kernel_remove)
+{
+	struct stat st;
+
+	ASSERT_EQ(write_file(self->scratch_sc, self->enable), 0);
+	/* Caches a positive dentry. */
+	ASSERT_EQ(stat(self->probe, &st), 0);
+
+	ASSERT_EQ(write_file(self->scratch_sc, self->disable), 0);
+
+	ASSERT_EQ(stat(self->probe, &st), -1);
+	EXPECT_EQ(errno, ENOENT);
+}
+
+/* Opening a removed node fails; it never returns stale content. */
+TEST_F(kernfs_cgroup, open_after_rmdir_fails)
+{
+	char path[PATH_MAX];
+	char buf[64];
+	int fd;
+
+	snprintf(path, sizeof(path), "%s/cgroup.procs", self->child);
+
+	fd = open(path, O_RDONLY | O_CLOEXEC);
+	ASSERT_GE(fd, 0);
+
+	ASSERT_EQ(rmdir(self->child), 0);
+
+	/* Lookup by path must fail. */
+	EXPECT_EQ(open(path, O_RDONLY | O_CLOEXEC), -1);
+	EXPECT_EQ(errno, ENOENT);
+
+	/*
+	 * An fd held across removal must fail rather than return stale
+	 * content.  rmdir() deactivates the node before it returns, so
+	 * kernfs_seq_start() fails to get an active reference.
+	 */
+	EXPECT_LT(read(fd, buf, sizeof(buf)), 0);
+	EXPECT_EQ(errno, ENODEV);
+	EXPECT_EQ(close(fd), 0);
+
+	ASSERT_EQ(mkdir(self->child, 0755), 0);
+}
+
+/* readdir returns every entry exactly once. */
+TEST_F(kernfs_cgroup, readdir_no_duplicates)
+{
+	char names[512][NAME_MAX + 1];
+	struct dirent *de;
+	int n = 0, i, j;
+	DIR *d;
+
+	ASSERT_EQ(write_file(self->scratch_sc, self->enable), 0);
+
+	d = opendir(self->child);
+	ASSERT_NE(d, NULL);
+	while ((de = readdir(d))) {
+		if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
+			continue;
+		ASSERT_LT(n, (int)ARRAY_SIZE(names));
+		strncpy(names[n], de->d_name, NAME_MAX);
+		names[n][NAME_MAX] = '\0';
+		n++;
+	}
+	closedir(d);
+
+	ASSERT_GT(n, 0);
+	for (i = 0; i < n; i++)
+		for (j = i + 1; j < n; j++)
+			EXPECT_STRNE(names[i], names[j]);
+}
+
+#define RESUME_DIRS	24
+
+/*
+ * Resuming at an entry that has gone must carry on after it, never before.
+ * Take a cookie for every entry, then remove each one, seek to its cookie
+ * and read the rest; nothing already reported may come back.
+ */
+TEST_F(kernfs_cgroup, readdir_resume_at_removed_entry)
+{
+	/* The cgroup's own control files are listed alongside ours. */
+	char names[128][NAME_MAX + 1];
+	long pos[128];
+	char path[PATH_MAX];
+	struct dirent *de;
+	int n = 0, i, j;
+	DIR *d;
+
+	for (i = 0; i < RESUME_DIRS; i++) {
+		snprintf(path, sizeof(path), "%s/e%02d", self->scratch, i);
+		ASSERT_EQ(mkdir(path, 0755), 0);
+	}
+
+	/* Record the cookie before reading each entry, with its name. */
+	d = opendir(self->scratch);
+	ASSERT_NE(d, NULL);
+	while (1) {
+		long here = telldir(d);
+
+		de = readdir(d);
+		if (!de)
+			break;
+		if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
+			continue;
+		ASSERT_LT(n, (int)ARRAY_SIZE(pos));
+		pos[n] = here;
+		strncpy(names[n], de->d_name, NAME_MAX);
+		names[n][NAME_MAX] = '\0';
+		n++;
+	}
+	closedir(d);
+	ASSERT_GT(n, 1);
+
+	for (i = 0; i < n; i++) {
+		/* Only the directories we made can be removed and put back. */
+		if (strncmp(names[i], "e", 1))
+			continue;
+
+		snprintf(path, sizeof(path), "%s/%s", self->scratch, names[i]);
+		ASSERT_EQ(rmdir(path), 0);
+
+		/* Reopen so the seek has to reach the kernel. */
+		d = opendir(self->scratch);
+		ASSERT_NE(d, NULL);
+		seekdir(d, pos[i]);
+		while ((de = readdir(d))) {
+			if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
+				continue;
+			for (j = 0; j < i; j++)
+				ASSERT_STRNE(de->d_name, names[j])
+					TH_LOG("resuming at %s (gone) went back to %s",
+					       names[i], names[j]);
+		}
+		closedir(d);
+
+		ASSERT_EQ(mkdir(path, 0755), 0);
+	}
+
+	for (i = 0; i < RESUME_DIRS; i++) {
+		snprintf(path, sizeof(path), "%s/e%02d", self->scratch, i);
+		EXPECT_EQ(rmdir(path), 0);
+	}
+}
+
+#define CHURN_ROUNDS	400
+#define CHURN_BUFSZ	512	/* small, so a listing takes several calls */
+
+/*
+ * The files appear at the end of the enabling write and go at the start of
+ * the disabling one, so the window where they exist is the short one.
+ */
+#define CHURN_DWELL_ON	2000
+#define CHURN_DWELL_OFF	200
+
+struct kernfs_dirent64 {
+	unsigned long long	d_ino;
+	long long		d_off;
+	unsigned short		d_reclen;
+	unsigned char		d_type;
+	char			d_name[];
+};
+
+/*
+ * The same resume, but inside one getdents(2) call.  rmdir(2) cannot reach
+ * that window because iterate_dir() holds the listed directory's i_rwsem
+ * for the whole listing; cgroup.subtree_control can, having no VFS
+ * operation on the names it adds and removes.  The files that are not the
+ * controller's stay throughout, so each must appear exactly once.
+ *
+ * A stress test: it has not been seen to catch the ordering bug, and is
+ * here to keep the unlocked window under load for lockdep and KASAN.
+ */
+TEST_F(kernfs_cgroup, readdir_resume_vs_internal_remove)
+{
+	char buf[CHURN_BUFSZ] __attribute__((aligned(8)));
+	char stable[128][NAME_MAX + 1];
+	int nstable = 0, i, r;
+	int withctl = 0, without = 0;
+	int seen[128], status;
+	pid_t churner;
+	DIR *d;
+
+	/* With the controller off, whatever is left is what must persist. */
+	ASSERT_EQ(write_file(self->scratch_sc, self->disable), 0);
+	d = opendir(self->child);
+	ASSERT_NE(d, NULL);
+	for (;;) {
+		struct dirent *de = readdir(d);
+
+		if (!de)
+			break;
+		if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
+			continue;
+		ASSERT_LT(nstable, (int)ARRAY_SIZE(stable));
+		strncpy(stable[nstable], de->d_name, NAME_MAX);
+		stable[nstable][NAME_MAX] = '\0';
+		nstable++;
+	}
+	closedir(d);
+	ASSERT_GT(nstable, 0);
+
+	churner = fork();
+	ASSERT_GE(churner, 0);
+	if (churner == 0) {
+		for (;;) {
+			if (write_file(self->scratch_sc, self->enable))
+				_exit(10);
+			usleep(CHURN_DWELL_ON);
+			if (write_file(self->scratch_sc, self->disable))
+				_exit(11);
+			usleep(CHURN_DWELL_OFF);
+		}
+	}
+
+	for (r = 0; r < CHURN_ROUNDS; r++) {
+		int fd = open(self->child, O_RDONLY | O_DIRECTORY);
+		int extra = 0;
+		int n;
+
+		ASSERT_GE(fd, 0);
+		memset(seen, 0, sizeof(seen));
+
+		while ((n = syscall(SYS_getdents64, fd, buf, sizeof(buf))) > 0) {
+			int off = 0;
 
+			while (off < n) {
+				struct kernfs_dirent64 *de = (void *)(buf + off);
+				bool known = false;
+
+				off += de->d_reclen;
+				for (i = 0; i < nstable; i++)
+					if (!strcmp(de->d_name, stable[i])) {
+						seen[i]++;
+						known = true;
+					}
+				if (!known && strcmp(de->d_name, ".") &&
+				    strcmp(de->d_name, ".."))
+					extra++;
+			}
+		}
+		ASSERT_GE(n, 0);
+		EXPECT_EQ(close(fd), 0);
+
+		if (extra)
+			withctl++;
+		else
+			without++;
+
+		for (i = 0; i < nstable; i++)
+			ASSERT_EQ(seen[i], 1)
+				TH_LOG("round %d: %s seen %d times",
+				       r, stable[i], seen[i]);
+	}
+
+	/* The churn must have been running, or the listings prove nothing. */
+	EXPECT_EQ(kill(churner, SIGKILL), 0);
+	ASSERT_EQ(waitpid(churner, &status, 0), churner);
+	ASSERT_TRUE(WIFSIGNALED(status) && WTERMSIG(status) == SIGKILL)
+		TH_LOG("churner exited on its own: status %d", status);
+
+	/*
+	 * They also have to have overlapped it.  How much depends on the
+	 * machine, so say the race could not be arranged rather than fail.
+	 */
+	if (!withctl || !without)
+		SKIP(return, "listings did not span the churn: %d with, %d without",
+		     withctl, without);
+}
+
+/*
+ * A telldir() cookie must resolve back to the same entry after seekdir().
+ * kernfs encodes the cookie as the node's name hash, so this covers
+ * kernfs_dir_pos() as well as plain iteration.
+ */
+TEST_F(kernfs_cgroup, readdir_seekdir_roundtrip)
+{
+	char names[512][NAME_MAX + 1];
+	struct dirent *de;
+	long pos[512];
+	int n = 0, i;
+	DIR *d;
+
+	ASSERT_EQ(write_file(self->scratch_sc, self->enable), 0);
+
+	d = opendir(self->child);
+	ASSERT_NE(d, NULL);
+
+	/* Record the cookie *before* reading each entry, with its name. */
+	while (1) {
+		long here = telldir(d);
+
+		de = readdir(d);
+		if (!de)
+			break;
+		if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
+			continue;
+		ASSERT_LT(n, (int)ARRAY_SIZE(pos));
+		pos[n] = here;
+		strncpy(names[n], de->d_name, NAME_MAX);
+		names[n][NAME_MAX] = '\0';
+		n++;
+	}
+	ASSERT_GT(n, 0);
+
+	/* Seeking back to a cookie must land on the entry it was taken at. */
+	for (i = 0; i < n; i++) {
+		seekdir(d, pos[i]);
+		de = readdir(d);
+		ASSERT_NE(de, NULL);
+		EXPECT_STREQ(de->d_name, names[i]);
+	}
+
+	closedir(d);
+}
+
+#define STRESS_SECS	2
+#define STRESS_DIRS	4
+#define STRESS_READERS	4
+
+/*
+ * Hammer lookup against creation and removal.  Revalidation holds no lock
+ * against the writers, so what makes it safe is that every answer it can
+ * give is one the caller already handles: a reader must only ever see
+ * success or an errno meaning "it went away", never garbage or a hang.
+ */
+TEST_F(kernfs_cgroup, lookup_vs_create_remove_stress)
+{
+	pid_t pids[STRESS_DIRS + STRESS_READERS];
+	struct timespec end;
+	int i, status, n = 0;
+
+	clock_gettime(CLOCK_MONOTONIC, &end);
+	end.tv_sec += STRESS_SECS;
+
+	for (i = 0; i < STRESS_DIRS; i++) {
+		pid_t pid = fork();
+
+		ASSERT_GE(pid, 0);
+		if (pid == 0) {
+			char dir[PATH_MAX];
+
+			snprintf(dir, sizeof(dir), "%s/s%d", self->scratch, i);
+			while (!stress_deadline(&end)) {
+				if (mkdir(dir, 0755) && errno != EEXIST)
+					_exit(10);
+				if (rmdir(dir) && errno != ENOENT &&
+				    errno != EBUSY)
+					_exit(11);
+			}
+			_exit(0);
+		}
+		pids[n++] = pid;
+	}
+
+	for (i = 0; i < STRESS_READERS; i++) {
+		pid_t pid = fork();
+
+		ASSERT_GE(pid, 0);
+		if (pid == 0) {
+			/* Start each reader on a different directory. */
+			unsigned int seq = i;
+
+			while (!stress_deadline(&end)) {
+				int which = seq++ % STRESS_DIRS;
+				char path[PATH_MAX];
+				struct stat st;
+				int fd;
+
+				snprintf(path, sizeof(path),
+					 "%s/s%d/cgroup.procs",
+					 self->scratch, which);
+
+				if (stat(path, &st) && errno != ENOENT &&
+				    errno != ENODEV)
+					_exit(20);
+
+				fd = open(path, O_RDONLY | O_CLOEXEC);
+				if (fd < 0) {
+					if (errno != ENOENT && errno != ENODEV)
+						_exit(21);
+				} else {
+					close(fd);
+				}
+
+				if (access(path, F_OK) && errno != ENOENT &&
+				    errno != ENODEV)
+					_exit(22);
+			}
+			_exit(0);
+		}
+		pids[n++] = pid;
+	}
+
+	for (i = 0; i < n; i++) {
+		ASSERT_EQ(waitpid(pids[i], &status, 0), pids[i]);
+		ASSERT_TRUE(WIFEXITED(status));
+		EXPECT_EQ(WEXITSTATUS(status), 0);
+	}
+
+	for (i = 0; i < STRESS_DIRS; i++) {
+		char dir[PATH_MAX];
+
+		snprintf(dir, sizeof(dir), "%s/s%d", self->scratch, i);
+		rmdir_retry(dir);
+	}
+}
+
+struct kernfs_handle {
+	struct file_handle h;
+	unsigned char buf[MAX_HANDLE_SZ];
+};
+
+static int kernfs_encode(const char *path, struct kernfs_handle *fh)
+{
+	int mount_id;
+
+	memset(fh, 0, sizeof(*fh));
+	fh->h.handle_bytes = sizeof(fh->buf);
+	return name_to_handle_at(AT_FDCWD, path, &fh->h, &mount_id, 0);
+}
+
+/*
+ * Skip only where file handles do not work at all.  ENOENT must still
+ * fail: mkdir leaves a negative dentry cached, so the name resolves only
+ * after ->d_revalidate() drops it.  The encode tests revalidation too.
+ */
+static bool fh_unsupported(int err)
+{
+	return err == EOPNOTSUPP || err == EPERM || err == ENOSYS;
+}
+
+/*
+ * Decoding a file needs CAP_DAC_READ_SEARCH in the initial user
+ * namespace.  Probe once so the tests skip instead of fail.
+ */
+static bool fh_can_decode(int mfd, struct kernfs_handle *fh)
+{
+	int fd = open_by_handle_at(mfd, &fh->h, O_PATH);
+
+	if (fd < 0)
+		return errno != EPERM;
+	close(fd);
+	return true;
+}
+
+/*
+ * A file handle reaches a node without a lookup through its parent.  A
+ * live node must decode.  A removed one must not, because
+ * kernfs_find_and_get_node_by_id() refuses inactive nodes.
+ *
+ * Use O_PATH: opening a removed node fails with ENODEV, which would hide
+ * what is being tested.
+ */
+TEST_F(kernfs_cgroup, exportfs_decode_and_stale)
+{
+	char victim[PATH_MAX], procs[PATH_MAX];
+	struct kernfs_handle fh;
+	struct stat st;
+	int mfd, fd;
+
+	snprintf(victim, sizeof(victim), "%s/fh", self->scratch);
+	snprintf(procs, sizeof(procs), "%s/cgroup.procs", victim);
+	ASSERT_EQ(mkdir(victim, 0755), 0);
+
+	/* Any fd on the filesystem identifies it to open_by_handle_at(). */
+	mfd = open(self->scratch, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
+	ASSERT_GE(mfd, 0);
+
+	if (kernfs_encode(procs, &fh)) {
+		int err = errno;
+
+		close(mfd);
+		rmdir(victim);
+		ASSERT_TRUE(fh_unsupported(err))
+			TH_LOG("name_to_handle_at: %s", strerror(err));
+		SKIP(return, "name_to_handle_at: %s", strerror(err));
+	}
+
+	if (!fh_can_decode(mfd, &fh)) {
+		close(mfd);
+		rmdir(victim);
+		SKIP(return, "open_by_handle_at: no CAP_DAC_READ_SEARCH");
+	}
+
+	fd = open_by_handle_at(mfd, &fh.h, O_PATH);
+	ASSERT_GE(fd, 0);
+	EXPECT_EQ(fstat(fd, &st), 0);
+	EXPECT_EQ(st.st_nlink, 1);
+	EXPECT_EQ(close(fd), 0);
+
+	ASSERT_EQ(rmdir(victim), 0);
+
+	fd = open_by_handle_at(mfd, &fh.h, O_PATH);
+	EXPECT_LT(fd, 0);
+	if (fd >= 0)
+		close(fd);
+	else
+		EXPECT_EQ(errno, ESTALE);
+
+	EXPECT_EQ(close(mfd), 0);
+}
+
+#define FH_STRESS_SECS	2
+#define FH_DECODE_CAP	10000
+
+/*
+ * Decode file handles while the node is being removed.  A decode must
+ * answer with a usable handle or ESTALE, never garbage and never a hang.
+ *
+ * The link count is checked too.  An inode that reaches the inode hash
+ * after the removal cleared link counts keeps the 1 it was born with, so
+ * it never gets an IN_DELETE_SELF.  This has not been seen to fire: it
+ * needs the decode to stall between the lookup by id and the hash insert,
+ * and nothing there blocks.  It is kept because it is cheap and only
+ * looks once the directory is gone, so it cannot fail falsely.
+ */
+TEST_F(kernfs_cgroup, exportfs_decode_vs_rmdir_stress)
+{
+	int mfd, bad = 0, rounds = 0;
+	struct timespec end;
+
+	mfd = open(self->scratch, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
+	ASSERT_GE(mfd, 0);
+
+	clock_gettime(CLOCK_MONOTONIC, &end);
+	end.tv_sec += FH_STRESS_SECS;
+
+	while (!stress_deadline(&end)) {
+		char victim[PATH_MAX], procs[PATH_MAX];
+		int last = -1, fd, i;
+		struct kernfs_handle fh;
+		struct stat st;
+		pid_t pid;
+
+		snprintf(victim, sizeof(victim), "%s/fh%d", self->scratch,
+			 rounds++);
+		snprintf(procs, sizeof(procs), "%s/cgroup.procs", victim);
+		if (mkdir(victim, 0755))
+			break;
+		if (kernfs_encode(procs, &fh)) {
+			int err = errno;
+
+			rmdir(victim);
+			ASSERT_TRUE(fh_unsupported(err))
+				TH_LOG("name_to_handle_at: %s", strerror(err));
+			SKIP(goto out, "name_to_handle_at: %s", strerror(err));
+		}
+		if (rounds == 1 && !fh_can_decode(mfd, &fh)) {
+			rmdir(victim);
+			SKIP(goto out,
+			     "open_by_handle_at: no CAP_DAC_READ_SEARCH");
+		}
+
+		pid = fork();
+		ASSERT_GE(pid, 0);
+		if (pid == 0) {
+			rmdir_retry(victim);
+			_exit(0);
+		}
+
+		/*
+		 * Decode until the removal deactivates the node.  Keep the
+		 * last one that worked: it ran closest to the removal.
+		 */
+		for (i = 0; i < FH_DECODE_CAP; i++) {
+			fd = open_by_handle_at(mfd, &fh.h, O_PATH);
+			if (fd < 0)
+				break;
+			if (last >= 0)
+				close(last);
+			last = fd;
+		}
+		ASSERT_EQ(waitpid(pid, NULL, 0), pid);
+
+		if (last >= 0) {
+			if (access(victim, F_OK) && errno == ENOENT &&
+			    !fstat(last, &st) && st.st_nlink != 0)
+				bad++;
+			close(last);
+		}
+		rmdir(victim);
+	}
+
+	EXPECT_EQ(bad, 0)
+		TH_LOG("%d of %d rounds decoded a removed node whose inode kept its link count",
+		       bad, rounds);
+out:
+	close(mfd);
+}
+
+/*
+ * sysfs is namespace tagged (KERNFS_NS) and supports rename; cgroup2 does
+ * neither.  Run in a private netns with its own sysfs so the host is
+ * untouched.
+ */
+FIXTURE(kernfs_netns)
+{
+	char mnt[PATH_MAX];
+	char net[PATH_MAX];
+	bool mounted;
+};
+
+FIXTURE_SETUP(kernfs_netns)
+{
+	if (geteuid())
+		SKIP(return, "test needs to run as root");
+
+	if (unshare(CLONE_NEWNS | CLONE_NEWNET))
+		SKIP(return, "unshare(CLONE_NEWNS|CLONE_NEWNET): %s",
+		     strerror(errno));
+
+	/* Don't let our sysfs mount escape into the parent namespace. */
+	ASSERT_EQ(mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL), 0);
+
+	strcpy(self->mnt, "/tmp/kernfs_selftest_sysfs.XXXXXX");
+	if (!mkdtemp(self->mnt))
+		SKIP(return, "mkdtemp: %s", strerror(errno));
+
+	if (mount("none", self->mnt, "sysfs", 0, NULL)) {
+		rmdir(self->mnt);
+		SKIP(return, "mount sysfs: %s", strerror(errno));
+	}
+	self->mounted = true;
+
+	snprintf(self->net, sizeof(self->net), "%s/class/net", self->mnt);
+}
+
+FIXTURE_TEARDOWN(kernfs_netns)
+{
+	if (self->mounted)
+		umount2(self->mnt, MNT_DETACH);
+	rmdir(self->mnt);
+}
+
+/*
+ * sysfs must show this network namespace's interfaces, not the parent's.
+ *
+ * Do not assume a fresh netns contains only "lo": fallback tunnel devices
+ * (tunl0, sit0, gre0, ...) are created in every namespace unless
+ * net.core.fb_tunnels_only_for_init_net is set, so which names appear
+ * depends on the modules the host has.  Check the set instead --
+ * if_nametoindex() resolves in the current netns, so every name sysfs shows
+ * must resolve there, and the counts must agree.
+ *
+ * Count only symlinks.  Not every entry is a device: bonding adds a
+ * bonding_masters attribute to /sys/class/net in every namespace.
+ */
+TEST_F(kernfs_netns, ns_tag_isolates_class_net)
+{
+	struct if_nameindex *idx, *i;
+	bool found_lo = false;
+	int n = 0, want = 0;
+	struct dirent *de;
+	DIR *d;
+
+	d = opendir(self->net);
+	ASSERT_NE(d, NULL);
+	while ((de = readdir(d))) {
+		if (de->d_type != DT_LNK)
+			continue;
+		EXPECT_NE(if_nametoindex(de->d_name), 0u)
+			TH_LOG("%s is not in this netns", de->d_name);
+		if (!strcmp(de->d_name, "lo"))
+			found_lo = true;
+		n++;
+	}
+	closedir(d);
+
+	idx = if_nameindex();
+	ASSERT_NE(idx, NULL);
+	for (i = idx; i->if_index; i++)
+		want++;
+	if_freenameindex(idx);
+
+	EXPECT_TRUE(found_lo);
+	EXPECT_EQ(n, want);
+}
+
+/*
+ * After a rename the old name must stop resolving and the new one must
+ * start, even though both dentries are already cached.
+ */
+TEST_F(kernfs_netns, rename_is_revalidated)
+{
+	char old_path[PATH_MAX], new_path[PATH_MAX];
+	struct ifreq ifr = {};
+	struct stat st;
+	int sk;
+
+	snprintf(old_path, sizeof(old_path), "%s/lo", self->net);
+	snprintf(new_path, sizeof(new_path), "%s/%s", self->net, TEST_IFNAME);
+
+	/* Warm both dentries: one positive, one negative. */
+	ASSERT_EQ(stat(old_path, &st), 0);
+	ASSERT_EQ(stat(new_path, &st), -1);
+	ASSERT_EQ(errno, ENOENT);
+
+	sk = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+	ASSERT_GE(sk, 0);
+	strcpy(ifr.ifr_name, "lo");
+	strcpy(ifr.ifr_newname, TEST_IFNAME);
+	if (ioctl(sk, SIOCSIFNAME, &ifr)) {
+		close(sk);
+		SKIP(return, "SIOCSIFNAME: %s", strerror(errno));
+	}
+	close(sk);
+
+	EXPECT_EQ(stat(old_path, &st), -1);
+	EXPECT_EQ(errno, ENOENT);
+	EXPECT_EQ(stat(new_path, &st), 0);
+}
+
+static int netdev_rename(const char *from, const char *to)
+{
+	struct ifreq ifr = {};
+	int sk, ret;
+
+	sk = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+	if (sk < 0)
+		return -1;
+	strncpy(ifr.ifr_name, from, IFNAMSIZ - 1);
+	strncpy(ifr.ifr_newname, to, IFNAMSIZ - 1);
+	ret = ioctl(sk, SIOCSIFNAME, &ifr);
+	close(sk);
+	return ret;
+}
+
+/*
+ * Bounded by a count, not by time: every rename is logged and not rate
+ * limited, so a timed loop would flood the kernel log.
+ */
+#define RENAME_FLIPS		200
+#define RENAME_READERS		4
+
+/*
+ * Rename an interface while other tasks look up the names it moves
+ * between.  This renames its /sys/class/net entry through
+ * kernfs_rename_ns() with the parent unchanged.
+ *
+ * The renamer checks what is certain: SIOCSIFNAME returns once the rename
+ * is done and nothing else renames here, so the new name must resolve and
+ * the old must not.  The readers cannot check that, because the name can
+ * move between their two lstat() calls.  They only check that a lookup
+ * returns success or ENOENT, and keep the lock busy while renames run.
+ *
+ * lstat() not stat(): /sys/class/net/<dev> is a symlink and is renamed
+ * before the directory it points at, so the two are not atomic.
+ */
+TEST_F(kernfs_netns, rename_vs_lookup_stress)
+{
+	char old_path[PATH_MAX], new_path[PATH_MAX];
+	pid_t pids[RENAME_READERS];
+	int i, status, n = 0, bad = 0;
+	struct stat st;
+	int done[2];
+
+	snprintf(old_path, sizeof(old_path), "%s/lo", self->net);
+	snprintf(new_path, sizeof(new_path), "%s/%s", self->net, TEST_IFNAME);
+
+	if (netdev_rename("lo", TEST_IFNAME))
+		SKIP(return, "SIOCSIFNAME: %s", strerror(errno));
+	if (netdev_rename(TEST_IFNAME, "lo"))
+		SKIP(return, "SIOCSIFNAME back: %s", strerror(errno));
+
+	/* Readers run until the renamer closes the write end. */
+	ASSERT_EQ(pipe2(done, O_NONBLOCK | O_CLOEXEC), 0);
+
+	for (i = 0; i < RENAME_READERS; i++) {
+		pid_t pid = fork();
+
+		ASSERT_GE(pid, 0);
+		if (pid == 0) {
+			struct stat rst;
+			char c;
+
+			close(done[1]);
+			while (read(done[0], &c, 1) < 0 && errno == EAGAIN) {
+				if (lstat(old_path, &rst) && errno != ENOENT)
+					_exit(20);
+				if (lstat(new_path, &rst) && errno != ENOENT)
+					_exit(21);
+			}
+			_exit(0);
+		}
+		pids[n++] = pid;
+	}
+	close(done[0]);
+
+	for (i = 0; i < RENAME_FLIPS; i++) {
+		if (netdev_rename("lo", TEST_IFNAME))
+			break;
+		if (lstat(new_path, &st) || !lstat(old_path, &st)) {
+			bad++;
+			break;
+		}
+		if (netdev_rename(TEST_IFNAME, "lo"))
+			break;
+		if (lstat(old_path, &st) || !lstat(new_path, &st)) {
+			bad++;
+			break;
+		}
+	}
+	close(done[1]);
+
+	for (i = 0; i < n; i++) {
+		ASSERT_EQ(waitpid(pids[i], &status, 0), pids[i]);
+		ASSERT_TRUE(WIFEXITED(status));
+		EXPECT_EQ(WEXITSTATUS(status), 0);
+	}
+
+	EXPECT_EQ(bad, 0)
+		TH_LOG("a completed rename left the wrong name resolving");
+
+	/* Leave the interface as the fixture found it. */
+	netdev_rename(TEST_IFNAME, "lo");
+}
+
+TEST_HARNESS_MAIN
