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
next prev parent 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®