Skip to content

Commit 93b27a8

Browse files
fatherMatrixgregkh
authored andcommitted
kernfs: switch global kernfs_rename_lock to per-fs lock
The kernfs implementation has big lock granularity(kernfs_rename_lock) so every kernfs-based(e.g., sysfs, cgroup) fs are able to compete the lock. This patch switches the global kernfs_rename_lock to per-fs lock, which put the rwlock into kernfs_root. Signed-off-by: Jinliang Zheng <alexjlzheng@tencent.com> Acked-by: Tejun Heo <tj@kernel.org> Link: https://lore.kernel.org/r/20250415153659.14950-3-alexjlzheng@tencent.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent cec59c4 commit 93b27a8

File tree

2 files changed

+19
-10
lines changed

2 files changed

+19
-10
lines changed

fs/kernfs/dir.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717

1818
#include "kernfs-internal.h"
1919

20-
DEFINE_RWLOCK(kernfs_rename_lock); /* kn->parent and ->name */
2120
/*
2221
* Don't use rename_lock to piggy back on pr_cont_buf. We don't want to
2322
* call pr_cont() while holding rename_lock. Because sometimes pr_cont()
@@ -228,7 +227,7 @@ int kernfs_path_from_node(struct kernfs_node *to, struct kernfs_node *from,
228227
if (to) {
229228
root = kernfs_root(to);
230229
if (!(root->flags & KERNFS_ROOT_INVARIANT_PARENT)) {
231-
guard(read_lock_irqsave)(&kernfs_rename_lock);
230+
guard(read_lock_irqsave)(&root->kernfs_rename_lock);
232231
return kernfs_path_from_node_locked(to, from, buf, buflen);
233232
}
234233
}
@@ -295,12 +294,14 @@ void pr_cont_kernfs_path(struct kernfs_node *kn)
295294
struct kernfs_node *kernfs_get_parent(struct kernfs_node *kn)
296295
{
297296
struct kernfs_node *parent;
297+
struct kernfs_root *root;
298298
unsigned long flags;
299299

300-
read_lock_irqsave(&kernfs_rename_lock, flags);
300+
root = kernfs_root(kn);
301+
read_lock_irqsave(&root->kernfs_rename_lock, flags);
301302
parent = kernfs_parent(kn);
302303
kernfs_get(parent);
303-
read_unlock_irqrestore(&kernfs_rename_lock, flags);
304+
read_unlock_irqrestore(&root->kernfs_rename_lock, flags);
304305

305306
return parent;
306307
}
@@ -993,6 +994,7 @@ struct kernfs_root *kernfs_create_root(struct kernfs_syscall_ops *scops,
993994
init_rwsem(&root->kernfs_iattr_rwsem);
994995
init_rwsem(&root->kernfs_supers_rwsem);
995996
INIT_LIST_HEAD(&root->supers);
997+
rwlock_init(&root->kernfs_rename_lock);
996998

997999
/*
9981000
* On 64bit ino setups, id is ino. On 32bit, low 32bits are ino.
@@ -1789,15 +1791,15 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent,
17891791
/* rename_lock protects ->parent accessors */
17901792
if (old_parent != new_parent) {
17911793
kernfs_get(new_parent);
1792-
write_lock_irq(&kernfs_rename_lock);
1794+
write_lock_irq(&root->kernfs_rename_lock);
17931795

17941796
rcu_assign_pointer(kn->__parent, new_parent);
17951797

17961798
kn->ns = new_ns;
17971799
if (new_name)
17981800
rcu_assign_pointer(kn->name, new_name);
17991801

1800-
write_unlock_irq(&kernfs_rename_lock);
1802+
write_unlock_irq(&root->kernfs_rename_lock);
18011803
kernfs_put(old_parent);
18021804
} else {
18031805
/* name assignment is RCU protected, parent is the same */

fs/kernfs/kernfs-internal.h

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@
1919
#include <linux/kernfs.h>
2020
#include <linux/fs_context.h>
2121

22-
extern rwlock_t kernfs_rename_lock;
23-
2422
struct kernfs_iattrs {
2523
kuid_t ia_uid;
2624
kgid_t ia_gid;
@@ -53,6 +51,9 @@ struct kernfs_root {
5351
struct rw_semaphore kernfs_iattr_rwsem;
5452
struct rw_semaphore kernfs_supers_rwsem;
5553

54+
/* kn->parent and kn->name */
55+
rwlock_t kernfs_rename_lock;
56+
5657
struct rcu_head rcu;
5758
};
5859

@@ -108,6 +109,11 @@ static inline bool kernfs_root_is_locked(const struct kernfs_node *kn)
108109
return lockdep_is_held(&kernfs_root(kn)->kernfs_rwsem);
109110
}
110111

112+
static inline bool kernfs_rename_is_locked(const struct kernfs_node *kn)
113+
{
114+
return lockdep_is_held(&kernfs_root(kn)->kernfs_rename_lock);
115+
}
116+
111117
static inline const char *kernfs_rcu_name(const struct kernfs_node *kn)
112118
{
113119
return rcu_dereference_check(kn->name, kernfs_root_is_locked(kn));
@@ -118,14 +124,15 @@ static inline struct kernfs_node *kernfs_parent(const struct kernfs_node *kn)
118124
/*
119125
* The kernfs_node::__parent remains valid within a RCU section. The kn
120126
* can be reparented (and renamed) which changes the entry. This can be
121-
* avoided by locking kernfs_root::kernfs_rwsem or kernfs_rename_lock.
127+
* avoided by locking kernfs_root::kernfs_rwsem or
128+
* kernfs_root::kernfs_rename_lock.
122129
* Both locks can be used to obtain a reference on __parent. Once the
123130
* reference count reaches 0 then the node is about to be freed
124131
* and can not be renamed (or become a different parent) anymore.
125132
*/
126133
return rcu_dereference_check(kn->__parent,
127134
kernfs_root_is_locked(kn) ||
128-
lockdep_is_held(&kernfs_rename_lock) ||
135+
kernfs_rename_is_locked(kn) ||
129136
!atomic_read(&kn->count));
130137
}
131138

0 commit comments

Comments
 (0)