Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Jinliang Zheng and committed by
Greg Kroah-Hartman
93b27a84 cec59c44

+19 -10
+8 -6
fs/kernfs/dir.c
··· 17 17 18 18 #include "kernfs-internal.h" 19 19 20 - DEFINE_RWLOCK(kernfs_rename_lock); /* kn->parent and ->name */ 21 20 /* 22 21 * Don't use rename_lock to piggy back on pr_cont_buf. We don't want to 23 22 * call pr_cont() while holding rename_lock. Because sometimes pr_cont() ··· 227 228 if (to) { 228 229 root = kernfs_root(to); 229 230 if (!(root->flags & KERNFS_ROOT_INVARIANT_PARENT)) { 230 - guard(read_lock_irqsave)(&kernfs_rename_lock); 231 + guard(read_lock_irqsave)(&root->kernfs_rename_lock); 231 232 return kernfs_path_from_node_locked(to, from, buf, buflen); 232 233 } 233 234 } ··· 294 295 struct kernfs_node *kernfs_get_parent(struct kernfs_node *kn) 295 296 { 296 297 struct kernfs_node *parent; 298 + struct kernfs_root *root; 297 299 unsigned long flags; 298 300 299 - read_lock_irqsave(&kernfs_rename_lock, flags); 301 + root = kernfs_root(kn); 302 + read_lock_irqsave(&root->kernfs_rename_lock, flags); 300 303 parent = kernfs_parent(kn); 301 304 kernfs_get(parent); 302 - read_unlock_irqrestore(&kernfs_rename_lock, flags); 305 + read_unlock_irqrestore(&root->kernfs_rename_lock, flags); 303 306 304 307 return parent; 305 308 } ··· 994 993 init_rwsem(&root->kernfs_iattr_rwsem); 995 994 init_rwsem(&root->kernfs_supers_rwsem); 996 995 INIT_LIST_HEAD(&root->supers); 996 + rwlock_init(&root->kernfs_rename_lock); 997 997 998 998 /* 999 999 * On 64bit ino setups, id is ino. On 32bit, low 32bits are ino. ··· 1791 1789 /* rename_lock protects ->parent accessors */ 1792 1790 if (old_parent != new_parent) { 1793 1791 kernfs_get(new_parent); 1794 - write_lock_irq(&kernfs_rename_lock); 1792 + write_lock_irq(&root->kernfs_rename_lock); 1795 1793 1796 1794 rcu_assign_pointer(kn->__parent, new_parent); 1797 1795 ··· 1799 1797 if (new_name) 1800 1798 rcu_assign_pointer(kn->name, new_name); 1801 1799 1802 - write_unlock_irq(&kernfs_rename_lock); 1800 + write_unlock_irq(&root->kernfs_rename_lock); 1803 1801 kernfs_put(old_parent); 1804 1802 } else { 1805 1803 /* name assignment is RCU protected, parent is the same */
+11 -4
fs/kernfs/kernfs-internal.h
··· 19 19 #include <linux/kernfs.h> 20 20 #include <linux/fs_context.h> 21 21 22 - extern rwlock_t kernfs_rename_lock; 23 - 24 22 struct kernfs_iattrs { 25 23 kuid_t ia_uid; 26 24 kgid_t ia_gid; ··· 50 52 struct rw_semaphore kernfs_rwsem; 51 53 struct rw_semaphore kernfs_iattr_rwsem; 52 54 struct rw_semaphore kernfs_supers_rwsem; 55 + 56 + /* kn->parent and kn->name */ 57 + rwlock_t kernfs_rename_lock; 53 58 54 59 struct rcu_head rcu; 55 60 }; ··· 109 108 return lockdep_is_held(&kernfs_root(kn)->kernfs_rwsem); 110 109 } 111 110 111 + static inline bool kernfs_rename_is_locked(const struct kernfs_node *kn) 112 + { 113 + return lockdep_is_held(&kernfs_root(kn)->kernfs_rename_lock); 114 + } 115 + 112 116 static inline const char *kernfs_rcu_name(const struct kernfs_node *kn) 113 117 { 114 118 return rcu_dereference_check(kn->name, kernfs_root_is_locked(kn)); ··· 124 118 /* 125 119 * The kernfs_node::__parent remains valid within a RCU section. The kn 126 120 * can be reparented (and renamed) which changes the entry. This can be 127 - * avoided by locking kernfs_root::kernfs_rwsem or kernfs_rename_lock. 121 + * avoided by locking kernfs_root::kernfs_rwsem or 122 + * kernfs_root::kernfs_rename_lock. 128 123 * Both locks can be used to obtain a reference on __parent. Once the 129 124 * reference count reaches 0 then the node is about to be freed 130 125 * and can not be renamed (or become a different parent) anymore. 131 126 */ 132 127 return rcu_dereference_check(kn->__parent, 133 128 kernfs_root_is_locked(kn) || 134 - lockdep_is_held(&kernfs_rename_lock) || 129 + kernfs_rename_is_locked(kn) || 135 130 !atomic_read(&kn->count)); 136 131 } 137 132