+++ /dev/null
-From e0f075353e977224e46dece88be33f30b3e4740b Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Thu, 13 Feb 2025 15:50:19 +0100
-Subject: kernfs: Acquire kernfs_rwsem in kernfs_get_parent_dentry().
-
-From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
-
-[ 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 <tj@kernel.org>
-Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
-Link: https://lore.kernel.org/r/20250213145023.2820193-3-bigeasy@linutronix.de
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- 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
-
+++ /dev/null
-From 2af692751023f0622caf0b54fae36902c66bb9e4 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-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 <bigeasy@linutronix.de>
-
-[ 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 <tj@kernel.org>
-Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
-Link: https://lore.kernel.org/r/20250213145023.2820193-5-bigeasy@linutronix.de
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- 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
-
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
+++ /dev/null
-From 47f4808a74c1abb8ff4a358d4a3fa28e5aec9039 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Thu, 13 Feb 2025 15:50:19 +0100
-Subject: kernfs: Acquire kernfs_rwsem in kernfs_get_parent_dentry().
-
-From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
-
-[ 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 <tj@kernel.org>
-Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
-Link: https://lore.kernel.org/r/20250213145023.2820193-3-bigeasy@linutronix.de
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- 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
-
+++ /dev/null
-From 9bb7d9f7370173a25f5494ebd70085a8a54e33bb Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Thu, 13 Feb 2025 15:50:20 +0100
-Subject: kernfs: Acquire kernfs_rwsem in kernfs_node_dentry().
-
-From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
-
-[ 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 <tj@kernel.org>
-Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
-Link: https://lore.kernel.org/r/20250213145023.2820193-4-bigeasy@linutronix.de
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- 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
-
+++ /dev/null
-From 079fbf2ff1f0e3107a47874c3cb8ee013bf89409 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Thu, 13 Feb 2025 15:50:18 +0100
-Subject: kernfs: Acquire kernfs_rwsem in kernfs_notify_workfn().
-
-From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
-
-[ 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 <tj@kernel.org>
-Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
-Link: https://lore.kernel.org/r/20250213145023.2820193-2-bigeasy@linutronix.de
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- 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
-
+++ /dev/null
-From 6247ef751c277b43adbe8b0e75696f1e59cf2921 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-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 <bigeasy@linutronix.de>
-
-[ 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 <tj@kernel.org>
-Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
-Link: https://lore.kernel.org/r/20250213145023.2820193-5-bigeasy@linutronix.de
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- 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
-
+++ /dev/null
-From 10d6731fc902f64ab2457c34c7d2cd1503e9cc34 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Thu, 13 Feb 2025 15:50:22 +0100
-Subject: kernfs: Use RCU to access kernfs_node::parent.
-
-From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
-
-[ 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 <tj@kernel.org>
-Cc: Yonghong Song <yonghong.song@linux.dev>
-Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
-Link: https://lore.kernel.org/r/20250213145023.2820193-6-bigeasy@linutronix.de
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- 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 <linux/kernfs.h>
- #include <linux/fs_context.h>
-
-+extern rwlock_t kernfs_rename_lock;
-+
- struct kernfs_iattrs {
- kuid_t ia_uid;
- kgid_t ia_gid;
-@@ -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
-
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
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
+++ /dev/null
-From 25a717297c69bf728ca7ef85fdfae89a520d5f2d Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Thu, 13 Feb 2025 15:50:19 +0100
-Subject: kernfs: Acquire kernfs_rwsem in kernfs_get_parent_dentry().
-
-From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
-
-[ 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 <tj@kernel.org>
-Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
-Link: https://lore.kernel.org/r/20250213145023.2820193-3-bigeasy@linutronix.de
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- 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
-
+++ /dev/null
-From f6f132bdcac41f2b42619efd69a1112b6a5a2dde Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Thu, 13 Feb 2025 15:50:20 +0100
-Subject: kernfs: Acquire kernfs_rwsem in kernfs_node_dentry().
-
-From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
-
-[ 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 <tj@kernel.org>
-Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
-Link: https://lore.kernel.org/r/20250213145023.2820193-4-bigeasy@linutronix.de
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- 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
-
+++ /dev/null
-From c004b9f6c4df78b795678226de60856ef13ca3ca Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Thu, 13 Feb 2025 15:50:18 +0100
-Subject: kernfs: Acquire kernfs_rwsem in kernfs_notify_workfn().
-
-From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
-
-[ 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 <tj@kernel.org>
-Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
-Link: https://lore.kernel.org/r/20250213145023.2820193-2-bigeasy@linutronix.de
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- 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
-
+++ /dev/null
-From d207a5442668cab762f65cae33b30cc749ede28e Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-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 <bigeasy@linutronix.de>
-
-[ 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 <tj@kernel.org>
-Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
-Link: https://lore.kernel.org/r/20250213145023.2820193-5-bigeasy@linutronix.de
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- 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
-
+++ /dev/null
-From a19c98bbfce95b52ef574173a1be3cbe45aa0ad0 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Tue, 18 Feb 2025 17:39:38 +0100
-Subject: kernfs: Drop kernfs_rwsem while invoking lookup_positive_unlocked().
-
-From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
-
-[ 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 <bigeasy@linutronix.de>
-Acked-by: Tejun Heo <tj@kernel.org>
-Link: https://lore.kernel.org/r/20250218163938.xmvjlJ0K@linutronix.de
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- 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
-
+++ /dev/null
-From 8e1b2461023eba183fce8c2b3ef54a3e6b6eb056 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Thu, 13 Feb 2025 15:50:23 +0100
-Subject: kernfs: Use RCU to access kernfs_node::name.
-
-From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
-
-[ 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 <tj@kernel.org>
-Acked-by: Tejun Heo <tj@kernel.org>
-Reported-by: syzbot+6ea37e2e6ffccf41a7e6@syzkaller.appspotmail.com
-Closes: https://lore.kernel.org/lkml/67251dc6.050a0220.529b6.015e.GAE@google.com/
-Reported-by: Hillf Danton <hdanton@sina.com>
-Closes: https://lore.kernel.org/20241102001224.2789-1-hdanton@sina.com
-Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
-Link: https://lore.kernel.org/r/20250213145023.2820193-7-bigeasy@linutronix.de
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-Stable-dep-of: 6ef5b6fae304 ("kernfs: Drop kernfs_rwsem while invoking lookup_positive_unlocked().")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- 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
-
+++ /dev/null
-From d00673680b5c872e774bcf1edfc01462fd88bb55 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Thu, 13 Feb 2025 15:50:22 +0100
-Subject: kernfs: Use RCU to access kernfs_node::parent.
-
-From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
-
-[ 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 <tj@kernel.org>
-Cc: Yonghong Song <yonghong.song@linux.dev>
-Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
-Link: https://lore.kernel.org/r/20250213145023.2820193-6-bigeasy@linutronix.de
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-Stable-dep-of: 6ef5b6fae304 ("kernfs: Drop kernfs_rwsem while invoking lookup_positive_unlocked().")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- 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 <linux/kernfs.h>
- #include <linux/fs_context.h>
-
-+extern rwlock_t kernfs_rename_lock;
-+
- struct kernfs_iattrs {
- kuid_t ia_uid;
- kgid_t ia_gid;
-@@ -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
-
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
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
+++ /dev/null
-From 9362b3f10e85a21ca5746eb6728a4b04cd9f7bcc Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Thu, 13 Feb 2025 15:50:19 +0100
-Subject: kernfs: Acquire kernfs_rwsem in kernfs_get_parent_dentry().
-
-From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
-
-[ 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 <tj@kernel.org>
-Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
-Link: https://lore.kernel.org/r/20250213145023.2820193-3-bigeasy@linutronix.de
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- 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
-
+++ /dev/null
-From bfa4512bf9c7000a225e25d0267d41d27ca321bb Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Thu, 13 Feb 2025 15:50:18 +0100
-Subject: kernfs: Acquire kernfs_rwsem in kernfs_notify_workfn().
-
-From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
-
-[ 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 <tj@kernel.org>
-Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
-Link: https://lore.kernel.org/r/20250213145023.2820193-2-bigeasy@linutronix.de
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- 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
-
+++ /dev/null
-From e4b9fe871c485a3fd77452bc61d1adf5ce7f5167 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-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 <bigeasy@linutronix.de>
-
-[ 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 <tj@kernel.org>
-Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
-Link: https://lore.kernel.org/r/20250213145023.2820193-5-bigeasy@linutronix.de
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- 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
-
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