From 14fc977bf0e5642172709bbe8d943359471c5817 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 23 May 2025 14:34:21 +0200 Subject: [PATCH] drop kernfs patches --- ...ernfs_rwsem-in-kernfs_get_parent_den.patch | 41 - ...lock-kernfs_root-kernfs_rwsem-in-ker.patch | 56 - queue-6.1/series | 2 - ...ernfs_rwsem-in-kernfs_get_parent_den.patch | 41 - ...e-kernfs_rwsem-in-kernfs_node_dentry.patch | 49 - ...kernfs_rwsem-in-kernfs_notify_workfn.patch | 47 - ...lock-kernfs_root-kernfs_rwsem-in-ker.patch | 56 - ...use-rcu-to-access-kernfs_node-parent.patch | 988 ----------------- queue-6.12/series | 5 - ...ernfs_rwsem-in-kernfs_get_parent_den.patch | 41 - ...e-kernfs_rwsem-in-kernfs_node_dentry.patch | 49 - ...kernfs_rwsem-in-kernfs_notify_workfn.patch | 47 - ...lock-kernfs_root-kernfs_rwsem-in-ker.patch | 56 - ...fs_rwsem-while-invoking-lookup_posit.patch | 98 -- ...s-use-rcu-to-access-kernfs_node-name.patch | 596 ----------- ...use-rcu-to-access-kernfs_node-parent.patch | 989 ------------------ queue-6.14/series | 7 - ...ernfs_rwsem-in-kernfs_get_parent_den.patch | 41 - ...kernfs_rwsem-in-kernfs_notify_workfn.patch | 47 - ...lock-kernfs_root-kernfs_rwsem-in-ker.patch | 56 - queue-6.6/series | 3 - 21 files changed, 3315 deletions(-) delete mode 100644 queue-6.1/kernfs-acquire-kernfs_rwsem-in-kernfs_get_parent_den.patch delete mode 100644 queue-6.1/kernfs-don-t-re-lock-kernfs_root-kernfs_rwsem-in-ker.patch delete mode 100644 queue-6.12/kernfs-acquire-kernfs_rwsem-in-kernfs_get_parent_den.patch delete mode 100644 queue-6.12/kernfs-acquire-kernfs_rwsem-in-kernfs_node_dentry.patch delete mode 100644 queue-6.12/kernfs-acquire-kernfs_rwsem-in-kernfs_notify_workfn.patch delete mode 100644 queue-6.12/kernfs-don-t-re-lock-kernfs_root-kernfs_rwsem-in-ker.patch delete mode 100644 queue-6.12/kernfs-use-rcu-to-access-kernfs_node-parent.patch delete mode 100644 queue-6.14/kernfs-acquire-kernfs_rwsem-in-kernfs_get_parent_den.patch delete mode 100644 queue-6.14/kernfs-acquire-kernfs_rwsem-in-kernfs_node_dentry.patch delete mode 100644 queue-6.14/kernfs-acquire-kernfs_rwsem-in-kernfs_notify_workfn.patch delete mode 100644 queue-6.14/kernfs-don-t-re-lock-kernfs_root-kernfs_rwsem-in-ker.patch delete mode 100644 queue-6.14/kernfs-drop-kernfs_rwsem-while-invoking-lookup_posit.patch delete mode 100644 queue-6.14/kernfs-use-rcu-to-access-kernfs_node-name.patch delete mode 100644 queue-6.14/kernfs-use-rcu-to-access-kernfs_node-parent.patch delete mode 100644 queue-6.6/kernfs-acquire-kernfs_rwsem-in-kernfs_get_parent_den.patch delete mode 100644 queue-6.6/kernfs-acquire-kernfs_rwsem-in-kernfs_notify_workfn.patch delete mode 100644 queue-6.6/kernfs-don-t-re-lock-kernfs_root-kernfs_rwsem-in-ker.patch diff --git a/queue-6.1/kernfs-acquire-kernfs_rwsem-in-kernfs_get_parent_den.patch b/queue-6.1/kernfs-acquire-kernfs_rwsem-in-kernfs_get_parent_den.patch deleted file mode 100644 index 87197dc192..0000000000 --- a/queue-6.1/kernfs-acquire-kernfs_rwsem-in-kernfs_get_parent_den.patch +++ /dev/null @@ -1,41 +0,0 @@ -From e0f075353e977224e46dece88be33f30b3e4740b Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Thu, 13 Feb 2025 15:50:19 +0100 -Subject: kernfs: Acquire kernfs_rwsem in kernfs_get_parent_dentry(). - -From: Sebastian Andrzej Siewior - -[ Upstream commit 122ab92dee80582c39740609a627198dd5b6b595 ] - -kernfs_get_parent_dentry() passes kernfs_node::parent to -kernfs_get_inode(). - -Acquire kernfs_root::kernfs_rwsem to ensure kernfs_node::parent isn't -replaced during the operation. - -Acked-by: Tejun Heo -Signed-off-by: Sebastian Andrzej Siewior -Link: https://lore.kernel.org/r/20250213145023.2820193-3-bigeasy@linutronix.de -Signed-off-by: Greg Kroah-Hartman -Signed-off-by: Sasha Levin ---- - fs/kernfs/mount.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c -index e08e8d9998070..0c98621a17a80 100644 ---- a/fs/kernfs/mount.c -+++ b/fs/kernfs/mount.c -@@ -138,7 +138,9 @@ static struct dentry *kernfs_fh_to_parent(struct super_block *sb, - static struct dentry *kernfs_get_parent_dentry(struct dentry *child) - { - struct kernfs_node *kn = kernfs_dentry_node(child); -+ struct kernfs_root *root = kernfs_root(kn); - -+ guard(rwsem_read)(&root->kernfs_rwsem); - return d_obtain_alias(kernfs_get_inode(child->d_sb, kn->parent)); - } - --- -2.39.5 - diff --git a/queue-6.1/kernfs-don-t-re-lock-kernfs_root-kernfs_rwsem-in-ker.patch b/queue-6.1/kernfs-don-t-re-lock-kernfs_root-kernfs_rwsem-in-ker.patch deleted file mode 100644 index 9dffbca1ae..0000000000 --- a/queue-6.1/kernfs-don-t-re-lock-kernfs_root-kernfs_rwsem-in-ker.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 2af692751023f0622caf0b54fae36902c66bb9e4 Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Thu, 13 Feb 2025 15:50:21 +0100 -Subject: kernfs: Don't re-lock kernfs_root::kernfs_rwsem in - kernfs_fop_readdir(). - -From: Sebastian Andrzej Siewior - -[ Upstream commit 9aab10a0249eab4ec77c6a5e4f66442610c12a09 ] - -The readdir operation iterates over all entries and invokes dir_emit() -for every entry passing kernfs_node::name as argument. -Since the name argument can change, and become invalid, the -kernfs_root::kernfs_rwsem lock should not be dropped to prevent renames -during the operation. - -The lock drop around dir_emit() has been initially introduced in commit - 1e5289c97bba2 ("sysfs: Cache the last sysfs_dirent to improve readdir scalability v2") - -to avoid holding a global lock during a page fault. The lock drop is -wrong since the support of renames and not a big burden since the lock -is no longer global. - -Don't re-acquire kernfs_root::kernfs_rwsem while copying the name to the -userpace buffer. - -Acked-by: Tejun Heo -Signed-off-by: Sebastian Andrzej Siewior -Link: https://lore.kernel.org/r/20250213145023.2820193-5-bigeasy@linutronix.de -Signed-off-by: Greg Kroah-Hartman -Signed-off-by: Sasha Levin ---- - fs/kernfs/dir.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c -index 2c74b24fc22aa..6ddab75a68dd2 100644 ---- a/fs/kernfs/dir.c -+++ b/fs/kernfs/dir.c -@@ -1846,10 +1846,10 @@ static int kernfs_fop_readdir(struct file *file, struct dir_context *ctx) - file->private_data = pos; - kernfs_get(pos); - -- up_read(&root->kernfs_rwsem); -- if (!dir_emit(ctx, name, len, ino, type)) -+ if (!dir_emit(ctx, name, len, ino, type)) { -+ up_read(&root->kernfs_rwsem); - return 0; -- down_read(&root->kernfs_rwsem); -+ } - } - up_read(&root->kernfs_rwsem); - file->private_data = NULL; --- -2.39.5 - diff --git a/queue-6.1/series b/queue-6.1/series index 97b73f100a..2afdd7c76c 100644 --- a/queue-6.1/series +++ b/queue-6.1/series @@ -174,8 +174,6 @@ asoc-soc-dai-check-return-value-at-snd_soc_dai_set_t.patch pinctrl-devicetree-do-not-goto-err-when-probing-hogs.patch smack-recognize-ipv4-cipso-w-o-categories.patch kunit-tool-use-qboot-on-qemu-x86_64.patch -kernfs-don-t-re-lock-kernfs_root-kernfs_rwsem-in-ker.patch -kernfs-acquire-kernfs_rwsem-in-kernfs_get_parent_den.patch libbpf-fix-ldx-stx-st-co-re-relocation-size-adjustme.patch net-mlx4_core-avoid-impossible-mlx4_db_alloc-order-v.patch clk-qcom-clk-alpha-pll-do-not-use-random-stack-value.patch diff --git a/queue-6.12/kernfs-acquire-kernfs_rwsem-in-kernfs_get_parent_den.patch b/queue-6.12/kernfs-acquire-kernfs_rwsem-in-kernfs_get_parent_den.patch deleted file mode 100644 index 61c00e7d10..0000000000 --- a/queue-6.12/kernfs-acquire-kernfs_rwsem-in-kernfs_get_parent_den.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 47f4808a74c1abb8ff4a358d4a3fa28e5aec9039 Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Thu, 13 Feb 2025 15:50:19 +0100 -Subject: kernfs: Acquire kernfs_rwsem in kernfs_get_parent_dentry(). - -From: Sebastian Andrzej Siewior - -[ Upstream commit 122ab92dee80582c39740609a627198dd5b6b595 ] - -kernfs_get_parent_dentry() passes kernfs_node::parent to -kernfs_get_inode(). - -Acquire kernfs_root::kernfs_rwsem to ensure kernfs_node::parent isn't -replaced during the operation. - -Acked-by: Tejun Heo -Signed-off-by: Sebastian Andrzej Siewior -Link: https://lore.kernel.org/r/20250213145023.2820193-3-bigeasy@linutronix.de -Signed-off-by: Greg Kroah-Hartman -Signed-off-by: Sasha Levin ---- - fs/kernfs/mount.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c -index 0f6379ae258d1..4a0ff08d589ca 100644 ---- a/fs/kernfs/mount.c -+++ b/fs/kernfs/mount.c -@@ -145,7 +145,9 @@ static struct dentry *kernfs_fh_to_parent(struct super_block *sb, - static struct dentry *kernfs_get_parent_dentry(struct dentry *child) - { - struct kernfs_node *kn = kernfs_dentry_node(child); -+ struct kernfs_root *root = kernfs_root(kn); - -+ guard(rwsem_read)(&root->kernfs_rwsem); - return d_obtain_alias(kernfs_get_inode(child->d_sb, kn->parent)); - } - --- -2.39.5 - diff --git a/queue-6.12/kernfs-acquire-kernfs_rwsem-in-kernfs_node_dentry.patch b/queue-6.12/kernfs-acquire-kernfs_rwsem-in-kernfs_node_dentry.patch deleted file mode 100644 index 1061f23182..0000000000 --- a/queue-6.12/kernfs-acquire-kernfs_rwsem-in-kernfs_node_dentry.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 9bb7d9f7370173a25f5494ebd70085a8a54e33bb Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Thu, 13 Feb 2025 15:50:20 +0100 -Subject: kernfs: Acquire kernfs_rwsem in kernfs_node_dentry(). - -From: Sebastian Andrzej Siewior - -[ Upstream commit 5b2fabf7fe8f745ff214ff003e6067b64f172271 ] - -kernfs_node_dentry() passes kernfs_node::name to -lookup_positive_unlocked(). - -Acquire kernfs_root::kernfs_rwsem to ensure the node is not renamed -during the operation. - -Acked-by: Tejun Heo -Signed-off-by: Sebastian Andrzej Siewior -Link: https://lore.kernel.org/r/20250213145023.2820193-4-bigeasy@linutronix.de -Signed-off-by: Greg Kroah-Hartman -Signed-off-by: Sasha Levin ---- - fs/kernfs/mount.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c -index 1358c21837f1a..0f6379ae258d1 100644 ---- a/fs/kernfs/mount.c -+++ b/fs/kernfs/mount.c -@@ -207,6 +207,7 @@ struct dentry *kernfs_node_dentry(struct kernfs_node *kn, - { - struct dentry *dentry; - struct kernfs_node *knparent; -+ struct kernfs_root *root; - - BUG_ON(sb->s_op != &kernfs_sops); - -@@ -216,6 +217,9 @@ struct dentry *kernfs_node_dentry(struct kernfs_node *kn, - if (!kn->parent) - return dentry; - -+ root = kernfs_root(kn); -+ guard(rwsem_read)(&root->kernfs_rwsem); -+ - knparent = find_next_ancestor(kn, NULL); - if (WARN_ON(!knparent)) { - dput(dentry); --- -2.39.5 - diff --git a/queue-6.12/kernfs-acquire-kernfs_rwsem-in-kernfs_notify_workfn.patch b/queue-6.12/kernfs-acquire-kernfs_rwsem-in-kernfs_notify_workfn.patch deleted file mode 100644 index ef962184bf..0000000000 --- a/queue-6.12/kernfs-acquire-kernfs_rwsem-in-kernfs_notify_workfn.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 079fbf2ff1f0e3107a47874c3cb8ee013bf89409 Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Thu, 13 Feb 2025 15:50:18 +0100 -Subject: kernfs: Acquire kernfs_rwsem in kernfs_notify_workfn(). - -From: Sebastian Andrzej Siewior - -[ Upstream commit 400188ae361a9d9a72a47a6cedaf2d2efcc84aa8 ] - -kernfs_notify_workfn() dereferences kernfs_node::name and passes it -later to fsnotify(). If the node is renamed then the previously observed -name pointer becomes invalid. - -Acquire kernfs_root::kernfs_rwsem to block renames of the node. - -Acked-by: Tejun Heo -Signed-off-by: Sebastian Andrzej Siewior -Link: https://lore.kernel.org/r/20250213145023.2820193-2-bigeasy@linutronix.de -Signed-off-by: Greg Kroah-Hartman -Signed-off-by: Sasha Levin ---- - fs/kernfs/file.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c -index 8502ef68459b9..165d8e37976ba 100644 ---- a/fs/kernfs/file.c -+++ b/fs/kernfs/file.c -@@ -911,6 +911,7 @@ static void kernfs_notify_workfn(struct work_struct *work) - /* kick fsnotify */ - - down_read(&root->kernfs_supers_rwsem); -+ down_read(&root->kernfs_rwsem); - list_for_each_entry(info, &kernfs_root(kn)->supers, node) { - struct kernfs_node *parent; - struct inode *p_inode = NULL; -@@ -947,6 +948,7 @@ static void kernfs_notify_workfn(struct work_struct *work) - iput(inode); - } - -+ up_read(&root->kernfs_rwsem); - up_read(&root->kernfs_supers_rwsem); - kernfs_put(kn); - goto repeat; --- -2.39.5 - diff --git a/queue-6.12/kernfs-don-t-re-lock-kernfs_root-kernfs_rwsem-in-ker.patch b/queue-6.12/kernfs-don-t-re-lock-kernfs_root-kernfs_rwsem-in-ker.patch deleted file mode 100644 index c1741ed7ba..0000000000 --- a/queue-6.12/kernfs-don-t-re-lock-kernfs_root-kernfs_rwsem-in-ker.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 6247ef751c277b43adbe8b0e75696f1e59cf2921 Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Thu, 13 Feb 2025 15:50:21 +0100 -Subject: kernfs: Don't re-lock kernfs_root::kernfs_rwsem in - kernfs_fop_readdir(). - -From: Sebastian Andrzej Siewior - -[ Upstream commit 9aab10a0249eab4ec77c6a5e4f66442610c12a09 ] - -The readdir operation iterates over all entries and invokes dir_emit() -for every entry passing kernfs_node::name as argument. -Since the name argument can change, and become invalid, the -kernfs_root::kernfs_rwsem lock should not be dropped to prevent renames -during the operation. - -The lock drop around dir_emit() has been initially introduced in commit - 1e5289c97bba2 ("sysfs: Cache the last sysfs_dirent to improve readdir scalability v2") - -to avoid holding a global lock during a page fault. The lock drop is -wrong since the support of renames and not a big burden since the lock -is no longer global. - -Don't re-acquire kernfs_root::kernfs_rwsem while copying the name to the -userpace buffer. - -Acked-by: Tejun Heo -Signed-off-by: Sebastian Andrzej Siewior -Link: https://lore.kernel.org/r/20250213145023.2820193-5-bigeasy@linutronix.de -Signed-off-by: Greg Kroah-Hartman -Signed-off-by: Sasha Levin ---- - fs/kernfs/dir.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c -index 458519e416fe7..5a1fea414996e 100644 ---- a/fs/kernfs/dir.c -+++ b/fs/kernfs/dir.c -@@ -1868,10 +1868,10 @@ static int kernfs_fop_readdir(struct file *file, struct dir_context *ctx) - file->private_data = pos; - kernfs_get(pos); - -- up_read(&root->kernfs_rwsem); -- if (!dir_emit(ctx, name, len, ino, type)) -+ if (!dir_emit(ctx, name, len, ino, type)) { -+ up_read(&root->kernfs_rwsem); - return 0; -- down_read(&root->kernfs_rwsem); -+ } - } - up_read(&root->kernfs_rwsem); - file->private_data = NULL; --- -2.39.5 - diff --git a/queue-6.12/kernfs-use-rcu-to-access-kernfs_node-parent.patch b/queue-6.12/kernfs-use-rcu-to-access-kernfs_node-parent.patch deleted file mode 100644 index e06cb323e0..0000000000 --- a/queue-6.12/kernfs-use-rcu-to-access-kernfs_node-parent.patch +++ /dev/null @@ -1,988 +0,0 @@ -From 10d6731fc902f64ab2457c34c7d2cd1503e9cc34 Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Thu, 13 Feb 2025 15:50:22 +0100 -Subject: kernfs: Use RCU to access kernfs_node::parent. - -From: Sebastian Andrzej Siewior - -[ Upstream commit 633488947ef66b194377411322dc9e12aab79b65 ] - -kernfs_rename_lock is used to obtain stable kernfs_node::{name|parent} -pointer. This is a preparation to access kernfs_node::parent under RCU -and ensure that the pointer remains stable under the RCU lifetime -guarantees. - -For a complete path, as it is done in kernfs_path_from_node(), the -kernfs_rename_lock is still required in order to obtain a stable parent -relationship while computing the relevant node depth. This must not -change while the nodes are inspected in order to build the path. -If the kernfs user never moves the nodes (changes the parent) then the -kernfs_rename_lock is not required and the RCU guarantees are -sufficient. This "restriction" can be set with -KERNFS_ROOT_INVARIANT_PARENT. Otherwise the lock is required. - -Rename kernfs_node::parent to kernfs_node::__parent to denote the RCU -access and use RCU accessor while accessing the node. -Make cgroup use KERNFS_ROOT_INVARIANT_PARENT since the parent here can -not change. - -Acked-by: Tejun Heo -Cc: Yonghong Song -Signed-off-by: Sebastian Andrzej Siewior -Link: https://lore.kernel.org/r/20250213145023.2820193-6-bigeasy@linutronix.de -Signed-off-by: Greg Kroah-Hartman -Signed-off-by: Sasha Levin ---- - arch/x86/kernel/cpu/resctrl/rdtgroup.c | 65 +++++++++---- - fs/kernfs/dir.c | 96 ++++++++++++------- - fs/kernfs/kernfs-internal.h | 32 ++++++- - fs/kernfs/mount.c | 10 +- - fs/kernfs/symlink.c | 23 ++--- - fs/sysfs/file.c | 24 +++-- - include/linux/kernfs.h | 10 +- - kernel/cgroup/cgroup-v1.c | 2 +- - kernel/cgroup/cgroup.c | 24 ++++- - .../selftests/bpf/progs/profiler.inc.h | 2 +- - 10 files changed, 195 insertions(+), 93 deletions(-) - -diff --git a/arch/x86/kernel/cpu/resctrl/rdtgroup.c b/arch/x86/kernel/cpu/resctrl/rdtgroup.c -index 2d48db66fca85..d4d7ccf1253b8 100644 ---- a/arch/x86/kernel/cpu/resctrl/rdtgroup.c -+++ b/arch/x86/kernel/cpu/resctrl/rdtgroup.c -@@ -948,10 +948,20 @@ static int rdt_last_cmd_status_show(struct kernfs_open_file *of, - return 0; - } - -+static void *rdt_kn_parent_priv(struct kernfs_node *kn) -+{ -+ /* -+ * The parent pointer is only valid within RCU section since it can be -+ * replaced. -+ */ -+ guard(rcu)(); -+ return rcu_dereference(kn->__parent)->priv; -+} -+ - static int rdt_num_closids_show(struct kernfs_open_file *of, - struct seq_file *seq, void *v) - { -- struct resctrl_schema *s = of->kn->parent->priv; -+ struct resctrl_schema *s = rdt_kn_parent_priv(of->kn); - - seq_printf(seq, "%u\n", s->num_closid); - return 0; -@@ -960,7 +970,7 @@ static int rdt_num_closids_show(struct kernfs_open_file *of, - static int rdt_default_ctrl_show(struct kernfs_open_file *of, - struct seq_file *seq, void *v) - { -- struct resctrl_schema *s = of->kn->parent->priv; -+ struct resctrl_schema *s = rdt_kn_parent_priv(of->kn); - struct rdt_resource *r = s->res; - - seq_printf(seq, "%x\n", r->default_ctrl); -@@ -970,7 +980,7 @@ static int rdt_default_ctrl_show(struct kernfs_open_file *of, - static int rdt_min_cbm_bits_show(struct kernfs_open_file *of, - struct seq_file *seq, void *v) - { -- struct resctrl_schema *s = of->kn->parent->priv; -+ struct resctrl_schema *s = rdt_kn_parent_priv(of->kn); - struct rdt_resource *r = s->res; - - seq_printf(seq, "%u\n", r->cache.min_cbm_bits); -@@ -980,7 +990,7 @@ static int rdt_min_cbm_bits_show(struct kernfs_open_file *of, - static int rdt_shareable_bits_show(struct kernfs_open_file *of, - struct seq_file *seq, void *v) - { -- struct resctrl_schema *s = of->kn->parent->priv; -+ struct resctrl_schema *s = rdt_kn_parent_priv(of->kn); - struct rdt_resource *r = s->res; - - seq_printf(seq, "%x\n", r->cache.shareable_bits); -@@ -1004,7 +1014,7 @@ static int rdt_shareable_bits_show(struct kernfs_open_file *of, - static int rdt_bit_usage_show(struct kernfs_open_file *of, - struct seq_file *seq, void *v) - { -- struct resctrl_schema *s = of->kn->parent->priv; -+ struct resctrl_schema *s = rdt_kn_parent_priv(of->kn); - /* - * Use unsigned long even though only 32 bits are used to ensure - * test_bit() is used safely. -@@ -1086,7 +1096,7 @@ static int rdt_bit_usage_show(struct kernfs_open_file *of, - static int rdt_min_bw_show(struct kernfs_open_file *of, - struct seq_file *seq, void *v) - { -- struct resctrl_schema *s = of->kn->parent->priv; -+ struct resctrl_schema *s = rdt_kn_parent_priv(of->kn); - struct rdt_resource *r = s->res; - - seq_printf(seq, "%u\n", r->membw.min_bw); -@@ -1096,7 +1106,7 @@ static int rdt_min_bw_show(struct kernfs_open_file *of, - static int rdt_num_rmids_show(struct kernfs_open_file *of, - struct seq_file *seq, void *v) - { -- struct rdt_resource *r = of->kn->parent->priv; -+ struct rdt_resource *r = rdt_kn_parent_priv(of->kn); - - seq_printf(seq, "%d\n", r->num_rmid); - -@@ -1106,7 +1116,7 @@ static int rdt_num_rmids_show(struct kernfs_open_file *of, - static int rdt_mon_features_show(struct kernfs_open_file *of, - struct seq_file *seq, void *v) - { -- struct rdt_resource *r = of->kn->parent->priv; -+ struct rdt_resource *r = rdt_kn_parent_priv(of->kn); - struct mon_evt *mevt; - - list_for_each_entry(mevt, &r->evt_list, list) { -@@ -1121,7 +1131,7 @@ static int rdt_mon_features_show(struct kernfs_open_file *of, - static int rdt_bw_gran_show(struct kernfs_open_file *of, - struct seq_file *seq, void *v) - { -- struct resctrl_schema *s = of->kn->parent->priv; -+ struct resctrl_schema *s = rdt_kn_parent_priv(of->kn); - struct rdt_resource *r = s->res; - - seq_printf(seq, "%u\n", r->membw.bw_gran); -@@ -1131,7 +1141,7 @@ static int rdt_bw_gran_show(struct kernfs_open_file *of, - static int rdt_delay_linear_show(struct kernfs_open_file *of, - struct seq_file *seq, void *v) - { -- struct resctrl_schema *s = of->kn->parent->priv; -+ struct resctrl_schema *s = rdt_kn_parent_priv(of->kn); - struct rdt_resource *r = s->res; - - seq_printf(seq, "%u\n", r->membw.delay_linear); -@@ -1149,7 +1159,7 @@ static int max_threshold_occ_show(struct kernfs_open_file *of, - static int rdt_thread_throttle_mode_show(struct kernfs_open_file *of, - struct seq_file *seq, void *v) - { -- struct resctrl_schema *s = of->kn->parent->priv; -+ struct resctrl_schema *s = rdt_kn_parent_priv(of->kn); - struct rdt_resource *r = s->res; - - if (r->membw.throttle_mode == THREAD_THROTTLE_PER_THREAD) -@@ -1214,7 +1224,7 @@ static enum resctrl_conf_type resctrl_peer_type(enum resctrl_conf_type my_type) - static int rdt_has_sparse_bitmasks_show(struct kernfs_open_file *of, - struct seq_file *seq, void *v) - { -- struct resctrl_schema *s = of->kn->parent->priv; -+ struct resctrl_schema *s = rdt_kn_parent_priv(of->kn); - struct rdt_resource *r = s->res; - - seq_printf(seq, "%u\n", r->cache.arch_has_sparse_bitmasks); -@@ -1626,7 +1636,7 @@ static int mbm_config_show(struct seq_file *s, struct rdt_resource *r, u32 evtid - static int mbm_total_bytes_config_show(struct kernfs_open_file *of, - struct seq_file *seq, void *v) - { -- struct rdt_resource *r = of->kn->parent->priv; -+ struct rdt_resource *r = rdt_kn_parent_priv(of->kn); - - mbm_config_show(seq, r, QOS_L3_MBM_TOTAL_EVENT_ID); - -@@ -1636,7 +1646,7 @@ static int mbm_total_bytes_config_show(struct kernfs_open_file *of, - static int mbm_local_bytes_config_show(struct kernfs_open_file *of, - struct seq_file *seq, void *v) - { -- struct rdt_resource *r = of->kn->parent->priv; -+ struct rdt_resource *r = rdt_kn_parent_priv(of->kn); - - mbm_config_show(seq, r, QOS_L3_MBM_LOCAL_EVENT_ID); - -@@ -1742,7 +1752,7 @@ static ssize_t mbm_total_bytes_config_write(struct kernfs_open_file *of, - char *buf, size_t nbytes, - loff_t off) - { -- struct rdt_resource *r = of->kn->parent->priv; -+ struct rdt_resource *r = rdt_kn_parent_priv(of->kn); - int ret; - - /* Valid input requires a trailing newline */ -@@ -1768,7 +1778,7 @@ static ssize_t mbm_local_bytes_config_write(struct kernfs_open_file *of, - char *buf, size_t nbytes, - loff_t off) - { -- struct rdt_resource *r = of->kn->parent->priv; -+ struct rdt_resource *r = rdt_kn_parent_priv(of->kn); - int ret; - - /* Valid input requires a trailing newline */ -@@ -2430,12 +2440,13 @@ static struct rdtgroup *kernfs_to_rdtgroup(struct kernfs_node *kn) - * resource. "info" and its subdirectories don't - * have rdtgroup structures, so return NULL here. - */ -- if (kn == kn_info || kn->parent == kn_info) -+ if (kn == kn_info || -+ rcu_access_pointer(kn->__parent) == kn_info) - return NULL; - else - return kn->priv; - } else { -- return kn->parent->priv; -+ return rdt_kn_parent_priv(kn); - } - } - -@@ -3759,9 +3770,18 @@ static int rdtgroup_rmdir_ctrl(struct rdtgroup *rdtgrp, cpumask_var_t tmpmask) - return 0; - } - -+static struct kernfs_node *rdt_kn_parent(struct kernfs_node *kn) -+{ -+ /* -+ * Valid within the RCU section it was obtained or while rdtgroup_mutex -+ * is held. -+ */ -+ return rcu_dereference_check(kn->__parent, lockdep_is_held(&rdtgroup_mutex)); -+} -+ - static int rdtgroup_rmdir(struct kernfs_node *kn) - { -- struct kernfs_node *parent_kn = kn->parent; -+ struct kernfs_node *parent_kn; - struct rdtgroup *rdtgrp; - cpumask_var_t tmpmask; - int ret = 0; -@@ -3774,6 +3794,7 @@ static int rdtgroup_rmdir(struct kernfs_node *kn) - ret = -EPERM; - goto out; - } -+ parent_kn = rdt_kn_parent(kn); - - /* - * If the rdtgroup is a ctrl_mon group and parent directory -@@ -3842,6 +3863,7 @@ static void mongrp_reparent(struct rdtgroup *rdtgrp, - static int rdtgroup_rename(struct kernfs_node *kn, - struct kernfs_node *new_parent, const char *new_name) - { -+ struct kernfs_node *kn_parent; - struct rdtgroup *new_prdtgrp; - struct rdtgroup *rdtgrp; - cpumask_var_t tmpmask; -@@ -3876,8 +3898,9 @@ static int rdtgroup_rename(struct kernfs_node *kn, - goto out; - } - -- if (rdtgrp->type != RDTMON_GROUP || !kn->parent || -- !is_mon_groups(kn->parent, kn->name)) { -+ kn_parent = rdt_kn_parent(kn); -+ if (rdtgrp->type != RDTMON_GROUP || !kn_parent || -+ !is_mon_groups(kn_parent, kn->name)) { - rdt_last_cmd_puts("Source must be a MON group\n"); - ret = -EPERM; - goto out; -diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c -index 5a1fea414996e..d2306641b569c 100644 ---- a/fs/kernfs/dir.c -+++ b/fs/kernfs/dir.c -@@ -17,7 +17,7 @@ - - #include "kernfs-internal.h" - --static DEFINE_RWLOCK(kernfs_rename_lock); /* kn->parent and ->name */ -+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() -@@ -56,7 +56,7 @@ static int kernfs_name_locked(struct kernfs_node *kn, char *buf, size_t buflen) - if (!kn) - return strscpy(buf, "(null)", buflen); - -- return strscpy(buf, kn->parent ? kn->name : "/", buflen); -+ return strscpy(buf, rcu_access_pointer(kn->__parent) ? kn->name : "/", buflen); - } - - /* kernfs_node_depth - compute depth from @from to @to */ -@@ -64,9 +64,9 @@ static size_t kernfs_depth(struct kernfs_node *from, struct kernfs_node *to) - { - size_t depth = 0; - -- while (to->parent && to != from) { -+ while (rcu_dereference(to->__parent) && to != from) { - depth++; -- to = to->parent; -+ to = rcu_dereference(to->__parent); - } - return depth; - } -@@ -84,18 +84,18 @@ static struct kernfs_node *kernfs_common_ancestor(struct kernfs_node *a, - db = kernfs_depth(rb->kn, b); - - while (da > db) { -- a = a->parent; -+ a = rcu_dereference(a->__parent); - da--; - } - while (db > da) { -- b = b->parent; -+ b = rcu_dereference(b->__parent); - db--; - } - - /* worst case b and a will be the same at root */ - while (b != a) { -- b = b->parent; -- a = a->parent; -+ b = rcu_dereference(b->__parent); -+ a = rcu_dereference(a->__parent); - } - - return a; -@@ -168,8 +168,9 @@ static int kernfs_path_from_node_locked(struct kernfs_node *kn_to, - - /* Calculate how many bytes we need for the rest */ - for (i = depth_to - 1; i >= 0; i--) { -+ - for (kn = kn_to, j = 0; j < i; j++) -- kn = kn->parent; -+ kn = rcu_dereference(kn->__parent); - - len += scnprintf(buf + len, buflen - len, "/%s", kn->name); - } -@@ -226,6 +227,7 @@ int kernfs_path_from_node(struct kernfs_node *to, struct kernfs_node *from, - unsigned long flags; - int ret; - -+ guard(rcu)(); - read_lock_irqsave(&kernfs_rename_lock, flags); - ret = kernfs_path_from_node_locked(to, from, buf, buflen); - read_unlock_irqrestore(&kernfs_rename_lock, flags); -@@ -295,7 +297,7 @@ struct kernfs_node *kernfs_get_parent(struct kernfs_node *kn) - unsigned long flags; - - read_lock_irqsave(&kernfs_rename_lock, flags); -- parent = kn->parent; -+ parent = kernfs_parent(kn); - kernfs_get(parent); - read_unlock_irqrestore(&kernfs_rename_lock, flags); - -@@ -360,8 +362,12 @@ static int kernfs_sd_compare(const struct kernfs_node *left, - */ - static int kernfs_link_sibling(struct kernfs_node *kn) - { -- struct rb_node **node = &kn->parent->dir.children.rb_node; - struct rb_node *parent = NULL; -+ struct kernfs_node *kn_parent; -+ struct rb_node **node; -+ -+ kn_parent = kernfs_parent(kn); -+ node = &kn_parent->dir.children.rb_node; - - while (*node) { - struct kernfs_node *pos; -@@ -380,13 +386,13 @@ static int kernfs_link_sibling(struct kernfs_node *kn) - - /* add new node and rebalance the tree */ - rb_link_node(&kn->rb, parent, node); -- rb_insert_color(&kn->rb, &kn->parent->dir.children); -+ rb_insert_color(&kn->rb, &kn_parent->dir.children); - - /* successfully added, account subdir number */ - down_write(&kernfs_root(kn)->kernfs_iattr_rwsem); - if (kernfs_type(kn) == KERNFS_DIR) -- kn->parent->dir.subdirs++; -- kernfs_inc_rev(kn->parent); -+ kn_parent->dir.subdirs++; -+ kernfs_inc_rev(kn_parent); - up_write(&kernfs_root(kn)->kernfs_iattr_rwsem); - - return 0; -@@ -407,16 +413,19 @@ static int kernfs_link_sibling(struct kernfs_node *kn) - */ - static bool kernfs_unlink_sibling(struct kernfs_node *kn) - { -+ struct kernfs_node *kn_parent; -+ - if (RB_EMPTY_NODE(&kn->rb)) - return false; - -+ kn_parent = kernfs_parent(kn); - down_write(&kernfs_root(kn)->kernfs_iattr_rwsem); - if (kernfs_type(kn) == KERNFS_DIR) -- kn->parent->dir.subdirs--; -- kernfs_inc_rev(kn->parent); -+ kn_parent->dir.subdirs--; -+ kernfs_inc_rev(kn_parent); - up_write(&kernfs_root(kn)->kernfs_iattr_rwsem); - -- rb_erase(&kn->rb, &kn->parent->dir.children); -+ rb_erase(&kn->rb, &kn_parent->dir.children); - RB_CLEAR_NODE(&kn->rb); - return true; - } -@@ -562,7 +571,7 @@ void kernfs_put(struct kernfs_node *kn) - * Moving/renaming is always done while holding reference. - * kn->parent won't change beneath us. - */ -- parent = kn->parent; -+ parent = kernfs_parent(kn); - - WARN_ONCE(atomic_read(&kn->active) != KN_DEACTIVATED_BIAS, - "kernfs_put: %s/%s: released with incorrect active_ref %d\n", -@@ -701,7 +710,7 @@ struct kernfs_node *kernfs_new_node(struct kernfs_node *parent, - name, mode, uid, gid, flags); - if (kn) { - kernfs_get(parent); -- kn->parent = parent; -+ rcu_assign_pointer(kn->__parent, parent); - } - return kn; - } -@@ -769,13 +778,14 @@ struct kernfs_node *kernfs_find_and_get_node_by_id(struct kernfs_root *root, - */ - int kernfs_add_one(struct kernfs_node *kn) - { -- struct kernfs_node *parent = kn->parent; -- struct kernfs_root *root = kernfs_root(parent); -+ struct kernfs_root *root = kernfs_root(kn); - struct kernfs_iattrs *ps_iattr; -+ struct kernfs_node *parent; - bool has_ns; - int ret; - - down_write(&root->kernfs_rwsem); -+ parent = kernfs_parent(kn); - - ret = -EINVAL; - has_ns = kernfs_ns_enabled(parent); -@@ -949,6 +959,11 @@ struct kernfs_node *kernfs_walk_and_get_ns(struct kernfs_node *parent, - return kn; - } - -+unsigned int kernfs_root_flags(struct kernfs_node *kn) -+{ -+ return kernfs_root(kn)->flags; -+} -+ - /** - * kernfs_create_root - create a new kernfs hierarchy - * @scops: optional syscall operations for the hierarchy -@@ -1111,7 +1126,7 @@ struct kernfs_node *kernfs_create_empty_dir(struct kernfs_node *parent, - - static int kernfs_dop_revalidate(struct dentry *dentry, unsigned int flags) - { -- struct kernfs_node *kn; -+ struct kernfs_node *kn, *parent; - struct kernfs_root *root; - - if (flags & LOOKUP_RCU) -@@ -1162,8 +1177,9 @@ static int kernfs_dop_revalidate(struct dentry *dentry, unsigned int flags) - if (!kernfs_active(kn)) - goto out_bad; - -+ parent = kernfs_parent(kn); - /* The kernfs node has been moved? */ -- if (kernfs_dentry_node(dentry->d_parent) != kn->parent) -+ if (kernfs_dentry_node(dentry->d_parent) != parent) - goto out_bad; - - /* The kernfs node has been renamed */ -@@ -1171,7 +1187,7 @@ static int kernfs_dop_revalidate(struct dentry *dentry, unsigned int flags) - goto out_bad; - - /* The kernfs node has been moved to a different namespace */ -- if (kn->parent && kernfs_ns_enabled(kn->parent) && -+ if (parent && kernfs_ns_enabled(parent) && - kernfs_info(dentry->d_sb)->ns != kn->ns) - goto out_bad; - -@@ -1364,7 +1380,7 @@ static struct kernfs_node *kernfs_next_descendant_post(struct kernfs_node *pos, - return kernfs_leftmost_descendant(rb_to_kn(rbn)); - - /* no sibling left, visit parent */ -- return pos->parent; -+ return kernfs_parent(pos); - } - - static void kernfs_activate_one(struct kernfs_node *kn) -@@ -1376,7 +1392,7 @@ static void kernfs_activate_one(struct kernfs_node *kn) - if (kernfs_active(kn) || (kn->flags & (KERNFS_HIDDEN | KERNFS_REMOVING))) - return; - -- WARN_ON_ONCE(kn->parent && RB_EMPTY_NODE(&kn->rb)); -+ WARN_ON_ONCE(rcu_access_pointer(kn->__parent) && RB_EMPTY_NODE(&kn->rb)); - WARN_ON_ONCE(atomic_read(&kn->active) != KN_DEACTIVATED_BIAS); - - atomic_sub(KN_DEACTIVATED_BIAS, &kn->active); -@@ -1446,7 +1462,7 @@ void kernfs_show(struct kernfs_node *kn, bool show) - - static void __kernfs_remove(struct kernfs_node *kn) - { -- struct kernfs_node *pos; -+ struct kernfs_node *pos, *parent; - - /* Short-circuit if non-root @kn has already finished removal. */ - if (!kn) -@@ -1458,7 +1474,7 @@ static void __kernfs_remove(struct kernfs_node *kn) - * This is for kernfs_remove_self() which plays with active ref - * after removal. - */ -- if (kn->parent && RB_EMPTY_NODE(&kn->rb)) -+ if (kernfs_parent(kn) && RB_EMPTY_NODE(&kn->rb)) - return; - - pr_debug("kernfs %s: removing\n", kn->name); -@@ -1484,14 +1500,14 @@ static void __kernfs_remove(struct kernfs_node *kn) - kernfs_get(pos); - - kernfs_drain(pos); -- -+ parent = kernfs_parent(pos); - /* - * kernfs_unlink_sibling() succeeds once per node. Use it - * to decide who's responsible for cleanups. - */ -- if (!pos->parent || kernfs_unlink_sibling(pos)) { -+ if (!parent || kernfs_unlink_sibling(pos)) { - struct kernfs_iattrs *ps_iattr = -- pos->parent ? pos->parent->iattr : NULL; -+ parent ? parent->iattr : NULL; - - /* update timestamps on the parent */ - down_write(&kernfs_root(kn)->kernfs_iattr_rwsem); -@@ -1721,7 +1737,7 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent, - int error; - - /* can't move or rename root */ -- if (!kn->parent) -+ if (!rcu_access_pointer(kn->__parent)) - return -EINVAL; - - root = kernfs_root(kn); -@@ -1732,8 +1748,15 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent, - (new_parent->flags & KERNFS_EMPTY_DIR)) - goto out; - -+ old_parent = kernfs_parent(kn); -+ if (root->flags & KERNFS_ROOT_INVARIANT_PARENT) { -+ error = -EINVAL; -+ if (WARN_ON_ONCE(old_parent != new_parent)) -+ goto out; -+ } -+ - error = 0; -- if ((kn->parent == new_parent) && (kn->ns == new_ns) && -+ if ((old_parent == new_parent) && (kn->ns == new_ns) && - (strcmp(kn->name, new_name) == 0)) - goto out; /* nothing to rename */ - -@@ -1760,8 +1783,8 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent, - /* rename_lock protects ->parent and ->name accessors */ - write_lock_irq(&kernfs_rename_lock); - -- old_parent = kn->parent; -- kn->parent = new_parent; -+ old_parent = kernfs_parent(kn); -+ rcu_assign_pointer(kn->__parent, new_parent); - - kn->ns = new_ns; - if (new_name) { -@@ -1794,7 +1817,8 @@ static struct kernfs_node *kernfs_dir_pos(const void *ns, - { - if (pos) { - int valid = kernfs_active(pos) && -- pos->parent == parent && hash == pos->hash; -+ rcu_access_pointer(pos->__parent) == parent && -+ hash == pos->hash; - kernfs_put(pos); - if (!valid) - pos = NULL; -diff --git a/fs/kernfs/kernfs-internal.h b/fs/kernfs/kernfs-internal.h -index b42ee6547cdc1..c43bee18b79f7 100644 ---- a/fs/kernfs/kernfs-internal.h -+++ b/fs/kernfs/kernfs-internal.h -@@ -19,6 +19,8 @@ - #include - #include - -+extern rwlock_t kernfs_rename_lock; -+ - struct kernfs_iattrs { - kuid_t ia_uid; - kgid_t ia_gid; -@@ -64,11 +66,14 @@ struct kernfs_root { - * - * Return: the kernfs_root @kn belongs to. - */ --static inline struct kernfs_root *kernfs_root(struct kernfs_node *kn) -+static inline struct kernfs_root *kernfs_root(const struct kernfs_node *kn) - { -+ const struct kernfs_node *knp; - /* if parent exists, it's always a dir; otherwise, @sd is a dir */ -- if (kn->parent) -- kn = kn->parent; -+ guard(rcu)(); -+ knp = rcu_dereference(kn->__parent); -+ if (knp) -+ kn = knp; - return kn->dir.root; - } - -@@ -97,6 +102,27 @@ struct kernfs_super_info { - }; - #define kernfs_info(SB) ((struct kernfs_super_info *)(SB->s_fs_info)) - -+static inline bool kernfs_root_is_locked(const struct kernfs_node *kn) -+{ -+ return lockdep_is_held(&kernfs_root(kn)->kernfs_rwsem); -+} -+ -+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. -+ * 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) || -+ !atomic_read(&kn->count)); -+} -+ - static inline struct kernfs_node *kernfs_dentry_node(struct dentry *dentry) - { - if (d_really_is_negative(dentry)) -diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c -index 4a0ff08d589ca..2252b16e6ef0b 100644 ---- a/fs/kernfs/mount.c -+++ b/fs/kernfs/mount.c -@@ -148,7 +148,7 @@ static struct dentry *kernfs_get_parent_dentry(struct dentry *child) - struct kernfs_root *root = kernfs_root(kn); - - guard(rwsem_read)(&root->kernfs_rwsem); -- return d_obtain_alias(kernfs_get_inode(child->d_sb, kn->parent)); -+ return d_obtain_alias(kernfs_get_inode(child->d_sb, kernfs_parent(kn))); - } - - static const struct export_operations kernfs_export_ops = { -@@ -188,10 +188,10 @@ static struct kernfs_node *find_next_ancestor(struct kernfs_node *child, - return NULL; - } - -- while (child->parent != parent) { -- if (!child->parent) -+ while (kernfs_parent(child) != parent) { -+ child = kernfs_parent(child); -+ if (!child) - return NULL; -- child = child->parent; - } - - return child; -@@ -216,7 +216,7 @@ struct dentry *kernfs_node_dentry(struct kernfs_node *kn, - dentry = dget(sb->s_root); - - /* Check if this is the root kernfs_node */ -- if (!kn->parent) -+ if (!rcu_access_pointer(kn->__parent)) - return dentry; - - root = kernfs_root(kn); -diff --git a/fs/kernfs/symlink.c b/fs/kernfs/symlink.c -index 45371a70caa71..05c62ca93c53d 100644 ---- a/fs/kernfs/symlink.c -+++ b/fs/kernfs/symlink.c -@@ -62,10 +62,10 @@ static int kernfs_get_target_path(struct kernfs_node *parent, - - /* go up to the root, stop at the base */ - base = parent; -- while (base->parent) { -- kn = target->parent; -- while (kn->parent && base != kn) -- kn = kn->parent; -+ while (kernfs_parent(base)) { -+ kn = kernfs_parent(target); -+ while (kernfs_parent(kn) && base != kn) -+ kn = kernfs_parent(kn); - - if (base == kn) - break; -@@ -75,14 +75,14 @@ static int kernfs_get_target_path(struct kernfs_node *parent, - - strcpy(s, "../"); - s += 3; -- base = base->parent; -+ base = kernfs_parent(base); - } - - /* determine end of target string for reverse fillup */ - kn = target; -- while (kn->parent && kn != base) { -+ while (kernfs_parent(kn) && kn != base) { - len += strlen(kn->name) + 1; -- kn = kn->parent; -+ kn = kernfs_parent(kn); - } - - /* check limits */ -@@ -94,7 +94,7 @@ static int kernfs_get_target_path(struct kernfs_node *parent, - - /* reverse fillup of target string from target to base */ - kn = target; -- while (kn->parent && kn != base) { -+ while (kernfs_parent(kn) && kn != base) { - int slen = strlen(kn->name); - - len -= slen; -@@ -102,7 +102,7 @@ static int kernfs_get_target_path(struct kernfs_node *parent, - if (len) - s[--len] = '/'; - -- kn = kn->parent; -+ kn = kernfs_parent(kn); - } - - return 0; -@@ -111,12 +111,13 @@ static int kernfs_get_target_path(struct kernfs_node *parent, - static int kernfs_getlink(struct inode *inode, char *path) - { - struct kernfs_node *kn = inode->i_private; -- struct kernfs_node *parent = kn->parent; -+ struct kernfs_node *parent; - struct kernfs_node *target = kn->symlink.target_kn; -- struct kernfs_root *root = kernfs_root(parent); -+ struct kernfs_root *root = kernfs_root(kn); - int error; - - down_read(&root->kernfs_rwsem); -+ parent = kernfs_parent(kn); - error = kernfs_get_target_path(parent, target, path); - up_read(&root->kernfs_rwsem); - -diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c -index d1995e2d6c943..3671a3fd60198 100644 ---- a/fs/sysfs/file.c -+++ b/fs/sysfs/file.c -@@ -19,13 +19,19 @@ - - #include "sysfs.h" - -+static struct kobject *sysfs_file_kobj(struct kernfs_node *kn) -+{ -+ guard(rcu)(); -+ return rcu_dereference(kn->__parent)->priv; -+} -+ - /* - * Determine ktype->sysfs_ops for the given kernfs_node. This function - * must be called while holding an active reference. - */ - static const struct sysfs_ops *sysfs_file_ops(struct kernfs_node *kn) - { -- struct kobject *kobj = kn->parent->priv; -+ struct kobject *kobj = sysfs_file_kobj(kn); - - if (kn->flags & KERNFS_LOCKDEP) - lockdep_assert_held(kn); -@@ -40,7 +46,7 @@ static const struct sysfs_ops *sysfs_file_ops(struct kernfs_node *kn) - static int sysfs_kf_seq_show(struct seq_file *sf, void *v) - { - struct kernfs_open_file *of = sf->private; -- struct kobject *kobj = of->kn->parent->priv; -+ struct kobject *kobj = sysfs_file_kobj(of->kn); - const struct sysfs_ops *ops = sysfs_file_ops(of->kn); - ssize_t count; - char *buf; -@@ -78,7 +84,7 @@ static ssize_t sysfs_kf_bin_read(struct kernfs_open_file *of, char *buf, - size_t count, loff_t pos) - { - struct bin_attribute *battr = of->kn->priv; -- struct kobject *kobj = of->kn->parent->priv; -+ struct kobject *kobj = sysfs_file_kobj(of->kn); - loff_t size = file_inode(of->file)->i_size; - - if (!count) -@@ -102,7 +108,7 @@ static ssize_t sysfs_kf_read(struct kernfs_open_file *of, char *buf, - size_t count, loff_t pos) - { - const struct sysfs_ops *ops = sysfs_file_ops(of->kn); -- struct kobject *kobj = of->kn->parent->priv; -+ struct kobject *kobj = sysfs_file_kobj(of->kn); - ssize_t len; - - /* -@@ -128,7 +134,7 @@ static ssize_t sysfs_kf_write(struct kernfs_open_file *of, char *buf, - size_t count, loff_t pos) - { - const struct sysfs_ops *ops = sysfs_file_ops(of->kn); -- struct kobject *kobj = of->kn->parent->priv; -+ struct kobject *kobj = sysfs_file_kobj(of->kn); - - if (!count) - return 0; -@@ -141,7 +147,7 @@ static ssize_t sysfs_kf_bin_write(struct kernfs_open_file *of, char *buf, - size_t count, loff_t pos) - { - struct bin_attribute *battr = of->kn->priv; -- struct kobject *kobj = of->kn->parent->priv; -+ struct kobject *kobj = sysfs_file_kobj(of->kn); - loff_t size = file_inode(of->file)->i_size; - - if (size) { -@@ -162,7 +168,7 @@ static int sysfs_kf_bin_mmap(struct kernfs_open_file *of, - struct vm_area_struct *vma) - { - struct bin_attribute *battr = of->kn->priv; -- struct kobject *kobj = of->kn->parent->priv; -+ struct kobject *kobj = sysfs_file_kobj(of->kn); - - return battr->mmap(of->file, kobj, battr, vma); - } -@@ -171,7 +177,7 @@ static loff_t sysfs_kf_bin_llseek(struct kernfs_open_file *of, loff_t offset, - int whence) - { - struct bin_attribute *battr = of->kn->priv; -- struct kobject *kobj = of->kn->parent->priv; -+ struct kobject *kobj = sysfs_file_kobj(of->kn); - - if (battr->llseek) - return battr->llseek(of->file, kobj, battr, offset, whence); -@@ -482,7 +488,7 @@ EXPORT_SYMBOL_GPL(sysfs_break_active_protection); - */ - void sysfs_unbreak_active_protection(struct kernfs_node *kn) - { -- struct kobject *kobj = kn->parent->priv; -+ struct kobject *kobj = sysfs_file_kobj(kn); - - kernfs_unbreak_active_protection(kn); - kernfs_put(kn); -diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h -index 87c79d076d6d7..5dda9a268e44c 100644 ---- a/include/linux/kernfs.h -+++ b/include/linux/kernfs.h -@@ -147,6 +147,11 @@ enum kernfs_root_flag { - * Support user xattrs to be written to nodes rooted at this root. - */ - KERNFS_ROOT_SUPPORT_USER_XATTR = 0x0008, -+ -+ /* -+ * Renames must not change the parent node. -+ */ -+ KERNFS_ROOT_INVARIANT_PARENT = 0x0010, - }; - - /* type-specific structures for kernfs_node union members */ -@@ -199,8 +204,8 @@ struct kernfs_node { - * never moved to a different parent, it is safe to access the - * parent directly. - */ -- struct kernfs_node *parent; - const char *name; -+ struct kernfs_node __rcu *__parent; - - struct rb_node rb; - -@@ -416,6 +421,7 @@ struct dentry *kernfs_node_dentry(struct kernfs_node *kn, - struct kernfs_root *kernfs_create_root(struct kernfs_syscall_ops *scops, - unsigned int flags, void *priv); - void kernfs_destroy_root(struct kernfs_root *root); -+unsigned int kernfs_root_flags(struct kernfs_node *kn); - - struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent, - const char *name, umode_t mode, -@@ -514,6 +520,8 @@ kernfs_create_root(struct kernfs_syscall_ops *scops, unsigned int flags, - { return ERR_PTR(-ENOSYS); } - - static inline void kernfs_destroy_root(struct kernfs_root *root) { } -+static inline unsigned int kernfs_root_flags(struct kernfs_node *kn) -+{ return 0; } - - static inline struct kernfs_node * - kernfs_create_dir_ns(struct kernfs_node *parent, const char *name, -diff --git a/kernel/cgroup/cgroup-v1.c b/kernel/cgroup/cgroup-v1.c -index e28d5f0d20ed0..c9752eb607ec9 100644 ---- a/kernel/cgroup/cgroup-v1.c -+++ b/kernel/cgroup/cgroup-v1.c -@@ -844,7 +844,7 @@ static int cgroup1_rename(struct kernfs_node *kn, struct kernfs_node *new_parent - - if (kernfs_type(kn) != KERNFS_DIR) - return -ENOTDIR; -- if (kn->parent != new_parent) -+ if (rcu_access_pointer(kn->__parent) != new_parent) - return -EIO; - - /* -diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c -index 62933468aaf46..6f3d942482350 100644 ---- a/kernel/cgroup/cgroup.c -+++ b/kernel/cgroup/cgroup.c -@@ -633,9 +633,22 @@ int cgroup_task_count(const struct cgroup *cgrp) - return count; - } - -+static struct cgroup *kn_priv(struct kernfs_node *kn) -+{ -+ struct kernfs_node *parent; -+ /* -+ * The parent can not be replaced due to KERNFS_ROOT_INVARIANT_PARENT. -+ * Therefore it is always safe to dereference this pointer outside of a -+ * RCU section. -+ */ -+ parent = rcu_dereference_check(kn->__parent, -+ kernfs_root_flags(kn) & KERNFS_ROOT_INVARIANT_PARENT); -+ return parent->priv; -+} -+ - struct cgroup_subsys_state *of_css(struct kernfs_open_file *of) - { -- struct cgroup *cgrp = of->kn->parent->priv; -+ struct cgroup *cgrp = kn_priv(of->kn); - struct cftype *cft = of_cft(of); - - /* -@@ -1612,7 +1625,7 @@ void cgroup_kn_unlock(struct kernfs_node *kn) - if (kernfs_type(kn) == KERNFS_DIR) - cgrp = kn->priv; - else -- cgrp = kn->parent->priv; -+ cgrp = kn_priv(kn); - - cgroup_unlock(); - -@@ -1644,7 +1657,7 @@ struct cgroup *cgroup_kn_lock_live(struct kernfs_node *kn, bool drain_offline) - if (kernfs_type(kn) == KERNFS_DIR) - cgrp = kn->priv; - else -- cgrp = kn->parent->priv; -+ cgrp = kn_priv(kn); - - /* - * We're gonna grab cgroup_mutex which nests outside kernfs -@@ -2118,7 +2131,8 @@ int cgroup_setup_root(struct cgroup_root *root, u16 ss_mask) - root->kf_root = kernfs_create_root(kf_sops, - KERNFS_ROOT_CREATE_DEACTIVATED | - KERNFS_ROOT_SUPPORT_EXPORTOP | -- KERNFS_ROOT_SUPPORT_USER_XATTR, -+ KERNFS_ROOT_SUPPORT_USER_XATTR | -+ KERNFS_ROOT_INVARIANT_PARENT, - root_cgrp); - if (IS_ERR(root->kf_root)) { - ret = PTR_ERR(root->kf_root); -@@ -4144,7 +4158,7 @@ static ssize_t cgroup_file_write(struct kernfs_open_file *of, char *buf, - size_t nbytes, loff_t off) - { - struct cgroup_file_ctx *ctx = of->priv; -- struct cgroup *cgrp = of->kn->parent->priv; -+ struct cgroup *cgrp = kn_priv(of->kn); - struct cftype *cft = of_cft(of); - struct cgroup_subsys_state *css; - int ret; -diff --git a/tools/testing/selftests/bpf/progs/profiler.inc.h b/tools/testing/selftests/bpf/progs/profiler.inc.h -index 8bd1ebd7d6afd..813143b4985dc 100644 ---- a/tools/testing/selftests/bpf/progs/profiler.inc.h -+++ b/tools/testing/selftests/bpf/progs/profiler.inc.h -@@ -223,7 +223,7 @@ static INLINE void* read_full_cgroup_path(struct kernfs_node* cgroup_node, - if (bpf_cmp_likely(filepart_length, <=, MAX_PATH)) { - payload += filepart_length; - } -- cgroup_node = BPF_CORE_READ(cgroup_node, parent); -+ cgroup_node = BPF_CORE_READ(cgroup_node, __parent); - } - return payload; - } --- -2.39.5 - diff --git a/queue-6.12/series b/queue-6.12/series index c198285b35..00e30e6649 100644 --- a/queue-6.12/series +++ b/queue-6.12/series @@ -369,10 +369,6 @@ pinctrl-devicetree-do-not-goto-err-when-probing-hogs.patch smack-recognize-ipv4-cipso-w-o-categories.patch smack-revert-smackfs-added-check-catlen.patch kunit-tool-use-qboot-on-qemu-x86_64.patch -kernfs-don-t-re-lock-kernfs_root-kernfs_rwsem-in-ker.patch -kernfs-acquire-kernfs_rwsem-in-kernfs_node_dentry.patch -kernfs-acquire-kernfs_rwsem-in-kernfs_get_parent_den.patch -kernfs-acquire-kernfs_rwsem-in-kernfs_notify_workfn.patch media-i2c-imx219-correct-the-minimum-vblanking-value.patch media-v4l-memset-argument-to-0-before-calling-get_mb.patch libbpf-fix-ldx-stx-st-co-re-relocation-size-adjustme.patch @@ -512,7 +508,6 @@ drm-atomic-clarify-the-rules-around-drm_atomic_state.patch drm-buddy-fix-issue-that-force_merge-cannot-free-all.patch drm-panel-edp-add-starry-116khd024006.patch drm-add-valid-clones-check.patch -kernfs-use-rcu-to-access-kernfs_node-parent.patch asoc-imx-card-adjust-over-allocation-of-memory-in-im.patch book3s64-radix-fix-compile-errors-when-config_arch_w.patch pinctrl-meson-define-the-pull-up-down-resistor-value.patch diff --git a/queue-6.14/kernfs-acquire-kernfs_rwsem-in-kernfs_get_parent_den.patch b/queue-6.14/kernfs-acquire-kernfs_rwsem-in-kernfs_get_parent_den.patch deleted file mode 100644 index aa0face48b..0000000000 --- a/queue-6.14/kernfs-acquire-kernfs_rwsem-in-kernfs_get_parent_den.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 25a717297c69bf728ca7ef85fdfae89a520d5f2d Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Thu, 13 Feb 2025 15:50:19 +0100 -Subject: kernfs: Acquire kernfs_rwsem in kernfs_get_parent_dentry(). - -From: Sebastian Andrzej Siewior - -[ Upstream commit 122ab92dee80582c39740609a627198dd5b6b595 ] - -kernfs_get_parent_dentry() passes kernfs_node::parent to -kernfs_get_inode(). - -Acquire kernfs_root::kernfs_rwsem to ensure kernfs_node::parent isn't -replaced during the operation. - -Acked-by: Tejun Heo -Signed-off-by: Sebastian Andrzej Siewior -Link: https://lore.kernel.org/r/20250213145023.2820193-3-bigeasy@linutronix.de -Signed-off-by: Greg Kroah-Hartman -Signed-off-by: Sasha Levin ---- - fs/kernfs/mount.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c -index 0f6379ae258d1..4a0ff08d589ca 100644 ---- a/fs/kernfs/mount.c -+++ b/fs/kernfs/mount.c -@@ -145,7 +145,9 @@ static struct dentry *kernfs_fh_to_parent(struct super_block *sb, - static struct dentry *kernfs_get_parent_dentry(struct dentry *child) - { - struct kernfs_node *kn = kernfs_dentry_node(child); -+ struct kernfs_root *root = kernfs_root(kn); - -+ guard(rwsem_read)(&root->kernfs_rwsem); - return d_obtain_alias(kernfs_get_inode(child->d_sb, kn->parent)); - } - --- -2.39.5 - diff --git a/queue-6.14/kernfs-acquire-kernfs_rwsem-in-kernfs_node_dentry.patch b/queue-6.14/kernfs-acquire-kernfs_rwsem-in-kernfs_node_dentry.patch deleted file mode 100644 index 83781407fa..0000000000 --- a/queue-6.14/kernfs-acquire-kernfs_rwsem-in-kernfs_node_dentry.patch +++ /dev/null @@ -1,49 +0,0 @@ -From f6f132bdcac41f2b42619efd69a1112b6a5a2dde Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Thu, 13 Feb 2025 15:50:20 +0100 -Subject: kernfs: Acquire kernfs_rwsem in kernfs_node_dentry(). - -From: Sebastian Andrzej Siewior - -[ Upstream commit 5b2fabf7fe8f745ff214ff003e6067b64f172271 ] - -kernfs_node_dentry() passes kernfs_node::name to -lookup_positive_unlocked(). - -Acquire kernfs_root::kernfs_rwsem to ensure the node is not renamed -during the operation. - -Acked-by: Tejun Heo -Signed-off-by: Sebastian Andrzej Siewior -Link: https://lore.kernel.org/r/20250213145023.2820193-4-bigeasy@linutronix.de -Signed-off-by: Greg Kroah-Hartman -Signed-off-by: Sasha Levin ---- - fs/kernfs/mount.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c -index 1358c21837f1a..0f6379ae258d1 100644 ---- a/fs/kernfs/mount.c -+++ b/fs/kernfs/mount.c -@@ -207,6 +207,7 @@ struct dentry *kernfs_node_dentry(struct kernfs_node *kn, - { - struct dentry *dentry; - struct kernfs_node *knparent; -+ struct kernfs_root *root; - - BUG_ON(sb->s_op != &kernfs_sops); - -@@ -216,6 +217,9 @@ struct dentry *kernfs_node_dentry(struct kernfs_node *kn, - if (!kn->parent) - return dentry; - -+ root = kernfs_root(kn); -+ guard(rwsem_read)(&root->kernfs_rwsem); -+ - knparent = find_next_ancestor(kn, NULL); - if (WARN_ON(!knparent)) { - dput(dentry); --- -2.39.5 - diff --git a/queue-6.14/kernfs-acquire-kernfs_rwsem-in-kernfs_notify_workfn.patch b/queue-6.14/kernfs-acquire-kernfs_rwsem-in-kernfs_notify_workfn.patch deleted file mode 100644 index f1899c860e..0000000000 --- a/queue-6.14/kernfs-acquire-kernfs_rwsem-in-kernfs_notify_workfn.patch +++ /dev/null @@ -1,47 +0,0 @@ -From c004b9f6c4df78b795678226de60856ef13ca3ca Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Thu, 13 Feb 2025 15:50:18 +0100 -Subject: kernfs: Acquire kernfs_rwsem in kernfs_notify_workfn(). - -From: Sebastian Andrzej Siewior - -[ Upstream commit 400188ae361a9d9a72a47a6cedaf2d2efcc84aa8 ] - -kernfs_notify_workfn() dereferences kernfs_node::name and passes it -later to fsnotify(). If the node is renamed then the previously observed -name pointer becomes invalid. - -Acquire kernfs_root::kernfs_rwsem to block renames of the node. - -Acked-by: Tejun Heo -Signed-off-by: Sebastian Andrzej Siewior -Link: https://lore.kernel.org/r/20250213145023.2820193-2-bigeasy@linutronix.de -Signed-off-by: Greg Kroah-Hartman -Signed-off-by: Sasha Levin ---- - fs/kernfs/file.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c -index 0eb320617d7b1..c4ffa8dc89ebc 100644 ---- a/fs/kernfs/file.c -+++ b/fs/kernfs/file.c -@@ -911,6 +911,7 @@ static void kernfs_notify_workfn(struct work_struct *work) - /* kick fsnotify */ - - down_read(&root->kernfs_supers_rwsem); -+ down_read(&root->kernfs_rwsem); - list_for_each_entry(info, &kernfs_root(kn)->supers, node) { - struct kernfs_node *parent; - struct inode *p_inode = NULL; -@@ -947,6 +948,7 @@ static void kernfs_notify_workfn(struct work_struct *work) - iput(inode); - } - -+ up_read(&root->kernfs_rwsem); - up_read(&root->kernfs_supers_rwsem); - kernfs_put(kn); - goto repeat; --- -2.39.5 - diff --git a/queue-6.14/kernfs-don-t-re-lock-kernfs_root-kernfs_rwsem-in-ker.patch b/queue-6.14/kernfs-don-t-re-lock-kernfs_root-kernfs_rwsem-in-ker.patch deleted file mode 100644 index c1cc4d9585..0000000000 --- a/queue-6.14/kernfs-don-t-re-lock-kernfs_root-kernfs_rwsem-in-ker.patch +++ /dev/null @@ -1,56 +0,0 @@ -From d207a5442668cab762f65cae33b30cc749ede28e Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Thu, 13 Feb 2025 15:50:21 +0100 -Subject: kernfs: Don't re-lock kernfs_root::kernfs_rwsem in - kernfs_fop_readdir(). - -From: Sebastian Andrzej Siewior - -[ Upstream commit 9aab10a0249eab4ec77c6a5e4f66442610c12a09 ] - -The readdir operation iterates over all entries and invokes dir_emit() -for every entry passing kernfs_node::name as argument. -Since the name argument can change, and become invalid, the -kernfs_root::kernfs_rwsem lock should not be dropped to prevent renames -during the operation. - -The lock drop around dir_emit() has been initially introduced in commit - 1e5289c97bba2 ("sysfs: Cache the last sysfs_dirent to improve readdir scalability v2") - -to avoid holding a global lock during a page fault. The lock drop is -wrong since the support of renames and not a big burden since the lock -is no longer global. - -Don't re-acquire kernfs_root::kernfs_rwsem while copying the name to the -userpace buffer. - -Acked-by: Tejun Heo -Signed-off-by: Sebastian Andrzej Siewior -Link: https://lore.kernel.org/r/20250213145023.2820193-5-bigeasy@linutronix.de -Signed-off-by: Greg Kroah-Hartman -Signed-off-by: Sasha Levin ---- - fs/kernfs/dir.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c -index 5f0f8b95f44c0..43fbada678381 100644 ---- a/fs/kernfs/dir.c -+++ b/fs/kernfs/dir.c -@@ -1869,10 +1869,10 @@ static int kernfs_fop_readdir(struct file *file, struct dir_context *ctx) - file->private_data = pos; - kernfs_get(pos); - -- up_read(&root->kernfs_rwsem); -- if (!dir_emit(ctx, name, len, ino, type)) -+ if (!dir_emit(ctx, name, len, ino, type)) { -+ up_read(&root->kernfs_rwsem); - return 0; -- down_read(&root->kernfs_rwsem); -+ } - } - up_read(&root->kernfs_rwsem); - file->private_data = NULL; --- -2.39.5 - diff --git a/queue-6.14/kernfs-drop-kernfs_rwsem-while-invoking-lookup_posit.patch b/queue-6.14/kernfs-drop-kernfs_rwsem-while-invoking-lookup_posit.patch deleted file mode 100644 index 1d6567e21b..0000000000 --- a/queue-6.14/kernfs-drop-kernfs_rwsem-while-invoking-lookup_posit.patch +++ /dev/null @@ -1,98 +0,0 @@ -From a19c98bbfce95b52ef574173a1be3cbe45aa0ad0 Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Tue, 18 Feb 2025 17:39:38 +0100 -Subject: kernfs: Drop kernfs_rwsem while invoking lookup_positive_unlocked(). - -From: Sebastian Andrzej Siewior - -[ Upstream commit 6ef5b6fae304091593956be59065c0c8633ad9e8 ] - -syzbot reported two warnings: -- kernfs_node::name was accessed outside of a RCU section so it created - warning. The kernfs_rwsem was held so it was okay but it wasn't seen. - -- While kernfs_rwsem was held invoked lookup_positive_unlocked()-> - kernfs_dop_revalidate() which acquired kernfs_rwsem. - -kernfs_rwsem was both acquired as a read lock so it can be acquired -twice. However if a writer acquires the lock after the first reader then -neither the writer nor the second reader can obtain the lock so it -deadlocks. - -The reason for the lock is to ensure that kernfs_node::name remain -stable during lookup_positive_unlocked()'s invocation. The function can -not be invoked within a RCU section because it may sleep. - -Make a temporary copy of the kernfs_node::name under the lock so -GFP_KERNEL can be used and use this instead. - -Reported-by: syzbot+ecccecbc636b455f9084@syzkaller.appspotmail.com -Fixes: 5b2fabf7fe8f ("kernfs: Acquire kernfs_rwsem in kernfs_node_dentry().") -Signed-off-by: Sebastian Andrzej Siewior -Acked-by: Tejun Heo -Link: https://lore.kernel.org/r/20250218163938.xmvjlJ0K@linutronix.de -Signed-off-by: Greg Kroah-Hartman -Signed-off-by: Sasha Levin ---- - fs/kernfs/mount.c | 33 ++++++++++++++++++++++++--------- - 1 file changed, 24 insertions(+), 9 deletions(-) - -diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c -index d1f512b7bf867..f1cea282aae32 100644 ---- a/fs/kernfs/mount.c -+++ b/fs/kernfs/mount.c -@@ -220,12 +220,19 @@ struct dentry *kernfs_node_dentry(struct kernfs_node *kn, - return dentry; - - root = kernfs_root(kn); -- guard(rwsem_read)(&root->kernfs_rwsem); -- -- knparent = find_next_ancestor(kn, NULL); -- if (WARN_ON(!knparent)) { -- dput(dentry); -+ /* -+ * As long as kn is valid, its parent can not vanish. This is cgroup's -+ * kn so it not have its parent replaced. Therefore it is safe to use -+ * the ancestor node outside of the RCU or locked section. -+ */ -+ if (WARN_ON_ONCE(!(root->flags & KERNFS_ROOT_INVARIANT_PARENT))) - return ERR_PTR(-EINVAL); -+ scoped_guard(rcu) { -+ knparent = find_next_ancestor(kn, NULL); -+ if (WARN_ON(!knparent)) { -+ dput(dentry); -+ return ERR_PTR(-EINVAL); -+ } - } - - do { -@@ -235,14 +242,22 @@ struct dentry *kernfs_node_dentry(struct kernfs_node *kn, - - if (kn == knparent) - return dentry; -- kntmp = find_next_ancestor(kn, knparent); -- if (WARN_ON(!kntmp)) { -+ -+ scoped_guard(rwsem_read, &root->kernfs_rwsem) { -+ kntmp = find_next_ancestor(kn, knparent); -+ if (WARN_ON(!kntmp)) { -+ dput(dentry); -+ return ERR_PTR(-EINVAL); -+ } -+ name = kstrdup(kernfs_rcu_name(kntmp), GFP_KERNEL); -+ } -+ if (!name) { - dput(dentry); -- return ERR_PTR(-EINVAL); -+ return ERR_PTR(-ENOMEM); - } -- name = rcu_dereference(kntmp->name); - dtmp = lookup_positive_unlocked(name, dentry, strlen(name)); - dput(dentry); -+ kfree(name); - if (IS_ERR(dtmp)) - return dtmp; - knparent = kntmp; --- -2.39.5 - diff --git a/queue-6.14/kernfs-use-rcu-to-access-kernfs_node-name.patch b/queue-6.14/kernfs-use-rcu-to-access-kernfs_node-name.patch deleted file mode 100644 index f7110a2aac..0000000000 --- a/queue-6.14/kernfs-use-rcu-to-access-kernfs_node-name.patch +++ /dev/null @@ -1,596 +0,0 @@ -From 8e1b2461023eba183fce8c2b3ef54a3e6b6eb056 Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Thu, 13 Feb 2025 15:50:23 +0100 -Subject: kernfs: Use RCU to access kernfs_node::name. - -From: Sebastian Andrzej Siewior - -[ Upstream commit 741c10b096bc4dd79cd9f215b6ef173bb953e75c ] - -Using RCU lifetime rules to access kernfs_node::name can avoid the -trouble with kernfs_rename_lock in kernfs_name() and kernfs_path_from_node() -if the fs was created with KERNFS_ROOT_INVARIANT_PARENT. This is usefull -as it allows to implement kernfs_path_from_node() only with RCU -protection and avoiding kernfs_rename_lock. The lock is only required if -the __parent node can be changed and the function requires an unchanged -hierarchy while it iterates from the node to its parent. -The change is needed to allow the lookup of the node's path -(kernfs_path_from_node()) from context which runs always with disabled -preemption and or interrutps even on PREEMPT_RT. The problem is that -kernfs_rename_lock becomes a sleeping lock on PREEMPT_RT. - -I went through all ::name users and added the required access for the lookup -with a few extensions: -- rdtgroup_pseudo_lock_create() drops all locks and then uses the name - later on. resctrl supports rename with different parents. Here I made - a temporal copy of the name while it is used outside of the lock. - -- kernfs_rename_ns() accepts NULL as new_parent. This simplifies - sysfs_move_dir_ns() where it can set NULL in order to reuse the current - name. - -- kernfs_rename_ns() is only using kernfs_rename_lock if the parents are - different. All users use either kernfs_rwsem (for stable path view) or - just RCU for the lookup. The ::name uses always RCU free. - -Use RCU lifetime guarantees to access kernfs_node::name. - -Suggested-by: Tejun Heo -Acked-by: Tejun Heo -Reported-by: syzbot+6ea37e2e6ffccf41a7e6@syzkaller.appspotmail.com -Closes: https://lore.kernel.org/lkml/67251dc6.050a0220.529b6.015e.GAE@google.com/ -Reported-by: Hillf Danton -Closes: https://lore.kernel.org/20241102001224.2789-1-hdanton@sina.com -Signed-off-by: Sebastian Andrzej Siewior -Link: https://lore.kernel.org/r/20250213145023.2820193-7-bigeasy@linutronix.de -Signed-off-by: Greg Kroah-Hartman -Stable-dep-of: 6ef5b6fae304 ("kernfs: Drop kernfs_rwsem while invoking lookup_positive_unlocked().") -Signed-off-by: Sasha Levin ---- - arch/x86/kernel/cpu/resctrl/internal.h | 5 + - arch/x86/kernel/cpu/resctrl/pseudo_lock.c | 14 ++- - arch/x86/kernel/cpu/resctrl/rdtgroup.c | 10 +- - fs/kernfs/dir.c | 113 ++++++++++++---------- - fs/kernfs/file.c | 4 +- - fs/kernfs/kernfs-internal.h | 5 + - fs/kernfs/mount.c | 5 +- - fs/kernfs/symlink.c | 7 +- - fs/sysfs/dir.c | 2 +- - include/linux/kernfs.h | 4 +- - security/selinux/hooks.c | 7 +- - 11 files changed, 105 insertions(+), 71 deletions(-) - -diff --git a/arch/x86/kernel/cpu/resctrl/internal.h b/arch/x86/kernel/cpu/resctrl/internal.h -index 20c898f09b7e7..dd5d6b4bfcc22 100644 ---- a/arch/x86/kernel/cpu/resctrl/internal.h -+++ b/arch/x86/kernel/cpu/resctrl/internal.h -@@ -507,6 +507,11 @@ int parse_bw(struct rdt_parse_data *data, struct resctrl_schema *s, - - extern struct mutex rdtgroup_mutex; - -+static inline const char *rdt_kn_name(const struct kernfs_node *kn) -+{ -+ return rcu_dereference_check(kn->name, lockdep_is_held(&rdtgroup_mutex)); -+} -+ - extern struct rdt_hw_resource rdt_resources_all[]; - extern struct rdtgroup rdtgroup_default; - extern struct dentry *debugfs_resctrl; -diff --git a/arch/x86/kernel/cpu/resctrl/pseudo_lock.c b/arch/x86/kernel/cpu/resctrl/pseudo_lock.c -index 42cc162f7fc91..7a2db7fa41083 100644 ---- a/arch/x86/kernel/cpu/resctrl/pseudo_lock.c -+++ b/arch/x86/kernel/cpu/resctrl/pseudo_lock.c -@@ -52,7 +52,8 @@ static char *pseudo_lock_devnode(const struct device *dev, umode_t *mode) - rdtgrp = dev_get_drvdata(dev); - if (mode) - *mode = 0600; -- return kasprintf(GFP_KERNEL, "pseudo_lock/%s", rdtgrp->kn->name); -+ guard(mutex)(&rdtgroup_mutex); -+ return kasprintf(GFP_KERNEL, "pseudo_lock/%s", rdt_kn_name(rdtgrp->kn)); - } - - static const struct class pseudo_lock_class = { -@@ -1293,6 +1294,7 @@ int rdtgroup_pseudo_lock_create(struct rdtgroup *rdtgrp) - struct task_struct *thread; - unsigned int new_minor; - struct device *dev; -+ char *kn_name __free(kfree) = NULL; - int ret; - - ret = pseudo_lock_region_alloc(plr); -@@ -1304,6 +1306,11 @@ int rdtgroup_pseudo_lock_create(struct rdtgroup *rdtgrp) - ret = -EINVAL; - goto out_region; - } -+ kn_name = kstrdup(rdt_kn_name(rdtgrp->kn), GFP_KERNEL); -+ if (!kn_name) { -+ ret = -ENOMEM; -+ goto out_cstates; -+ } - - plr->thread_done = 0; - -@@ -1348,8 +1355,7 @@ int rdtgroup_pseudo_lock_create(struct rdtgroup *rdtgrp) - mutex_unlock(&rdtgroup_mutex); - - if (!IS_ERR_OR_NULL(debugfs_resctrl)) { -- plr->debugfs_dir = debugfs_create_dir(rdtgrp->kn->name, -- debugfs_resctrl); -+ plr->debugfs_dir = debugfs_create_dir(kn_name, debugfs_resctrl); - if (!IS_ERR_OR_NULL(plr->debugfs_dir)) - debugfs_create_file("pseudo_lock_measure", 0200, - plr->debugfs_dir, rdtgrp, -@@ -1358,7 +1364,7 @@ int rdtgroup_pseudo_lock_create(struct rdtgroup *rdtgrp) - - dev = device_create(&pseudo_lock_class, NULL, - MKDEV(pseudo_lock_major, new_minor), -- rdtgrp, "%s", rdtgrp->kn->name); -+ rdtgrp, "%s", kn_name); - - mutex_lock(&rdtgroup_mutex); - -diff --git a/arch/x86/kernel/cpu/resctrl/rdtgroup.c b/arch/x86/kernel/cpu/resctrl/rdtgroup.c -index 3d2a850ea737d..1f769d819a864 100644 ---- a/arch/x86/kernel/cpu/resctrl/rdtgroup.c -+++ b/arch/x86/kernel/cpu/resctrl/rdtgroup.c -@@ -917,14 +917,14 @@ int proc_resctrl_show(struct seq_file *s, struct pid_namespace *ns, - continue; - - seq_printf(s, "res:%s%s\n", (rdtg == &rdtgroup_default) ? "/" : "", -- rdtg->kn->name); -+ rdt_kn_name(rdtg->kn)); - seq_puts(s, "mon:"); - list_for_each_entry(crg, &rdtg->mon.crdtgrp_list, - mon.crdtgrp_list) { - if (!resctrl_arch_match_rmid(tsk, crg->mon.parent->closid, - crg->mon.rmid)) - continue; -- seq_printf(s, "%s", crg->kn->name); -+ seq_printf(s, "%s", rdt_kn_name(crg->kn)); - break; - } - seq_putc(s, '\n'); -@@ -3676,7 +3676,7 @@ static int rdtgroup_mkdir_ctrl_mon(struct kernfs_node *parent_kn, - */ - static bool is_mon_groups(struct kernfs_node *kn, const char *name) - { -- return (!strcmp(kn->name, "mon_groups") && -+ return (!strcmp(rdt_kn_name(kn), "mon_groups") && - strcmp(name, "mon_groups")); - } - -@@ -3825,7 +3825,7 @@ static int rdtgroup_rmdir(struct kernfs_node *kn) - ret = rdtgroup_rmdir_ctrl(rdtgrp, tmpmask); - } - } else if (rdtgrp->type == RDTMON_GROUP && -- is_mon_groups(parent_kn, kn->name)) { -+ is_mon_groups(parent_kn, rdt_kn_name(kn))) { - ret = rdtgroup_rmdir_mon(rdtgrp, tmpmask); - } else { - ret = -EPERM; -@@ -3913,7 +3913,7 @@ static int rdtgroup_rename(struct kernfs_node *kn, - - kn_parent = rdt_kn_parent(kn); - if (rdtgrp->type != RDTMON_GROUP || !kn_parent || -- !is_mon_groups(kn_parent, kn->name)) { -+ !is_mon_groups(kn_parent, rdt_kn_name(kn))) { - rdt_last_cmd_puts("Source must be a MON group\n"); - ret = -EPERM; - goto out; -diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c -index 1d370c497e8a3..c5a578c46759a 100644 ---- a/fs/kernfs/dir.c -+++ b/fs/kernfs/dir.c -@@ -51,14 +51,6 @@ static bool kernfs_lockdep(struct kernfs_node *kn) - #endif - } - --static int kernfs_name_locked(struct kernfs_node *kn, char *buf, size_t buflen) --{ -- if (!kn) -- return strscpy(buf, "(null)", buflen); -- -- return strscpy(buf, rcu_access_pointer(kn->__parent) ? kn->name : "/", buflen); --} -- - /* kernfs_node_depth - compute depth from @from to @to */ - static size_t kernfs_depth(struct kernfs_node *from, struct kernfs_node *to) - { -@@ -168,11 +160,13 @@ static int kernfs_path_from_node_locked(struct kernfs_node *kn_to, - - /* Calculate how many bytes we need for the rest */ - for (i = depth_to - 1; i >= 0; i--) { -+ const char *name; - - for (kn = kn_to, j = 0; j < i; j++) - kn = rcu_dereference(kn->__parent); - -- len += scnprintf(buf + len, buflen - len, "/%s", kn->name); -+ name = rcu_dereference(kn->name); -+ len += scnprintf(buf + len, buflen - len, "/%s", name); - } - - return len; -@@ -196,13 +190,18 @@ static int kernfs_path_from_node_locked(struct kernfs_node *kn_to, - */ - int kernfs_name(struct kernfs_node *kn, char *buf, size_t buflen) - { -- unsigned long flags; -- int ret; -+ struct kernfs_node *kn_parent; - -- read_lock_irqsave(&kernfs_rename_lock, flags); -- ret = kernfs_name_locked(kn, buf, buflen); -- read_unlock_irqrestore(&kernfs_rename_lock, flags); -- return ret; -+ if (!kn) -+ return strscpy(buf, "(null)", buflen); -+ -+ guard(rcu)(); -+ /* -+ * KERNFS_ROOT_INVARIANT_PARENT is ignored here. The name is RCU freed and -+ * the parent is either existing or not. -+ */ -+ kn_parent = rcu_dereference(kn->__parent); -+ return strscpy(buf, kn_parent ? rcu_dereference(kn->name) : "/", buflen); - } - - /** -@@ -224,14 +223,17 @@ int kernfs_name(struct kernfs_node *kn, char *buf, size_t buflen) - int kernfs_path_from_node(struct kernfs_node *to, struct kernfs_node *from, - char *buf, size_t buflen) - { -- unsigned long flags; -- int ret; -+ struct kernfs_root *root; - - guard(rcu)(); -- read_lock_irqsave(&kernfs_rename_lock, flags); -- ret = kernfs_path_from_node_locked(to, from, buf, buflen); -- read_unlock_irqrestore(&kernfs_rename_lock, flags); -- return ret; -+ if (to) { -+ root = kernfs_root(to); -+ if (!(root->flags & KERNFS_ROOT_INVARIANT_PARENT)) { -+ guard(read_lock_irqsave)(&kernfs_rename_lock); -+ return kernfs_path_from_node_locked(to, from, buf, buflen); -+ } -+ } -+ return kernfs_path_from_node_locked(to, from, buf, buflen); - } - EXPORT_SYMBOL_GPL(kernfs_path_from_node); - -@@ -338,13 +340,13 @@ static int kernfs_name_compare(unsigned int hash, const char *name, - return -1; - if (ns > kn->ns) - return 1; -- return strcmp(name, kn->name); -+ return strcmp(name, kernfs_rcu_name(kn)); - } - - static int kernfs_sd_compare(const struct kernfs_node *left, - const struct kernfs_node *right) - { -- return kernfs_name_compare(left->hash, left->name, left->ns, right); -+ return kernfs_name_compare(left->hash, kernfs_rcu_name(left), left->ns, right); - } - - /** -@@ -542,7 +544,8 @@ static void kernfs_free_rcu(struct rcu_head *rcu) - { - struct kernfs_node *kn = container_of(rcu, struct kernfs_node, rcu); - -- kfree_const(kn->name); -+ /* If the whole node goes away, then name can't be used outside */ -+ kfree_const(rcu_access_pointer(kn->name)); - - if (kn->iattr) { - simple_xattrs_free(&kn->iattr->xattrs, NULL); -@@ -575,7 +578,8 @@ void kernfs_put(struct kernfs_node *kn) - - WARN_ONCE(atomic_read(&kn->active) != KN_DEACTIVATED_BIAS, - "kernfs_put: %s/%s: released with incorrect active_ref %d\n", -- parent ? parent->name : "", kn->name, atomic_read(&kn->active)); -+ parent ? rcu_dereference(parent->name) : "", -+ rcu_dereference(kn->name), atomic_read(&kn->active)); - - if (kernfs_type(kn) == KERNFS_LINK) - kernfs_put(kn->symlink.target_kn); -@@ -652,7 +656,7 @@ static struct kernfs_node *__kernfs_new_node(struct kernfs_root *root, - atomic_set(&kn->active, KN_DEACTIVATED_BIAS); - RB_CLEAR_NODE(&kn->rb); - -- kn->name = name; -+ rcu_assign_pointer(kn->name, name); - kn->mode = mode; - kn->flags = flags; - -@@ -790,7 +794,8 @@ int kernfs_add_one(struct kernfs_node *kn) - ret = -EINVAL; - has_ns = kernfs_ns_enabled(parent); - if (WARN(has_ns != (bool)kn->ns, KERN_WARNING "kernfs: ns %s in '%s' for '%s'\n", -- has_ns ? "required" : "invalid", parent->name, kn->name)) -+ has_ns ? "required" : "invalid", -+ kernfs_rcu_name(parent), kernfs_rcu_name(kn))) - goto out_unlock; - - if (kernfs_type(parent) != KERNFS_DIR) -@@ -800,7 +805,7 @@ int kernfs_add_one(struct kernfs_node *kn) - if (parent->flags & (KERNFS_REMOVING | KERNFS_EMPTY_DIR)) - goto out_unlock; - -- kn->hash = kernfs_name_hash(kn->name, kn->ns); -+ kn->hash = kernfs_name_hash(kernfs_rcu_name(kn), kn->ns); - - ret = kernfs_link_sibling(kn); - if (ret) -@@ -856,7 +861,7 @@ static struct kernfs_node *kernfs_find_ns(struct kernfs_node *parent, - - if (has_ns != (bool)ns) { - WARN(1, KERN_WARNING "kernfs: ns %s in '%s' for '%s'\n", -- has_ns ? "required" : "invalid", parent->name, name); -+ has_ns ? "required" : "invalid", kernfs_rcu_name(parent), name); - return NULL; - } - -@@ -1135,8 +1140,6 @@ static int kernfs_dop_revalidate(struct inode *dir, const struct qstr *name, - - /* Negative hashed dentry? */ - if (d_really_is_negative(dentry)) { -- struct kernfs_node *parent; -- - /* If the kernfs parent node has changed discard and - * proceed to ->lookup. - * -@@ -1184,7 +1187,7 @@ static int kernfs_dop_revalidate(struct inode *dir, const struct qstr *name, - goto out_bad; - - /* The kernfs node has been renamed */ -- if (strcmp(dentry->d_name.name, kn->name) != 0) -+ if (strcmp(dentry->d_name.name, kernfs_rcu_name(kn)) != 0) - goto out_bad; - - /* The kernfs node has been moved to a different namespace */ -@@ -1478,7 +1481,7 @@ static void __kernfs_remove(struct kernfs_node *kn) - if (kernfs_parent(kn) && RB_EMPTY_NODE(&kn->rb)) - return; - -- pr_debug("kernfs %s: removing\n", kn->name); -+ pr_debug("kernfs %s: removing\n", kernfs_rcu_name(kn)); - - /* prevent new usage by marking all nodes removing and deactivating */ - pos = NULL; -@@ -1734,7 +1737,7 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent, - { - struct kernfs_node *old_parent; - struct kernfs_root *root; -- const char *old_name = NULL; -+ const char *old_name; - int error; - - /* can't move or rename root */ -@@ -1757,8 +1760,11 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent, - } - - error = 0; -+ old_name = kernfs_rcu_name(kn); -+ if (!new_name) -+ new_name = old_name; - if ((old_parent == new_parent) && (kn->ns == new_ns) && -- (strcmp(kn->name, new_name) == 0)) -+ (strcmp(old_name, new_name) == 0)) - goto out; /* nothing to rename */ - - error = -EEXIST; -@@ -1766,7 +1772,7 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent, - goto out; - - /* rename kernfs_node */ -- if (strcmp(kn->name, new_name) != 0) { -+ if (strcmp(old_name, new_name) != 0) { - error = -ENOMEM; - new_name = kstrdup_const(new_name, GFP_KERNEL); - if (!new_name) -@@ -1779,27 +1785,32 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent, - * Move to the appropriate place in the appropriate directories rbtree. - */ - kernfs_unlink_sibling(kn); -- kernfs_get(new_parent); - -- /* rename_lock protects ->parent and ->name accessors */ -- write_lock_irq(&kernfs_rename_lock); -+ /* rename_lock protects ->parent accessors */ -+ if (old_parent != new_parent) { -+ kernfs_get(new_parent); -+ write_lock_irq(&kernfs_rename_lock); - -- old_parent = kernfs_parent(kn); -- rcu_assign_pointer(kn->__parent, new_parent); -+ rcu_assign_pointer(kn->__parent, new_parent); - -- kn->ns = new_ns; -- if (new_name) { -- old_name = kn->name; -- kn->name = new_name; -- } -+ kn->ns = new_ns; -+ if (new_name) -+ rcu_assign_pointer(kn->name, new_name); - -- write_unlock_irq(&kernfs_rename_lock); -+ write_unlock_irq(&kernfs_rename_lock); -+ kernfs_put(old_parent); -+ } else { -+ /* name assignment is RCU protected, parent is the same */ -+ kn->ns = new_ns; -+ if (new_name) -+ rcu_assign_pointer(kn->name, new_name); -+ } - -- kn->hash = kernfs_name_hash(kn->name, kn->ns); -+ kn->hash = kernfs_name_hash(new_name ?: old_name, kn->ns); - kernfs_link_sibling(kn); - -- kernfs_put(old_parent); -- kfree_const(old_name); -+ if (new_name && !is_kernel_rodata((unsigned long)old_name)) -+ kfree_rcu_mightsleep(old_name); - - error = 0; - out: -@@ -1884,7 +1895,7 @@ static int kernfs_fop_readdir(struct file *file, struct dir_context *ctx) - for (pos = kernfs_dir_pos(ns, parent, ctx->pos, pos); - pos; - pos = kernfs_dir_next_pos(ns, parent, ctx->pos, pos)) { -- const char *name = pos->name; -+ const char *name = kernfs_rcu_name(pos); - unsigned int type = fs_umode_to_dtype(pos->mode); - int len = strlen(name); - ino_t ino = kernfs_ino(pos); -diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c -index c4ffa8dc89ebc..66fe8fe41f060 100644 ---- a/fs/kernfs/file.c -+++ b/fs/kernfs/file.c -@@ -915,6 +915,7 @@ static void kernfs_notify_workfn(struct work_struct *work) - list_for_each_entry(info, &kernfs_root(kn)->supers, node) { - struct kernfs_node *parent; - struct inode *p_inode = NULL; -+ const char *kn_name; - struct inode *inode; - struct qstr name; - -@@ -928,7 +929,8 @@ static void kernfs_notify_workfn(struct work_struct *work) - if (!inode) - continue; - -- name = QSTR(kn->name); -+ kn_name = kernfs_rcu_name(kn); -+ name = QSTR(kn_name); - parent = kernfs_get_parent(kn); - if (parent) { - p_inode = ilookup(info->sb, kernfs_ino(parent)); -diff --git a/fs/kernfs/kernfs-internal.h b/fs/kernfs/kernfs-internal.h -index c43bee18b79f7..40a2a9cd819d0 100644 ---- a/fs/kernfs/kernfs-internal.h -+++ b/fs/kernfs/kernfs-internal.h -@@ -107,6 +107,11 @@ static inline bool kernfs_root_is_locked(const struct kernfs_node *kn) - return lockdep_is_held(&kernfs_root(kn)->kernfs_rwsem); - } - -+static inline const char *kernfs_rcu_name(const struct kernfs_node *kn) -+{ -+ return rcu_dereference_check(kn->name, kernfs_root_is_locked(kn)); -+} -+ - static inline struct kernfs_node *kernfs_parent(const struct kernfs_node *kn) - { - /* -diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c -index 2252b16e6ef0b..d1f512b7bf867 100644 ---- a/fs/kernfs/mount.c -+++ b/fs/kernfs/mount.c -@@ -231,6 +231,7 @@ struct dentry *kernfs_node_dentry(struct kernfs_node *kn, - do { - struct dentry *dtmp; - struct kernfs_node *kntmp; -+ const char *name; - - if (kn == knparent) - return dentry; -@@ -239,8 +240,8 @@ struct dentry *kernfs_node_dentry(struct kernfs_node *kn, - dput(dentry); - return ERR_PTR(-EINVAL); - } -- dtmp = lookup_positive_unlocked(kntmp->name, dentry, -- strlen(kntmp->name)); -+ name = rcu_dereference(kntmp->name); -+ dtmp = lookup_positive_unlocked(name, dentry, strlen(name)); - dput(dentry); - if (IS_ERR(dtmp)) - return dtmp; -diff --git a/fs/kernfs/symlink.c b/fs/kernfs/symlink.c -index 05c62ca93c53d..0bd8a2143723d 100644 ---- a/fs/kernfs/symlink.c -+++ b/fs/kernfs/symlink.c -@@ -81,7 +81,7 @@ static int kernfs_get_target_path(struct kernfs_node *parent, - /* determine end of target string for reverse fillup */ - kn = target; - while (kernfs_parent(kn) && kn != base) { -- len += strlen(kn->name) + 1; -+ len += strlen(kernfs_rcu_name(kn)) + 1; - kn = kernfs_parent(kn); - } - -@@ -95,10 +95,11 @@ static int kernfs_get_target_path(struct kernfs_node *parent, - /* reverse fillup of target string from target to base */ - kn = target; - while (kernfs_parent(kn) && kn != base) { -- int slen = strlen(kn->name); -+ const char *name = kernfs_rcu_name(kn); -+ int slen = strlen(name); - - len -= slen; -- memcpy(s + len, kn->name, slen); -+ memcpy(s + len, name, slen); - if (len) - s[--len] = '/'; - -diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c -index 4df2afa551dc6..94e12efd92f21 100644 ---- a/fs/sysfs/dir.c -+++ b/fs/sysfs/dir.c -@@ -123,7 +123,7 @@ int sysfs_move_dir_ns(struct kobject *kobj, struct kobject *new_parent_kobj, - new_parent = new_parent_kobj && new_parent_kobj->sd ? - new_parent_kobj->sd : sysfs_root_kn; - -- return kernfs_rename_ns(kn, new_parent, kn->name, new_ns); -+ return kernfs_rename_ns(kn, new_parent, NULL, new_ns); - } - - /** -diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h -index 5dda9a268e44c..b5a5f32fdfd1a 100644 ---- a/include/linux/kernfs.h -+++ b/include/linux/kernfs.h -@@ -204,8 +204,8 @@ struct kernfs_node { - * never moved to a different parent, it is safe to access the - * parent directly. - */ -- const char *name; - struct kernfs_node __rcu *__parent; -+ const char __rcu *name; - - struct rb_node rb; - -@@ -400,7 +400,7 @@ static inline bool kernfs_ns_enabled(struct kernfs_node *kn) - } - - int kernfs_name(struct kernfs_node *kn, char *buf, size_t buflen); --int kernfs_path_from_node(struct kernfs_node *root_kn, struct kernfs_node *kn, -+int kernfs_path_from_node(struct kernfs_node *kn_to, struct kernfs_node *kn_from, - char *buf, size_t buflen); - void pr_cont_kernfs_name(struct kernfs_node *kn); - void pr_cont_kernfs_path(struct kernfs_node *kn); -diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c -index 7b867dfec88ba..7dee9616147d2 100644 ---- a/security/selinux/hooks.c -+++ b/security/selinux/hooks.c -@@ -3584,10 +3584,13 @@ static int selinux_kernfs_init_security(struct kernfs_node *kn_dir, - newsid = tsec->create_sid; - } else { - u16 secclass = inode_mode_to_security_class(kn->mode); -+ const char *kn_name; - struct qstr q; - -- q.name = kn->name; -- q.hash_len = hashlen_string(kn_dir, kn->name); -+ /* kn is fresh, can't be renamed, name goes not away */ -+ kn_name = rcu_dereference_check(kn->name, true); -+ q.name = kn_name; -+ q.hash_len = hashlen_string(kn_dir, kn_name); - - rc = security_transition_sid(tsec->sid, - parent_sid, secclass, &q, --- -2.39.5 - diff --git a/queue-6.14/kernfs-use-rcu-to-access-kernfs_node-parent.patch b/queue-6.14/kernfs-use-rcu-to-access-kernfs_node-parent.patch deleted file mode 100644 index 2a6d928b79..0000000000 --- a/queue-6.14/kernfs-use-rcu-to-access-kernfs_node-parent.patch +++ /dev/null @@ -1,989 +0,0 @@ -From d00673680b5c872e774bcf1edfc01462fd88bb55 Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Thu, 13 Feb 2025 15:50:22 +0100 -Subject: kernfs: Use RCU to access kernfs_node::parent. - -From: Sebastian Andrzej Siewior - -[ Upstream commit 633488947ef66b194377411322dc9e12aab79b65 ] - -kernfs_rename_lock is used to obtain stable kernfs_node::{name|parent} -pointer. This is a preparation to access kernfs_node::parent under RCU -and ensure that the pointer remains stable under the RCU lifetime -guarantees. - -For a complete path, as it is done in kernfs_path_from_node(), the -kernfs_rename_lock is still required in order to obtain a stable parent -relationship while computing the relevant node depth. This must not -change while the nodes are inspected in order to build the path. -If the kernfs user never moves the nodes (changes the parent) then the -kernfs_rename_lock is not required and the RCU guarantees are -sufficient. This "restriction" can be set with -KERNFS_ROOT_INVARIANT_PARENT. Otherwise the lock is required. - -Rename kernfs_node::parent to kernfs_node::__parent to denote the RCU -access and use RCU accessor while accessing the node. -Make cgroup use KERNFS_ROOT_INVARIANT_PARENT since the parent here can -not change. - -Acked-by: Tejun Heo -Cc: Yonghong Song -Signed-off-by: Sebastian Andrzej Siewior -Link: https://lore.kernel.org/r/20250213145023.2820193-6-bigeasy@linutronix.de -Signed-off-by: Greg Kroah-Hartman -Stable-dep-of: 6ef5b6fae304 ("kernfs: Drop kernfs_rwsem while invoking lookup_positive_unlocked().") -Signed-off-by: Sasha Levin ---- - arch/x86/kernel/cpu/resctrl/rdtgroup.c | 65 +++++++++---- - fs/kernfs/dir.c | 96 ++++++++++++------- - fs/kernfs/kernfs-internal.h | 32 ++++++- - fs/kernfs/mount.c | 10 +- - fs/kernfs/symlink.c | 23 ++--- - fs/sysfs/file.c | 24 +++-- - include/linux/kernfs.h | 10 +- - kernel/cgroup/cgroup-v1.c | 2 +- - kernel/cgroup/cgroup.c | 24 ++++- - .../selftests/bpf/progs/profiler.inc.h | 2 +- - 10 files changed, 195 insertions(+), 93 deletions(-) - -diff --git a/arch/x86/kernel/cpu/resctrl/rdtgroup.c b/arch/x86/kernel/cpu/resctrl/rdtgroup.c -index 04b653d613e88..3d2a850ea737d 100644 ---- a/arch/x86/kernel/cpu/resctrl/rdtgroup.c -+++ b/arch/x86/kernel/cpu/resctrl/rdtgroup.c -@@ -957,10 +957,20 @@ static int rdt_last_cmd_status_show(struct kernfs_open_file *of, - return 0; - } - -+static void *rdt_kn_parent_priv(struct kernfs_node *kn) -+{ -+ /* -+ * The parent pointer is only valid within RCU section since it can be -+ * replaced. -+ */ -+ guard(rcu)(); -+ return rcu_dereference(kn->__parent)->priv; -+} -+ - static int rdt_num_closids_show(struct kernfs_open_file *of, - struct seq_file *seq, void *v) - { -- struct resctrl_schema *s = of->kn->parent->priv; -+ struct resctrl_schema *s = rdt_kn_parent_priv(of->kn); - - seq_printf(seq, "%u\n", s->num_closid); - return 0; -@@ -969,7 +979,7 @@ static int rdt_num_closids_show(struct kernfs_open_file *of, - static int rdt_default_ctrl_show(struct kernfs_open_file *of, - struct seq_file *seq, void *v) - { -- struct resctrl_schema *s = of->kn->parent->priv; -+ struct resctrl_schema *s = rdt_kn_parent_priv(of->kn); - struct rdt_resource *r = s->res; - - seq_printf(seq, "%x\n", r->default_ctrl); -@@ -979,7 +989,7 @@ static int rdt_default_ctrl_show(struct kernfs_open_file *of, - static int rdt_min_cbm_bits_show(struct kernfs_open_file *of, - struct seq_file *seq, void *v) - { -- struct resctrl_schema *s = of->kn->parent->priv; -+ struct resctrl_schema *s = rdt_kn_parent_priv(of->kn); - struct rdt_resource *r = s->res; - - seq_printf(seq, "%u\n", r->cache.min_cbm_bits); -@@ -989,7 +999,7 @@ static int rdt_min_cbm_bits_show(struct kernfs_open_file *of, - static int rdt_shareable_bits_show(struct kernfs_open_file *of, - struct seq_file *seq, void *v) - { -- struct resctrl_schema *s = of->kn->parent->priv; -+ struct resctrl_schema *s = rdt_kn_parent_priv(of->kn); - struct rdt_resource *r = s->res; - - seq_printf(seq, "%x\n", r->cache.shareable_bits); -@@ -1013,7 +1023,7 @@ static int rdt_shareable_bits_show(struct kernfs_open_file *of, - static int rdt_bit_usage_show(struct kernfs_open_file *of, - struct seq_file *seq, void *v) - { -- struct resctrl_schema *s = of->kn->parent->priv; -+ struct resctrl_schema *s = rdt_kn_parent_priv(of->kn); - /* - * Use unsigned long even though only 32 bits are used to ensure - * test_bit() is used safely. -@@ -1095,7 +1105,7 @@ static int rdt_bit_usage_show(struct kernfs_open_file *of, - static int rdt_min_bw_show(struct kernfs_open_file *of, - struct seq_file *seq, void *v) - { -- struct resctrl_schema *s = of->kn->parent->priv; -+ struct resctrl_schema *s = rdt_kn_parent_priv(of->kn); - struct rdt_resource *r = s->res; - - seq_printf(seq, "%u\n", r->membw.min_bw); -@@ -1105,7 +1115,7 @@ static int rdt_min_bw_show(struct kernfs_open_file *of, - static int rdt_num_rmids_show(struct kernfs_open_file *of, - struct seq_file *seq, void *v) - { -- struct rdt_resource *r = of->kn->parent->priv; -+ struct rdt_resource *r = rdt_kn_parent_priv(of->kn); - - seq_printf(seq, "%d\n", r->num_rmid); - -@@ -1115,7 +1125,7 @@ static int rdt_num_rmids_show(struct kernfs_open_file *of, - static int rdt_mon_features_show(struct kernfs_open_file *of, - struct seq_file *seq, void *v) - { -- struct rdt_resource *r = of->kn->parent->priv; -+ struct rdt_resource *r = rdt_kn_parent_priv(of->kn); - struct mon_evt *mevt; - - list_for_each_entry(mevt, &r->evt_list, list) { -@@ -1130,7 +1140,7 @@ static int rdt_mon_features_show(struct kernfs_open_file *of, - static int rdt_bw_gran_show(struct kernfs_open_file *of, - struct seq_file *seq, void *v) - { -- struct resctrl_schema *s = of->kn->parent->priv; -+ struct resctrl_schema *s = rdt_kn_parent_priv(of->kn); - struct rdt_resource *r = s->res; - - seq_printf(seq, "%u\n", r->membw.bw_gran); -@@ -1140,7 +1150,7 @@ static int rdt_bw_gran_show(struct kernfs_open_file *of, - static int rdt_delay_linear_show(struct kernfs_open_file *of, - struct seq_file *seq, void *v) - { -- struct resctrl_schema *s = of->kn->parent->priv; -+ struct resctrl_schema *s = rdt_kn_parent_priv(of->kn); - struct rdt_resource *r = s->res; - - seq_printf(seq, "%u\n", r->membw.delay_linear); -@@ -1158,7 +1168,7 @@ static int max_threshold_occ_show(struct kernfs_open_file *of, - static int rdt_thread_throttle_mode_show(struct kernfs_open_file *of, - struct seq_file *seq, void *v) - { -- struct resctrl_schema *s = of->kn->parent->priv; -+ struct resctrl_schema *s = rdt_kn_parent_priv(of->kn); - struct rdt_resource *r = s->res; - - if (r->membw.throttle_mode == THREAD_THROTTLE_PER_THREAD) -@@ -1223,7 +1233,7 @@ static enum resctrl_conf_type resctrl_peer_type(enum resctrl_conf_type my_type) - static int rdt_has_sparse_bitmasks_show(struct kernfs_open_file *of, - struct seq_file *seq, void *v) - { -- struct resctrl_schema *s = of->kn->parent->priv; -+ struct resctrl_schema *s = rdt_kn_parent_priv(of->kn); - struct rdt_resource *r = s->res; - - seq_printf(seq, "%u\n", r->cache.arch_has_sparse_bitmasks); -@@ -1635,7 +1645,7 @@ static int mbm_config_show(struct seq_file *s, struct rdt_resource *r, u32 evtid - static int mbm_total_bytes_config_show(struct kernfs_open_file *of, - struct seq_file *seq, void *v) - { -- struct rdt_resource *r = of->kn->parent->priv; -+ struct rdt_resource *r = rdt_kn_parent_priv(of->kn); - - mbm_config_show(seq, r, QOS_L3_MBM_TOTAL_EVENT_ID); - -@@ -1645,7 +1655,7 @@ static int mbm_total_bytes_config_show(struct kernfs_open_file *of, - static int mbm_local_bytes_config_show(struct kernfs_open_file *of, - struct seq_file *seq, void *v) - { -- struct rdt_resource *r = of->kn->parent->priv; -+ struct rdt_resource *r = rdt_kn_parent_priv(of->kn); - - mbm_config_show(seq, r, QOS_L3_MBM_LOCAL_EVENT_ID); - -@@ -1751,7 +1761,7 @@ static ssize_t mbm_total_bytes_config_write(struct kernfs_open_file *of, - char *buf, size_t nbytes, - loff_t off) - { -- struct rdt_resource *r = of->kn->parent->priv; -+ struct rdt_resource *r = rdt_kn_parent_priv(of->kn); - int ret; - - /* Valid input requires a trailing newline */ -@@ -1777,7 +1787,7 @@ static ssize_t mbm_local_bytes_config_write(struct kernfs_open_file *of, - char *buf, size_t nbytes, - loff_t off) - { -- struct rdt_resource *r = of->kn->parent->priv; -+ struct rdt_resource *r = rdt_kn_parent_priv(of->kn); - int ret; - - /* Valid input requires a trailing newline */ -@@ -2441,12 +2451,13 @@ static struct rdtgroup *kernfs_to_rdtgroup(struct kernfs_node *kn) - * resource. "info" and its subdirectories don't - * have rdtgroup structures, so return NULL here. - */ -- if (kn == kn_info || kn->parent == kn_info) -+ if (kn == kn_info || -+ rcu_access_pointer(kn->__parent) == kn_info) - return NULL; - else - return kn->priv; - } else { -- return kn->parent->priv; -+ return rdt_kn_parent_priv(kn); - } - } - -@@ -3772,9 +3783,18 @@ static int rdtgroup_rmdir_ctrl(struct rdtgroup *rdtgrp, cpumask_var_t tmpmask) - return 0; - } - -+static struct kernfs_node *rdt_kn_parent(struct kernfs_node *kn) -+{ -+ /* -+ * Valid within the RCU section it was obtained or while rdtgroup_mutex -+ * is held. -+ */ -+ return rcu_dereference_check(kn->__parent, lockdep_is_held(&rdtgroup_mutex)); -+} -+ - static int rdtgroup_rmdir(struct kernfs_node *kn) - { -- struct kernfs_node *parent_kn = kn->parent; -+ struct kernfs_node *parent_kn; - struct rdtgroup *rdtgrp; - cpumask_var_t tmpmask; - int ret = 0; -@@ -3787,6 +3807,7 @@ static int rdtgroup_rmdir(struct kernfs_node *kn) - ret = -EPERM; - goto out; - } -+ parent_kn = rdt_kn_parent(kn); - - /* - * If the rdtgroup is a ctrl_mon group and parent directory -@@ -3855,6 +3876,7 @@ static void mongrp_reparent(struct rdtgroup *rdtgrp, - static int rdtgroup_rename(struct kernfs_node *kn, - struct kernfs_node *new_parent, const char *new_name) - { -+ struct kernfs_node *kn_parent; - struct rdtgroup *new_prdtgrp; - struct rdtgroup *rdtgrp; - cpumask_var_t tmpmask; -@@ -3889,8 +3911,9 @@ static int rdtgroup_rename(struct kernfs_node *kn, - goto out; - } - -- if (rdtgrp->type != RDTMON_GROUP || !kn->parent || -- !is_mon_groups(kn->parent, kn->name)) { -+ kn_parent = rdt_kn_parent(kn); -+ if (rdtgrp->type != RDTMON_GROUP || !kn_parent || -+ !is_mon_groups(kn_parent, kn->name)) { - rdt_last_cmd_puts("Source must be a MON group\n"); - ret = -EPERM; - goto out; -diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c -index 43fbada678381..1d370c497e8a3 100644 ---- a/fs/kernfs/dir.c -+++ b/fs/kernfs/dir.c -@@ -17,7 +17,7 @@ - - #include "kernfs-internal.h" - --static DEFINE_RWLOCK(kernfs_rename_lock); /* kn->parent and ->name */ -+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() -@@ -56,7 +56,7 @@ static int kernfs_name_locked(struct kernfs_node *kn, char *buf, size_t buflen) - if (!kn) - return strscpy(buf, "(null)", buflen); - -- return strscpy(buf, kn->parent ? kn->name : "/", buflen); -+ return strscpy(buf, rcu_access_pointer(kn->__parent) ? kn->name : "/", buflen); - } - - /* kernfs_node_depth - compute depth from @from to @to */ -@@ -64,9 +64,9 @@ static size_t kernfs_depth(struct kernfs_node *from, struct kernfs_node *to) - { - size_t depth = 0; - -- while (to->parent && to != from) { -+ while (rcu_dereference(to->__parent) && to != from) { - depth++; -- to = to->parent; -+ to = rcu_dereference(to->__parent); - } - return depth; - } -@@ -84,18 +84,18 @@ static struct kernfs_node *kernfs_common_ancestor(struct kernfs_node *a, - db = kernfs_depth(rb->kn, b); - - while (da > db) { -- a = a->parent; -+ a = rcu_dereference(a->__parent); - da--; - } - while (db > da) { -- b = b->parent; -+ b = rcu_dereference(b->__parent); - db--; - } - - /* worst case b and a will be the same at root */ - while (b != a) { -- b = b->parent; -- a = a->parent; -+ b = rcu_dereference(b->__parent); -+ a = rcu_dereference(a->__parent); - } - - return a; -@@ -168,8 +168,9 @@ static int kernfs_path_from_node_locked(struct kernfs_node *kn_to, - - /* Calculate how many bytes we need for the rest */ - for (i = depth_to - 1; i >= 0; i--) { -+ - for (kn = kn_to, j = 0; j < i; j++) -- kn = kn->parent; -+ kn = rcu_dereference(kn->__parent); - - len += scnprintf(buf + len, buflen - len, "/%s", kn->name); - } -@@ -226,6 +227,7 @@ int kernfs_path_from_node(struct kernfs_node *to, struct kernfs_node *from, - unsigned long flags; - int ret; - -+ guard(rcu)(); - read_lock_irqsave(&kernfs_rename_lock, flags); - ret = kernfs_path_from_node_locked(to, from, buf, buflen); - read_unlock_irqrestore(&kernfs_rename_lock, flags); -@@ -295,7 +297,7 @@ struct kernfs_node *kernfs_get_parent(struct kernfs_node *kn) - unsigned long flags; - - read_lock_irqsave(&kernfs_rename_lock, flags); -- parent = kn->parent; -+ parent = kernfs_parent(kn); - kernfs_get(parent); - read_unlock_irqrestore(&kernfs_rename_lock, flags); - -@@ -360,8 +362,12 @@ static int kernfs_sd_compare(const struct kernfs_node *left, - */ - static int kernfs_link_sibling(struct kernfs_node *kn) - { -- struct rb_node **node = &kn->parent->dir.children.rb_node; - struct rb_node *parent = NULL; -+ struct kernfs_node *kn_parent; -+ struct rb_node **node; -+ -+ kn_parent = kernfs_parent(kn); -+ node = &kn_parent->dir.children.rb_node; - - while (*node) { - struct kernfs_node *pos; -@@ -380,13 +386,13 @@ static int kernfs_link_sibling(struct kernfs_node *kn) - - /* add new node and rebalance the tree */ - rb_link_node(&kn->rb, parent, node); -- rb_insert_color(&kn->rb, &kn->parent->dir.children); -+ rb_insert_color(&kn->rb, &kn_parent->dir.children); - - /* successfully added, account subdir number */ - down_write(&kernfs_root(kn)->kernfs_iattr_rwsem); - if (kernfs_type(kn) == KERNFS_DIR) -- kn->parent->dir.subdirs++; -- kernfs_inc_rev(kn->parent); -+ kn_parent->dir.subdirs++; -+ kernfs_inc_rev(kn_parent); - up_write(&kernfs_root(kn)->kernfs_iattr_rwsem); - - return 0; -@@ -407,16 +413,19 @@ static int kernfs_link_sibling(struct kernfs_node *kn) - */ - static bool kernfs_unlink_sibling(struct kernfs_node *kn) - { -+ struct kernfs_node *kn_parent; -+ - if (RB_EMPTY_NODE(&kn->rb)) - return false; - -+ kn_parent = kernfs_parent(kn); - down_write(&kernfs_root(kn)->kernfs_iattr_rwsem); - if (kernfs_type(kn) == KERNFS_DIR) -- kn->parent->dir.subdirs--; -- kernfs_inc_rev(kn->parent); -+ kn_parent->dir.subdirs--; -+ kernfs_inc_rev(kn_parent); - up_write(&kernfs_root(kn)->kernfs_iattr_rwsem); - -- rb_erase(&kn->rb, &kn->parent->dir.children); -+ rb_erase(&kn->rb, &kn_parent->dir.children); - RB_CLEAR_NODE(&kn->rb); - return true; - } -@@ -562,7 +571,7 @@ void kernfs_put(struct kernfs_node *kn) - * Moving/renaming is always done while holding reference. - * kn->parent won't change beneath us. - */ -- parent = kn->parent; -+ parent = kernfs_parent(kn); - - WARN_ONCE(atomic_read(&kn->active) != KN_DEACTIVATED_BIAS, - "kernfs_put: %s/%s: released with incorrect active_ref %d\n", -@@ -701,7 +710,7 @@ struct kernfs_node *kernfs_new_node(struct kernfs_node *parent, - name, mode, uid, gid, flags); - if (kn) { - kernfs_get(parent); -- kn->parent = parent; -+ rcu_assign_pointer(kn->__parent, parent); - } - return kn; - } -@@ -769,13 +778,14 @@ struct kernfs_node *kernfs_find_and_get_node_by_id(struct kernfs_root *root, - */ - int kernfs_add_one(struct kernfs_node *kn) - { -- struct kernfs_node *parent = kn->parent; -- struct kernfs_root *root = kernfs_root(parent); -+ struct kernfs_root *root = kernfs_root(kn); - struct kernfs_iattrs *ps_iattr; -+ struct kernfs_node *parent; - bool has_ns; - int ret; - - down_write(&root->kernfs_rwsem); -+ parent = kernfs_parent(kn); - - ret = -EINVAL; - has_ns = kernfs_ns_enabled(parent); -@@ -949,6 +959,11 @@ struct kernfs_node *kernfs_walk_and_get_ns(struct kernfs_node *parent, - return kn; - } - -+unsigned int kernfs_root_flags(struct kernfs_node *kn) -+{ -+ return kernfs_root(kn)->flags; -+} -+ - /** - * kernfs_create_root - create a new kernfs hierarchy - * @scops: optional syscall operations for the hierarchy -@@ -1112,7 +1127,7 @@ struct kernfs_node *kernfs_create_empty_dir(struct kernfs_node *parent, - static int kernfs_dop_revalidate(struct inode *dir, const struct qstr *name, - struct dentry *dentry, unsigned int flags) - { -- struct kernfs_node *kn; -+ struct kernfs_node *kn, *parent; - struct kernfs_root *root; - - if (flags & LOOKUP_RCU) -@@ -1163,8 +1178,9 @@ static int kernfs_dop_revalidate(struct inode *dir, const struct qstr *name, - if (!kernfs_active(kn)) - goto out_bad; - -+ parent = kernfs_parent(kn); - /* The kernfs node has been moved? */ -- if (kernfs_dentry_node(dentry->d_parent) != kn->parent) -+ if (kernfs_dentry_node(dentry->d_parent) != parent) - goto out_bad; - - /* The kernfs node has been renamed */ -@@ -1172,7 +1188,7 @@ static int kernfs_dop_revalidate(struct inode *dir, const struct qstr *name, - goto out_bad; - - /* The kernfs node has been moved to a different namespace */ -- if (kn->parent && kernfs_ns_enabled(kn->parent) && -+ if (parent && kernfs_ns_enabled(parent) && - kernfs_info(dentry->d_sb)->ns != kn->ns) - goto out_bad; - -@@ -1365,7 +1381,7 @@ static struct kernfs_node *kernfs_next_descendant_post(struct kernfs_node *pos, - return kernfs_leftmost_descendant(rb_to_kn(rbn)); - - /* no sibling left, visit parent */ -- return pos->parent; -+ return kernfs_parent(pos); - } - - static void kernfs_activate_one(struct kernfs_node *kn) -@@ -1377,7 +1393,7 @@ static void kernfs_activate_one(struct kernfs_node *kn) - if (kernfs_active(kn) || (kn->flags & (KERNFS_HIDDEN | KERNFS_REMOVING))) - return; - -- WARN_ON_ONCE(kn->parent && RB_EMPTY_NODE(&kn->rb)); -+ WARN_ON_ONCE(rcu_access_pointer(kn->__parent) && RB_EMPTY_NODE(&kn->rb)); - WARN_ON_ONCE(atomic_read(&kn->active) != KN_DEACTIVATED_BIAS); - - atomic_sub(KN_DEACTIVATED_BIAS, &kn->active); -@@ -1447,7 +1463,7 @@ void kernfs_show(struct kernfs_node *kn, bool show) - - static void __kernfs_remove(struct kernfs_node *kn) - { -- struct kernfs_node *pos; -+ struct kernfs_node *pos, *parent; - - /* Short-circuit if non-root @kn has already finished removal. */ - if (!kn) -@@ -1459,7 +1475,7 @@ static void __kernfs_remove(struct kernfs_node *kn) - * This is for kernfs_remove_self() which plays with active ref - * after removal. - */ -- if (kn->parent && RB_EMPTY_NODE(&kn->rb)) -+ if (kernfs_parent(kn) && RB_EMPTY_NODE(&kn->rb)) - return; - - pr_debug("kernfs %s: removing\n", kn->name); -@@ -1485,14 +1501,14 @@ static void __kernfs_remove(struct kernfs_node *kn) - kernfs_get(pos); - - kernfs_drain(pos); -- -+ parent = kernfs_parent(pos); - /* - * kernfs_unlink_sibling() succeeds once per node. Use it - * to decide who's responsible for cleanups. - */ -- if (!pos->parent || kernfs_unlink_sibling(pos)) { -+ if (!parent || kernfs_unlink_sibling(pos)) { - struct kernfs_iattrs *ps_iattr = -- pos->parent ? pos->parent->iattr : NULL; -+ parent ? parent->iattr : NULL; - - /* update timestamps on the parent */ - down_write(&kernfs_root(kn)->kernfs_iattr_rwsem); -@@ -1722,7 +1738,7 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent, - int error; - - /* can't move or rename root */ -- if (!kn->parent) -+ if (!rcu_access_pointer(kn->__parent)) - return -EINVAL; - - root = kernfs_root(kn); -@@ -1733,8 +1749,15 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent, - (new_parent->flags & KERNFS_EMPTY_DIR)) - goto out; - -+ old_parent = kernfs_parent(kn); -+ if (root->flags & KERNFS_ROOT_INVARIANT_PARENT) { -+ error = -EINVAL; -+ if (WARN_ON_ONCE(old_parent != new_parent)) -+ goto out; -+ } -+ - error = 0; -- if ((kn->parent == new_parent) && (kn->ns == new_ns) && -+ if ((old_parent == new_parent) && (kn->ns == new_ns) && - (strcmp(kn->name, new_name) == 0)) - goto out; /* nothing to rename */ - -@@ -1761,8 +1784,8 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent, - /* rename_lock protects ->parent and ->name accessors */ - write_lock_irq(&kernfs_rename_lock); - -- old_parent = kn->parent; -- kn->parent = new_parent; -+ old_parent = kernfs_parent(kn); -+ rcu_assign_pointer(kn->__parent, new_parent); - - kn->ns = new_ns; - if (new_name) { -@@ -1795,7 +1818,8 @@ static struct kernfs_node *kernfs_dir_pos(const void *ns, - { - if (pos) { - int valid = kernfs_active(pos) && -- pos->parent == parent && hash == pos->hash; -+ rcu_access_pointer(pos->__parent) == parent && -+ hash == pos->hash; - kernfs_put(pos); - if (!valid) - pos = NULL; -diff --git a/fs/kernfs/kernfs-internal.h b/fs/kernfs/kernfs-internal.h -index b42ee6547cdc1..c43bee18b79f7 100644 ---- a/fs/kernfs/kernfs-internal.h -+++ b/fs/kernfs/kernfs-internal.h -@@ -19,6 +19,8 @@ - #include - #include - -+extern rwlock_t kernfs_rename_lock; -+ - struct kernfs_iattrs { - kuid_t ia_uid; - kgid_t ia_gid; -@@ -64,11 +66,14 @@ struct kernfs_root { - * - * Return: the kernfs_root @kn belongs to. - */ --static inline struct kernfs_root *kernfs_root(struct kernfs_node *kn) -+static inline struct kernfs_root *kernfs_root(const struct kernfs_node *kn) - { -+ const struct kernfs_node *knp; - /* if parent exists, it's always a dir; otherwise, @sd is a dir */ -- if (kn->parent) -- kn = kn->parent; -+ guard(rcu)(); -+ knp = rcu_dereference(kn->__parent); -+ if (knp) -+ kn = knp; - return kn->dir.root; - } - -@@ -97,6 +102,27 @@ struct kernfs_super_info { - }; - #define kernfs_info(SB) ((struct kernfs_super_info *)(SB->s_fs_info)) - -+static inline bool kernfs_root_is_locked(const struct kernfs_node *kn) -+{ -+ return lockdep_is_held(&kernfs_root(kn)->kernfs_rwsem); -+} -+ -+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. -+ * 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) || -+ !atomic_read(&kn->count)); -+} -+ - static inline struct kernfs_node *kernfs_dentry_node(struct dentry *dentry) - { - if (d_really_is_negative(dentry)) -diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c -index 4a0ff08d589ca..2252b16e6ef0b 100644 ---- a/fs/kernfs/mount.c -+++ b/fs/kernfs/mount.c -@@ -148,7 +148,7 @@ static struct dentry *kernfs_get_parent_dentry(struct dentry *child) - struct kernfs_root *root = kernfs_root(kn); - - guard(rwsem_read)(&root->kernfs_rwsem); -- return d_obtain_alias(kernfs_get_inode(child->d_sb, kn->parent)); -+ return d_obtain_alias(kernfs_get_inode(child->d_sb, kernfs_parent(kn))); - } - - static const struct export_operations kernfs_export_ops = { -@@ -188,10 +188,10 @@ static struct kernfs_node *find_next_ancestor(struct kernfs_node *child, - return NULL; - } - -- while (child->parent != parent) { -- if (!child->parent) -+ while (kernfs_parent(child) != parent) { -+ child = kernfs_parent(child); -+ if (!child) - return NULL; -- child = child->parent; - } - - return child; -@@ -216,7 +216,7 @@ struct dentry *kernfs_node_dentry(struct kernfs_node *kn, - dentry = dget(sb->s_root); - - /* Check if this is the root kernfs_node */ -- if (!kn->parent) -+ if (!rcu_access_pointer(kn->__parent)) - return dentry; - - root = kernfs_root(kn); -diff --git a/fs/kernfs/symlink.c b/fs/kernfs/symlink.c -index 45371a70caa71..05c62ca93c53d 100644 ---- a/fs/kernfs/symlink.c -+++ b/fs/kernfs/symlink.c -@@ -62,10 +62,10 @@ static int kernfs_get_target_path(struct kernfs_node *parent, - - /* go up to the root, stop at the base */ - base = parent; -- while (base->parent) { -- kn = target->parent; -- while (kn->parent && base != kn) -- kn = kn->parent; -+ while (kernfs_parent(base)) { -+ kn = kernfs_parent(target); -+ while (kernfs_parent(kn) && base != kn) -+ kn = kernfs_parent(kn); - - if (base == kn) - break; -@@ -75,14 +75,14 @@ static int kernfs_get_target_path(struct kernfs_node *parent, - - strcpy(s, "../"); - s += 3; -- base = base->parent; -+ base = kernfs_parent(base); - } - - /* determine end of target string for reverse fillup */ - kn = target; -- while (kn->parent && kn != base) { -+ while (kernfs_parent(kn) && kn != base) { - len += strlen(kn->name) + 1; -- kn = kn->parent; -+ kn = kernfs_parent(kn); - } - - /* check limits */ -@@ -94,7 +94,7 @@ static int kernfs_get_target_path(struct kernfs_node *parent, - - /* reverse fillup of target string from target to base */ - kn = target; -- while (kn->parent && kn != base) { -+ while (kernfs_parent(kn) && kn != base) { - int slen = strlen(kn->name); - - len -= slen; -@@ -102,7 +102,7 @@ static int kernfs_get_target_path(struct kernfs_node *parent, - if (len) - s[--len] = '/'; - -- kn = kn->parent; -+ kn = kernfs_parent(kn); - } - - return 0; -@@ -111,12 +111,13 @@ static int kernfs_get_target_path(struct kernfs_node *parent, - static int kernfs_getlink(struct inode *inode, char *path) - { - struct kernfs_node *kn = inode->i_private; -- struct kernfs_node *parent = kn->parent; -+ struct kernfs_node *parent; - struct kernfs_node *target = kn->symlink.target_kn; -- struct kernfs_root *root = kernfs_root(parent); -+ struct kernfs_root *root = kernfs_root(kn); - int error; - - down_read(&root->kernfs_rwsem); -+ parent = kernfs_parent(kn); - error = kernfs_get_target_path(parent, target, path); - up_read(&root->kernfs_rwsem); - -diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c -index 6931308876c4a..c3d3b079aedde 100644 ---- a/fs/sysfs/file.c -+++ b/fs/sysfs/file.c -@@ -19,13 +19,19 @@ - - #include "sysfs.h" - -+static struct kobject *sysfs_file_kobj(struct kernfs_node *kn) -+{ -+ guard(rcu)(); -+ return rcu_dereference(kn->__parent)->priv; -+} -+ - /* - * Determine ktype->sysfs_ops for the given kernfs_node. This function - * must be called while holding an active reference. - */ - static const struct sysfs_ops *sysfs_file_ops(struct kernfs_node *kn) - { -- struct kobject *kobj = kn->parent->priv; -+ struct kobject *kobj = sysfs_file_kobj(kn); - - if (kn->flags & KERNFS_LOCKDEP) - lockdep_assert_held(kn); -@@ -40,7 +46,7 @@ static const struct sysfs_ops *sysfs_file_ops(struct kernfs_node *kn) - static int sysfs_kf_seq_show(struct seq_file *sf, void *v) - { - struct kernfs_open_file *of = sf->private; -- struct kobject *kobj = of->kn->parent->priv; -+ struct kobject *kobj = sysfs_file_kobj(of->kn); - const struct sysfs_ops *ops = sysfs_file_ops(of->kn); - ssize_t count; - char *buf; -@@ -78,7 +84,7 @@ static ssize_t sysfs_kf_bin_read(struct kernfs_open_file *of, char *buf, - size_t count, loff_t pos) - { - struct bin_attribute *battr = of->kn->priv; -- struct kobject *kobj = of->kn->parent->priv; -+ struct kobject *kobj = sysfs_file_kobj(of->kn); - loff_t size = file_inode(of->file)->i_size; - - if (!count) -@@ -105,7 +111,7 @@ static ssize_t sysfs_kf_read(struct kernfs_open_file *of, char *buf, - size_t count, loff_t pos) - { - const struct sysfs_ops *ops = sysfs_file_ops(of->kn); -- struct kobject *kobj = of->kn->parent->priv; -+ struct kobject *kobj = sysfs_file_kobj(of->kn); - ssize_t len; - - /* -@@ -131,7 +137,7 @@ static ssize_t sysfs_kf_write(struct kernfs_open_file *of, char *buf, - size_t count, loff_t pos) - { - const struct sysfs_ops *ops = sysfs_file_ops(of->kn); -- struct kobject *kobj = of->kn->parent->priv; -+ struct kobject *kobj = sysfs_file_kobj(of->kn); - - if (!count) - return 0; -@@ -144,7 +150,7 @@ static ssize_t sysfs_kf_bin_write(struct kernfs_open_file *of, char *buf, - size_t count, loff_t pos) - { - struct bin_attribute *battr = of->kn->priv; -- struct kobject *kobj = of->kn->parent->priv; -+ struct kobject *kobj = sysfs_file_kobj(of->kn); - loff_t size = file_inode(of->file)->i_size; - - if (size) { -@@ -168,7 +174,7 @@ static int sysfs_kf_bin_mmap(struct kernfs_open_file *of, - struct vm_area_struct *vma) - { - struct bin_attribute *battr = of->kn->priv; -- struct kobject *kobj = of->kn->parent->priv; -+ struct kobject *kobj = sysfs_file_kobj(of->kn); - - return battr->mmap(of->file, kobj, battr, vma); - } -@@ -177,7 +183,7 @@ static loff_t sysfs_kf_bin_llseek(struct kernfs_open_file *of, loff_t offset, - int whence) - { - struct bin_attribute *battr = of->kn->priv; -- struct kobject *kobj = of->kn->parent->priv; -+ struct kobject *kobj = sysfs_file_kobj(of->kn); - - if (battr->llseek) - return battr->llseek(of->file, kobj, battr, offset, whence); -@@ -494,7 +500,7 @@ EXPORT_SYMBOL_GPL(sysfs_break_active_protection); - */ - void sysfs_unbreak_active_protection(struct kernfs_node *kn) - { -- struct kobject *kobj = kn->parent->priv; -+ struct kobject *kobj = sysfs_file_kobj(kn); - - kernfs_unbreak_active_protection(kn); - kernfs_put(kn); -diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h -index 87c79d076d6d7..5dda9a268e44c 100644 ---- a/include/linux/kernfs.h -+++ b/include/linux/kernfs.h -@@ -147,6 +147,11 @@ enum kernfs_root_flag { - * Support user xattrs to be written to nodes rooted at this root. - */ - KERNFS_ROOT_SUPPORT_USER_XATTR = 0x0008, -+ -+ /* -+ * Renames must not change the parent node. -+ */ -+ KERNFS_ROOT_INVARIANT_PARENT = 0x0010, - }; - - /* type-specific structures for kernfs_node union members */ -@@ -199,8 +204,8 @@ struct kernfs_node { - * never moved to a different parent, it is safe to access the - * parent directly. - */ -- struct kernfs_node *parent; - const char *name; -+ struct kernfs_node __rcu *__parent; - - struct rb_node rb; - -@@ -416,6 +421,7 @@ struct dentry *kernfs_node_dentry(struct kernfs_node *kn, - struct kernfs_root *kernfs_create_root(struct kernfs_syscall_ops *scops, - unsigned int flags, void *priv); - void kernfs_destroy_root(struct kernfs_root *root); -+unsigned int kernfs_root_flags(struct kernfs_node *kn); - - struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent, - const char *name, umode_t mode, -@@ -514,6 +520,8 @@ kernfs_create_root(struct kernfs_syscall_ops *scops, unsigned int flags, - { return ERR_PTR(-ENOSYS); } - - static inline void kernfs_destroy_root(struct kernfs_root *root) { } -+static inline unsigned int kernfs_root_flags(struct kernfs_node *kn) -+{ return 0; } - - static inline struct kernfs_node * - kernfs_create_dir_ns(struct kernfs_node *parent, const char *name, -diff --git a/kernel/cgroup/cgroup-v1.c b/kernel/cgroup/cgroup-v1.c -index e28d5f0d20ed0..c9752eb607ec9 100644 ---- a/kernel/cgroup/cgroup-v1.c -+++ b/kernel/cgroup/cgroup-v1.c -@@ -844,7 +844,7 @@ static int cgroup1_rename(struct kernfs_node *kn, struct kernfs_node *new_parent - - if (kernfs_type(kn) != KERNFS_DIR) - return -ENOTDIR; -- if (kn->parent != new_parent) -+ if (rcu_access_pointer(kn->__parent) != new_parent) - return -EIO; - - /* -diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c -index 660d27a0cb3d4..1e2bc9f74fe29 100644 ---- a/kernel/cgroup/cgroup.c -+++ b/kernel/cgroup/cgroup.c -@@ -633,9 +633,22 @@ int cgroup_task_count(const struct cgroup *cgrp) - return count; - } - -+static struct cgroup *kn_priv(struct kernfs_node *kn) -+{ -+ struct kernfs_node *parent; -+ /* -+ * The parent can not be replaced due to KERNFS_ROOT_INVARIANT_PARENT. -+ * Therefore it is always safe to dereference this pointer outside of a -+ * RCU section. -+ */ -+ parent = rcu_dereference_check(kn->__parent, -+ kernfs_root_flags(kn) & KERNFS_ROOT_INVARIANT_PARENT); -+ return parent->priv; -+} -+ - struct cgroup_subsys_state *of_css(struct kernfs_open_file *of) - { -- struct cgroup *cgrp = of->kn->parent->priv; -+ struct cgroup *cgrp = kn_priv(of->kn); - struct cftype *cft = of_cft(of); - - /* -@@ -1612,7 +1625,7 @@ void cgroup_kn_unlock(struct kernfs_node *kn) - if (kernfs_type(kn) == KERNFS_DIR) - cgrp = kn->priv; - else -- cgrp = kn->parent->priv; -+ cgrp = kn_priv(kn); - - cgroup_unlock(); - -@@ -1644,7 +1657,7 @@ struct cgroup *cgroup_kn_lock_live(struct kernfs_node *kn, bool drain_offline) - if (kernfs_type(kn) == KERNFS_DIR) - cgrp = kn->priv; - else -- cgrp = kn->parent->priv; -+ cgrp = kn_priv(kn); - - /* - * We're gonna grab cgroup_mutex which nests outside kernfs -@@ -2118,7 +2131,8 @@ int cgroup_setup_root(struct cgroup_root *root, u16 ss_mask) - root->kf_root = kernfs_create_root(kf_sops, - KERNFS_ROOT_CREATE_DEACTIVATED | - KERNFS_ROOT_SUPPORT_EXPORTOP | -- KERNFS_ROOT_SUPPORT_USER_XATTR, -+ KERNFS_ROOT_SUPPORT_USER_XATTR | -+ KERNFS_ROOT_INVARIANT_PARENT, - root_cgrp); - if (IS_ERR(root->kf_root)) { - ret = PTR_ERR(root->kf_root); -@@ -4144,7 +4158,7 @@ static ssize_t cgroup_file_write(struct kernfs_open_file *of, char *buf, - size_t nbytes, loff_t off) - { - struct cgroup_file_ctx *ctx = of->priv; -- struct cgroup *cgrp = of->kn->parent->priv; -+ struct cgroup *cgrp = kn_priv(of->kn); - struct cftype *cft = of_cft(of); - struct cgroup_subsys_state *css; - int ret; -diff --git a/tools/testing/selftests/bpf/progs/profiler.inc.h b/tools/testing/selftests/bpf/progs/profiler.inc.h -index 8bd1ebd7d6afd..813143b4985dc 100644 ---- a/tools/testing/selftests/bpf/progs/profiler.inc.h -+++ b/tools/testing/selftests/bpf/progs/profiler.inc.h -@@ -223,7 +223,7 @@ static INLINE void* read_full_cgroup_path(struct kernfs_node* cgroup_node, - if (bpf_cmp_likely(filepart_length, <=, MAX_PATH)) { - payload += filepart_length; - } -- cgroup_node = BPF_CORE_READ(cgroup_node, parent); -+ cgroup_node = BPF_CORE_READ(cgroup_node, __parent); - } - return payload; - } --- -2.39.5 - diff --git a/queue-6.14/series b/queue-6.14/series index 963a7cb612..5a0ca27af8 100644 --- a/queue-6.14/series +++ b/queue-6.14/series @@ -451,10 +451,6 @@ smack-recognize-ipv4-cipso-w-o-categories.patch drm-xe-pf-release-all-vfs-configs-on-device-removal.patch smack-revert-smackfs-added-check-catlen.patch kunit-tool-use-qboot-on-qemu-x86_64.patch -kernfs-don-t-re-lock-kernfs_root-kernfs_rwsem-in-ker.patch -kernfs-acquire-kernfs_rwsem-in-kernfs_node_dentry.patch -kernfs-acquire-kernfs_rwsem-in-kernfs_get_parent_den.patch -kernfs-acquire-kernfs_rwsem-in-kernfs_notify_workfn.patch media-i2c-imx219-correct-the-minimum-vblanking-value.patch media-v4l-memset-argument-to-0-before-calling-get_mb.patch media-stm32-csi-use-array_size-to-search-d-phy-table.patch @@ -647,9 +643,6 @@ virtgpu-don-t-reset-on-shutdown.patch x86-mm-init-handle-the-special-case-of-device-privat.patch bpf-abort-verification-if-env-cur_state-loop_entry-n.patch ipv6-remove-leftover-ip6-cookie-initializer.patch -kernfs-use-rcu-to-access-kernfs_node-parent.patch -kernfs-use-rcu-to-access-kernfs_node-name.patch -kernfs-drop-kernfs_rwsem-while-invoking-lookup_posit.patch serial-sh-sci-save-and-restore-more-registers.patch drm-amd-display-exit-idle-optimizations-before-acces.patch drm-amdkfd-fix-error-handling-for-missing-pasid-in-k.patch diff --git a/queue-6.6/kernfs-acquire-kernfs_rwsem-in-kernfs_get_parent_den.patch b/queue-6.6/kernfs-acquire-kernfs_rwsem-in-kernfs_get_parent_den.patch deleted file mode 100644 index 62427b905f..0000000000 --- a/queue-6.6/kernfs-acquire-kernfs_rwsem-in-kernfs_get_parent_den.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 9362b3f10e85a21ca5746eb6728a4b04cd9f7bcc Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Thu, 13 Feb 2025 15:50:19 +0100 -Subject: kernfs: Acquire kernfs_rwsem in kernfs_get_parent_dentry(). - -From: Sebastian Andrzej Siewior - -[ Upstream commit 122ab92dee80582c39740609a627198dd5b6b595 ] - -kernfs_get_parent_dentry() passes kernfs_node::parent to -kernfs_get_inode(). - -Acquire kernfs_root::kernfs_rwsem to ensure kernfs_node::parent isn't -replaced during the operation. - -Acked-by: Tejun Heo -Signed-off-by: Sebastian Andrzej Siewior -Link: https://lore.kernel.org/r/20250213145023.2820193-3-bigeasy@linutronix.de -Signed-off-by: Greg Kroah-Hartman -Signed-off-by: Sasha Levin ---- - fs/kernfs/mount.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c -index c4bf26142eec9..5fda25dbbd256 100644 ---- a/fs/kernfs/mount.c -+++ b/fs/kernfs/mount.c -@@ -147,7 +147,9 @@ static struct dentry *kernfs_fh_to_parent(struct super_block *sb, - static struct dentry *kernfs_get_parent_dentry(struct dentry *child) - { - struct kernfs_node *kn = kernfs_dentry_node(child); -+ struct kernfs_root *root = kernfs_root(kn); - -+ guard(rwsem_read)(&root->kernfs_rwsem); - return d_obtain_alias(kernfs_get_inode(child->d_sb, kn->parent)); - } - --- -2.39.5 - diff --git a/queue-6.6/kernfs-acquire-kernfs_rwsem-in-kernfs_notify_workfn.patch b/queue-6.6/kernfs-acquire-kernfs_rwsem-in-kernfs_notify_workfn.patch deleted file mode 100644 index 5c0d8e3ead..0000000000 --- a/queue-6.6/kernfs-acquire-kernfs_rwsem-in-kernfs_notify_workfn.patch +++ /dev/null @@ -1,47 +0,0 @@ -From bfa4512bf9c7000a225e25d0267d41d27ca321bb Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Thu, 13 Feb 2025 15:50:18 +0100 -Subject: kernfs: Acquire kernfs_rwsem in kernfs_notify_workfn(). - -From: Sebastian Andrzej Siewior - -[ Upstream commit 400188ae361a9d9a72a47a6cedaf2d2efcc84aa8 ] - -kernfs_notify_workfn() dereferences kernfs_node::name and passes it -later to fsnotify(). If the node is renamed then the previously observed -name pointer becomes invalid. - -Acquire kernfs_root::kernfs_rwsem to block renames of the node. - -Acked-by: Tejun Heo -Signed-off-by: Sebastian Andrzej Siewior -Link: https://lore.kernel.org/r/20250213145023.2820193-2-bigeasy@linutronix.de -Signed-off-by: Greg Kroah-Hartman -Signed-off-by: Sasha Levin ---- - fs/kernfs/file.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c -index 332d08d2fe0d5..501502cd5194e 100644 ---- a/fs/kernfs/file.c -+++ b/fs/kernfs/file.c -@@ -926,6 +926,7 @@ static void kernfs_notify_workfn(struct work_struct *work) - /* kick fsnotify */ - - down_read(&root->kernfs_supers_rwsem); -+ down_read(&root->kernfs_rwsem); - list_for_each_entry(info, &kernfs_root(kn)->supers, node) { - struct kernfs_node *parent; - struct inode *p_inode = NULL; -@@ -962,6 +963,7 @@ static void kernfs_notify_workfn(struct work_struct *work) - iput(inode); - } - -+ up_read(&root->kernfs_rwsem); - up_read(&root->kernfs_supers_rwsem); - kernfs_put(kn); - goto repeat; --- -2.39.5 - diff --git a/queue-6.6/kernfs-don-t-re-lock-kernfs_root-kernfs_rwsem-in-ker.patch b/queue-6.6/kernfs-don-t-re-lock-kernfs_root-kernfs_rwsem-in-ker.patch deleted file mode 100644 index fa02cfafba..0000000000 --- a/queue-6.6/kernfs-don-t-re-lock-kernfs_root-kernfs_rwsem-in-ker.patch +++ /dev/null @@ -1,56 +0,0 @@ -From e4b9fe871c485a3fd77452bc61d1adf5ce7f5167 Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Thu, 13 Feb 2025 15:50:21 +0100 -Subject: kernfs: Don't re-lock kernfs_root::kernfs_rwsem in - kernfs_fop_readdir(). - -From: Sebastian Andrzej Siewior - -[ Upstream commit 9aab10a0249eab4ec77c6a5e4f66442610c12a09 ] - -The readdir operation iterates over all entries and invokes dir_emit() -for every entry passing kernfs_node::name as argument. -Since the name argument can change, and become invalid, the -kernfs_root::kernfs_rwsem lock should not be dropped to prevent renames -during the operation. - -The lock drop around dir_emit() has been initially introduced in commit - 1e5289c97bba2 ("sysfs: Cache the last sysfs_dirent to improve readdir scalability v2") - -to avoid holding a global lock during a page fault. The lock drop is -wrong since the support of renames and not a big burden since the lock -is no longer global. - -Don't re-acquire kernfs_root::kernfs_rwsem while copying the name to the -userpace buffer. - -Acked-by: Tejun Heo -Signed-off-by: Sebastian Andrzej Siewior -Link: https://lore.kernel.org/r/20250213145023.2820193-5-bigeasy@linutronix.de -Signed-off-by: Greg Kroah-Hartman -Signed-off-by: Sasha Levin ---- - fs/kernfs/dir.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c -index b068ed32d7b32..60ea525dd205f 100644 ---- a/fs/kernfs/dir.c -+++ b/fs/kernfs/dir.c -@@ -1868,10 +1868,10 @@ static int kernfs_fop_readdir(struct file *file, struct dir_context *ctx) - file->private_data = pos; - kernfs_get(pos); - -- up_read(&root->kernfs_rwsem); -- if (!dir_emit(ctx, name, len, ino, type)) -+ if (!dir_emit(ctx, name, len, ino, type)) { -+ up_read(&root->kernfs_rwsem); - return 0; -- down_read(&root->kernfs_rwsem); -+ } - } - up_read(&root->kernfs_rwsem); - file->private_data = NULL; --- -2.39.5 - diff --git a/queue-6.6/series b/queue-6.6/series index 73e67eeb58..65a1ddc7ed 100644 --- a/queue-6.6/series +++ b/queue-6.6/series @@ -232,9 +232,6 @@ pinctrl-devicetree-do-not-goto-err-when-probing-hogs.patch smack-recognize-ipv4-cipso-w-o-categories.patch smack-revert-smackfs-added-check-catlen.patch kunit-tool-use-qboot-on-qemu-x86_64.patch -kernfs-don-t-re-lock-kernfs_root-kernfs_rwsem-in-ker.patch -kernfs-acquire-kernfs_rwsem-in-kernfs_get_parent_den.patch -kernfs-acquire-kernfs_rwsem-in-kernfs_notify_workfn.patch media-i2c-imx219-correct-the-minimum-vblanking-value.patch media-v4l-memset-argument-to-0-before-calling-get_mb.patch libbpf-fix-ldx-stx-st-co-re-relocation-size-adjustme.patch -- 2.47.3