mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Pavol Sakac <sakacpav@amazon.de>
To: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	Tejun Heo <tj@kernel.org>,
	"Rafael J . Wysocki" <rafael@kernel.org>,
	Danilo Krummrich <dakr@kernel.org>
Cc: <driver-core@lists.linux.dev>, <linux-kernel@vger.kernel.org>,
	"Andy Shevchenko" <andriy.shevchenko@linux.intel.com>,
	Xu Yang <xu.yang_2@nxp.com>,
	Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>,
	Bjorn Helgaas <bhelgaas@google.com>, <linux-pci@vger.kernel.org>,
	Alex Williamson <alex@shazbot.org>, <kvm@vger.kernel.org>,
	<nh-open-source@amazon.com>
Subject: [RFC PATCH 1/8] kernfs: factor out reusable directory helpers
Date: Fri, 11 Sep 2026 19:43:33 +0200	[thread overview]
Message-ID: <20260911174414.97060-1-sakacpav@amazon.de> (raw)
In-Reply-To: <20260911-vfopt-s5-v1-0-fa4cacdb6ca8@amazon.de>

An upcoming change adds staged directories whose children collections are
protected by a per-subtree mutex instead of kernfs_rwsem, so it needs the
pure rbtree and directory-creation operations without the rwsem assertions
and accounting wrapped around them.

Split those out: __kernfs_link_sibling() and __kernfs_find_ns() for the
children-rbtree work, __kernfs_create_dir() for the sequence both directory
creators repeat, and kernfs_update_parent_times() for the parent timestamp
bump open-coded at each link and unlink site. The existing names stay as
locked wrappers carrying the lockdep assertions, the link-side wrapper
gaining the write-side assertion it lacked. No functional change intended.

Assisted-by: LLM
Signed-off-by: Pavol Sakac <sakacpav@amazon.de>
---
 fs/kernfs/dir.c | 128 ++++++++++++++++++++++++++++++++----------------
 1 file changed, 87 insertions(+), 41 deletions(-)

diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index 1938edd39eff..a6290f94139c 100644
--- a/fs/kernfs/dir.c
+++ b/fs/kernfs/dir.c
@@ -459,12 +459,24 @@ static int kernfs_sd_compare(const struct kernfs_node *left,
 	return kernfs_name_compare(left->hash, kernfs_rcu_name(left), left->ns, right);
 }
 
+/* Bump @parent's ctime/mtime; caller holds whichever lock covers @parent. */
+static void kernfs_update_parent_times(struct kernfs_node *parent)
+{
+	struct kernfs_iattrs *ps_iattr = parent ? parent->iattr : NULL;
+
+	if (ps_iattr) {
+		ktime_get_real_ts64(&ps_iattr->ia_ctime);
+		ps_iattr->ia_mtime = ps_iattr->ia_ctime;
+	}
+}
+
 /**
- *	kernfs_link_sibling - link kernfs_node into sibling rbtree
+ *	__kernfs_link_sibling - link kernfs_node into sibling rbtree
  *	@kn: kernfs_node of interest
  *
- *	Link @kn into its sibling rbtree which starts from
- *	@kn->parent->dir.children.
+ *	Link @kn into its parent's children rbtree.  This is the pure rbtree
+ *	insertion, without the subdir/revision accounting; the caller performs
+ *	that under whichever lock protects the parent's children collection.
  *
  *	Locking:
  *	kernfs_rwsem held exclusive
@@ -472,7 +484,7 @@ static int kernfs_sd_compare(const struct kernfs_node *left,
  *	Return:
  *	%0 on success, -EEXIST on failure.
  */
