[PATCH 2/3] kernfs: allocate the new name outside kernfs_rwsem
From: Shakeel Butt
Date: Sat Sep 12 2026 - 22:15:57 EST
kernfs_rename_ns() calls kstrdup_const() while holding the kernfs_rwsem
write lock. It is the only GFP_KERNEL allocation under that lock in
kernfs, so a rename can enter reclaim while every create, remove and
rename in the hierarchy waits behind it.
Copy the name before taking the lock and free the copy again if the
rename turns out not to need it. A rename that keeps the name, hits a
collision or finds the node gone now does one extra kstrdup_const();
renames are rare. -ENOMEM is still reported at the same point as
before, so nothing changes about which error a caller sees.
Assisted-by: LLM
Signed-off-by: Shakeel Butt <shakeel.butt@xxxxxxxxx>
---
fs/kernfs/dir.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index 8953e8a07537..3bbdd9a8acc8 100644
--- a/fs/kernfs/dir.c
+++ b/fs/kernfs/dir.c
@@ -1819,6 +1819,7 @@ 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;
struct kernfs_root *root;
const char *old_name;
bool reparent;
@@ -1828,6 +1829,9 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent,
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 +1863,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;
}
@@ -1901,6 +1906,7 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent,
error = 0;
out:
up_write(&root->kernfs_rwsem);
+ kfree_const(dup_name);
return error;
}
--
2.53.0-Meta