diff options
author | Jinliang Zheng <alexjlzheng@tencent.com> | 2025-04-15 23:36:59 +0800 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2025-04-25 16:01:57 +0200 |
commit | 93b27a845ec1355459e6aa539dd203a2f5136d8f (patch) | |
tree | d5db22f2abdf9e28e751befd1205ab3c553f22d8 | |
parent | cec59c440a05c241846e8fe9d2575a2dafb56fd9 (diff) |
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>
-rw-r--r-- | fs/kernfs/dir.c | 14 | ||||
-rw-r--r-- | fs/kernfs/kernfs-internal.h | 15 |
2 files changed, 19 insertions, 10 deletions
diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index 355d943ffe27..d63a96786c9b 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c @@ -17,7 +17,6 @@ #include "kernfs-internal.h" -DEFINE_RWLOCK(kernfs_rename_lock); /* kn->parent and ->name */ /* * Don't use rename_lock to piggy back on pr_cont_buf. We don't want to * 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, if (to) { root = kernfs_root(to); if (!(root->flags & KERNFS_ROOT_INVARIANT_PARENT)) { - guard(read_lock_irqsave)(&kernfs_rename_lock); + guard(read_lock_irqsave)(&root->kernfs_rename_lock); return kernfs_path_from_node_locked(to, from, buf, buflen); } } @@ -295,12 +294,14 @@ out: struct kernfs_node *kernfs_get_parent(struct kernfs_node *kn) { struct kernfs_node *parent; + struct kernfs_root *root; unsigned long flags; - read_lock_irqsave(&kernfs_rename_lock, flags); + root = kernfs_root(kn); + read_lock_irqsave(&root->kernfs_rename_lock, flags); parent = kernfs_parent(kn); kernfs_get(parent); - read_unlock_irqrestore(&kernfs_rename_lock, flags); + read_unlock_irqrestore(&root->kernfs_rename_lock, flags); return parent; } @@ -993,6 +994,7 @@ struct kernfs_root *kernfs_create_root(struct kernfs_syscall_ops *scops, init_rwsem(&root->kernfs_iattr_rwsem); init_rwsem(&root->kernfs_supers_rwsem); INIT_LIST_HEAD(&root->supers); + rwlock_init(&root->kernfs_rename_lock); /* * On 64bit ino setups, id is ino. On 32bit, low 32bits are ino. @@ -1789,7 +1791,7 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent, /* rename_lock protects ->parent accessors */ if (old_parent != new_parent) { kernfs_get(new_parent); - write_lock_irq(&kernfs_rename_lock); + write_lock_irq(&root->kernfs_rename_lock); rcu_assign_pointer(kn->__parent, new_parent); @@ -1797,7 +1799,7 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent, if (new_name) rcu_assign_pointer(kn->name, new_name); - write_unlock_irq(&kernfs_rename_lock); + write_unlock_irq(&root->kernfs_rename_lock); kernfs_put(old_parent); } else { /* name assignment is RCU protected, parent is the same */ diff --git a/fs/kernfs/kernfs-internal.h b/fs/kernfs/kernfs-internal.h index 24e9514565ac..6061b6f70d2a 100644 --- a/fs/kernfs/kernfs-internal.h +++ b/fs/kernfs/kernfs-internal.h @@ -19,8 +19,6 @@ #include <linux/kernfs.h> #include <linux/fs_context.h> -extern rwlock_t kernfs_rename_lock; - struct kernfs_iattrs { kuid_t ia_uid; kgid_t ia_gid; @@ -53,6 +51,9 @@ struct kernfs_root { struct rw_semaphore kernfs_iattr_rwsem; struct rw_semaphore kernfs_supers_rwsem; + /* kn->parent and kn->name */ + rwlock_t kernfs_rename_lock; + struct rcu_head rcu; }; @@ -108,6 +109,11 @@ static inline bool kernfs_root_is_locked(const struct kernfs_node *kn) return lockdep_is_held(&kernfs_root(kn)->kernfs_rwsem); } +static inline bool kernfs_rename_is_locked(const struct kernfs_node *kn) +{ + return lockdep_is_held(&kernfs_root(kn)->kernfs_rename_lock); +} + static inline const char *kernfs_rcu_name(const struct kernfs_node *kn) { 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) /* * The kernfs_node::__parent remains valid within a RCU section. The kn * can be reparented (and renamed) which changes the entry. This can be - * avoided by locking kernfs_root::kernfs_rwsem or kernfs_rename_lock. + * avoided by locking kernfs_root::kernfs_rwsem or + * kernfs_root::kernfs_rename_lock. * Both locks can be used to obtain a reference on __parent. Once the * reference count reaches 0 then the node is about to be freed * and can not be renamed (or become a different parent) anymore. */ return rcu_dereference_check(kn->__parent, kernfs_root_is_locked(kn) || - lockdep_is_held(&kernfs_rename_lock) || + kernfs_rename_is_locked(kn) || !atomic_read(&kn->count)); } |