-static int kernfs_link_sibling(struct kernfs_node *kn)
+static int __kernfs_link_sibling(struct kernfs_node *kn)
 {
 	struct rb_node *parent = NULL;
 	struct kernfs_node *kn_parent;
@@ -500,7 +512,26 @@ static int kernfs_link_sibling(struct kernfs_node *kn)
 	rb_link_node(&kn->rb, parent, node);
 	rb_insert_color(&kn->rb, &kn_parent->dir.children);
 
+	return 0;
+}
+
+/*
+ * Locked variant of __kernfs_link_sibling(): kernfs_rwsem held exclusive; also
+ * performs the subdir count and directory-revision accounting.
+ */
+static int kernfs_link_sibling(struct kernfs_node *kn)
+{
+	struct kernfs_node *kn_parent;
+	int ret;
+
+	lockdep_assert_held_write(&kernfs_root(kn)->kernfs_rwsem);
+
+	ret = __kernfs_link_sibling(kn);
+	if (ret)
+		return ret;
+
 	/* successfully added, account subdir number */
+	kn_parent = kernfs_parent(kn);
 	down_write(&kernfs_root(kn)->kernfs_iattr_rwsem);
 	if (kernfs_type(kn) == KERNFS_DIR)
 		kn_parent->dir.subdirs++;
@@ -934,7 +965,6 @@ struct kernfs_node *kernfs_find_and_get_node_by_id(struct kernfs_root *root,
 int kernfs_add_one(struct kernfs_node *kn)
 {
 	struct kernfs_root *root = kernfs_root(kn);
-	struct kernfs_iattrs *ps_iattr;
 	struct kernfs_node *parent;
 	bool has_ns;
 	int ret;
@@ -964,13 +994,7 @@ int kernfs_add_one(struct kernfs_node *kn)
 
 	/* Update timestamps on the parent */
 	down_write(&root->kernfs_iattr_rwsem);
-
-	ps_iattr = parent->iattr;
-	if (ps_iattr) {
-		ktime_get_real_ts64(&ps_iattr->ia_ctime);
-		ps_iattr->ia_mtime = ps_iattr->ia_ctime;
-	}
-
+	kernfs_update_parent_times(parent);
 	up_write(&root->kernfs_iattr_rwsem);
 
 	/*
@@ -990,25 +1014,24 @@ int kernfs_add_one(struct kernfs_node *kn)
 }
 
 /**
- * kernfs_find_ns - find kernfs_node with the given name
+ * __kernfs_find_ns - find kernfs_node with the given name
  * @parent: kernfs_node to search under
  * @name: name to look for
  * @ns: the namespace tag to use
  *
- * Look for kernfs_node with name @name under @parent.
+ * Caller must hold a lock covering @parent's children collection:
+ * kernfs_rwsem.
  *
  * Return: pointer to the found kernfs_node on success, %NULL on failure.
  */
-static struct kernfs_node *kernfs_find_ns(struct kernfs_node *parent,
-					  const unsigned char *name,
-					  const struct ns_common *ns)
+static struct kernfs_node *__kernfs_find_ns(struct kernfs_node *parent,
+					    const unsigned char *name,
+					    const struct ns_common *ns)
 {
 	struct rb_node *node = parent->dir.children.rb_node;
 	bool has_ns = kernfs_ns_enabled(parent);
 	unsigned int hash;
 
-	lockdep_assert_held(&kernfs_root(parent)->kernfs_rwsem);
-
 	if (has_ns != (bool)ns) {
 		WARN(1, KERN_WARNING "kernfs: ns %s in '%s' for '%s'\n",
 		     has_ns ? "required" : "invalid", kernfs_rcu_name(parent), name);
@@ -1032,6 +1055,18 @@ static struct kernfs_node *kernfs_find_ns(struct kernfs_node *parent,
 	return NULL;
 }
 
+/*
+ * The asserted kernfs_rwsem hold (write or read) also covers the RCU-managed
+ * name dereferences in __kernfs_find_ns()'s walk.
+ */
+static struct kernfs_node *kernfs_find_ns(struct kernfs_node *parent,
+					  const unsigned char *name,
+					  const struct ns_common *ns)
+{
+	lockdep_assert_held(&kernfs_root(parent)->kernfs_rwsem);
+	return __kernfs_find_ns(parent, name, ns);
+}
+
 static struct kernfs_node *kernfs_walk_ns(struct kernfs_node *parent,
 					  const unsigned char *path,
 					  const struct ns_common *ns)
@@ -1218,6 +1253,31 @@ struct kernfs_node *kernfs_root_to_node(struct kernfs_root *root)
 	return root->kn;
 }
 
+/*
+ * Allocate and initialize a directory node with @extra_flags OR'd into its
+ * type flags, without linking it anywhere.
+ */
+static struct kernfs_node *__kernfs_create_dir(struct kernfs_node *parent,
+					       const char *name, umode_t mode,
+					       kuid_t uid, kgid_t gid,
+					       void *priv,
+					       const struct ns_common *ns,
+					       unsigned int extra_flags)
+{
+	struct kernfs_node *kn;
+
+	kn = kernfs_new_node(parent, name, mode | S_IFDIR, uid, gid,
+			     KERNFS_DIR | extra_flags);
+	if (!kn)
+		return ERR_PTR(-ENOMEM);
+
+	kn->dir.root = parent->dir.root;
+	kn->ns = ns;
+	kn->priv = priv;
+
+	return kn;
+}
+
 /**
  * kernfs_create_dir_ns - create a directory
  * @parent: parent in which to create a new directory
@@ -1240,14 +1300,9 @@ struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent,
 	int rc;
 
 	/* allocate */
-	kn = kernfs_new_node(parent, name, mode | S_IFDIR,
-			     uid, gid, KERNFS_DIR);
-	if (!kn)
-		return ERR_PTR(-ENOMEM);
-
-	kn->dir.root = parent->dir.root;
-	kn->ns = ns;
-	kn->priv = priv;
+	kn = __kernfs_create_dir(parent, name, mode, uid, gid, priv, ns, 0);
+	if (IS_ERR(kn))
+		return kn;
 
 	/* link in */
 	rc = kernfs_add_one(kn);
@@ -1272,15 +1327,12 @@ struct kernfs_node *kernfs_create_empty_dir(struct kernfs_node *parent,
 	int rc;
 
 	/* allocate */
-	kn = kernfs_new_node(parent, name, S_IRUGO|S_IXUGO|S_IFDIR,
-			     GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, KERNFS_DIR);
-	if (!kn)
-		return ERR_PTR(-ENOMEM);
+	kn = __kernfs_create_dir(parent, name, 0555,
+				 GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, NULL, NULL, 0);
+	if (IS_ERR(kn))
+		return kn;
 
 	kn->flags |= KERNFS_EMPTY_DIR;
-	kn->dir.root = parent->dir.root;
-	kn->ns = NULL;
-	kn->priv = NULL;
 
 	/* link in */
 	rc = kernfs_add_one(kn);
@@ -1706,18 +1758,12 @@ static void __kernfs_remove(struct kernfs_node *kn)
 		 * to decide who's responsible for cleanups.
 		 */
 		if (!parent || kernfs_unlink_sibling(pos)) {
-			struct kernfs_iattrs *ps_iattr =
-				parent ? parent->iattr : NULL;
-
 			down_write(&kernfs_root(kn)->kernfs_iattr_rwsem);
 
 			kernfs_clear_inode_nlink(pos);
 
 			/* update timestamps on the parent */
-			if (ps_iattr) {
-				ktime_get_real_ts64(&ps_iattr->ia_ctime);
-				ps_iattr->ia_mtime = ps_iattr->ia_ctime;
-			}
+			kernfs_update_parent_times(parent);
 
 			up_write(&kernfs_root(kn)->kernfs_iattr_rwsem);
 			kernfs_put(pos);
-- 
2.47.3


  reply	other threads:[~2026-09-11 17:44 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-11 17:43 [RFC PATCH 0/8] kernfs, driver core: staged sysfs registration Pavol Sakac
2026-09-11 17:43 ` Pavol Sakac [this message]
2026-09-11 17:43 ` [RFC PATCH 2/8] kernfs: add staged directory creation and publication Pavol Sakac
2026-09-11 17:43 ` [RFC PATCH 3/8] sysfs: add opt-in " Pavol Sakac
2026-09-11 17:43 ` [RFC PATCH 4/8] driver core: Register opted-in devices through the staged sysfs path Pavol Sakac
2026-09-11 17:43 ` [RFC PATCH 5/8] drivers: base: test: Add KUnit suite for staged sysfs registration Pavol Sakac
2026-09-12 13:14   ` Andy Shevchenko
2026-09-11 17:43 ` [RFC PATCH 6/8] driver core: Defer uevents for devices registered in a staged window Pavol Sakac
2026-09-12 13:20   ` Andy Shevchenko
2026-09-11 17:43 ` [RFC PATCH 7/8] PCI/IOV: Register virtual functions through the staged sysfs path Pavol Sakac
2026-09-11 17:43 ` [RFC PATCH 8/8] vfio: Opt the group and vfio-dev class devices into staged sysfs Pavol Sakac

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260911174414.97060-1-sakacpav@amazon.de \
    --to=sakacpav@amazon.de \
    --cc=alex@shazbot.org \
    --cc=andriy.shevchenko@linux.intel.com \
    --cc=bartosz.golaszewski@oss.qualcomm.com \
    --cc=bhelgaas@google.com \
    --cc=dakr@kernel.org \
    --cc=driver-core@lists.linux.dev \
    --cc=gregkh@linuxfoundation.org \
    --cc=kvm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pci@vger.kernel.org \
    --cc=nh-open-source@amazon.com \
    --cc=rafael@kernel.org \
    --cc=tj@kernel.org \
    --cc=xu.yang_2@nxp.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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®