[PATCH v2 2/2] cgroup, kernfs: Move cgroup to the RCU interface for name lookups

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



cgroup only renames nodes and keeps the same parent node. It can be
switched RCU for name lookups to avoid acquiring a lock.
For the switch the flag KERNFS_ROOT_SAME_PARENT is added while creating
the root node and lookups are switched to the _rcu() interface.

The pr_cont_kernfs_.*() is only used by cgroup and is renamed as part of
the switch.
kernfs_path() has one user in tree, sysfs.
kernfs_name() has no callers, could be removed.
kernfs_path_from_node() has no in-tree module callers, module export is
removed.

Fixes: 2b5067a8143e3 ("mm: mmap_lock: add tracepoints around lock acquisition")
Reported-by: syzbot+6ea37e2e6ffccf41a7e6@xxxxxxxxxxxxxxxxxxxxxxxxx
Closes: https://lore.kernel.org/lkml/67251dc6.050a0220.529b6.015e.GAE@xxxxxxxxxx/
Reported-by: Hillf Danton <hdanton@xxxxxxxx>
Closes: https://lore.kernel.org/20241102001224.2789-1-hdanton@xxxxxxxx
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@xxxxxxxxxxxxx>
---
 fs/kernfs/dir.c        | 21 +++++++++++----------
 include/linux/cgroup.h |  8 ++++----
 include/linux/kernfs.h | 26 ++++++++++++++++++++++----
 kernel/cgroup/cgroup.c |  9 +++++----
 4 files changed, 42 insertions(+), 22 deletions(-)

diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index 41c87ee76aa70..93bdaad8b9886 100644
--- a/fs/kernfs/dir.c
+++ b/fs/kernfs/dir.c
@@ -264,7 +264,6 @@ int kernfs_path_from_node(struct kernfs_node *to, struct kernfs_node *from,
 	}
 	return kernfs_path_from_node_locked(to, from, buf, buflen);
 }
-EXPORT_SYMBOL_GPL(kernfs_path_from_node);
 
 /**
  * kernfs_path_from_node_rcu - build path of node @to relative to @from.
@@ -291,38 +290,40 @@ int kernfs_path_from_node_rcu(struct kernfs_node *to, struct kernfs_node *from,
 }
 
 /**
- * pr_cont_kernfs_name - pr_cont name of a kernfs_node
+ * pr_cont_kernfs_name_rcu - pr_cont name of a kernfs_node
  * @kn: kernfs_node of interest
  *
- * This function can be called from any context.
+ * This function can be called from any context. The root node must be with
+ * KERNFS_ROOT_SAME_PARENT.
  */
-void pr_cont_kernfs_name(struct kernfs_node *kn)
+void pr_cont_kernfs_name_rcu(struct kernfs_node *kn)
 {
 	unsigned long flags;
 
 	spin_lock_irqsave(&kernfs_pr_cont_lock, flags);
 
-	kernfs_name(kn, kernfs_pr_cont_buf, sizeof(kernfs_pr_cont_buf));
+	kernfs_name_rcu(kn, kernfs_pr_cont_buf, sizeof(kernfs_pr_cont_buf));
 	pr_cont("%s", kernfs_pr_cont_buf);
 
 	spin_unlock_irqrestore(&kernfs_pr_cont_lock, flags);
 }
 
 /**
- * pr_cont_kernfs_path - pr_cont path of a kernfs_node
+ * pr_cont_kernfs_path_rcu - pr_cont path of a kernfs_node
  * @kn: kernfs_node of interest
  *
- * This function can be called from any context.
+ * This function can be called from any context. The root node must be with
+ * KERNFS_ROOT_SAME_PARENT.
  */
-void pr_cont_kernfs_path(struct kernfs_node *kn)
+void pr_cont_kernfs_path_rcu(struct kernfs_node *kn)
 {
 	unsigned long flags;
 	int sz;
 
 	spin_lock_irqsave(&kernfs_pr_cont_lock, flags);
 
-	sz = kernfs_path_from_node(kn, NULL, kernfs_pr_cont_buf,
-				   sizeof(kernfs_pr_cont_buf));
+	sz = kernfs_path_from_node_rcu(kn, NULL, kernfs_pr_cont_buf,
+				       sizeof(kernfs_pr_cont_buf));
 	if (sz < 0) {
 		if (sz == -E2BIG)
 			pr_cont("(name too long)");
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index f8ef47f8a634d..555a299e583ef 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -591,22 +591,22 @@ static inline struct cgroup_subsys_state *seq_css(struct seq_file *seq)
 
 static inline int cgroup_name(struct cgroup *cgrp, char *buf, size_t buflen)
 {
-	return kernfs_name(cgrp->kn, buf, buflen);
+	return kernfs_name_rcu(cgrp->kn, buf, buflen);
 }
 
 static inline int cgroup_path(struct cgroup *cgrp, char *buf, size_t buflen)
 {
-	return kernfs_path(cgrp->kn, buf, buflen);
+	return kernfs_path_rcu(cgrp->kn, buf, buflen);
 }
 
 static inline void pr_cont_cgroup_name(struct cgroup *cgrp)
 {
-	pr_cont_kernfs_name(cgrp->kn);
+	pr_cont_kernfs_name_rcu(cgrp->kn);
 }
 
 static inline void pr_cont_cgroup_path(struct cgroup *cgrp)
 {
-	pr_cont_kernfs_path(cgrp->kn);
+	pr_cont_kernfs_path_rcu(cgrp->kn);
 }
 
 bool cgroup_psi_enabled(void);
diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h
index b52393f1045c6..a1907f3c944d0 100644
--- a/include/linux/kernfs.h
+++ b/include/linux/kernfs.h
@@ -408,8 +408,8 @@ int kernfs_path_from_node(struct kernfs_node *kn_to, struct kernfs_node *kn_from
 			  char *buf, size_t buflen);
 int kernfs_path_from_node_rcu(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);
+void pr_cont_kernfs_name_rcu(struct kernfs_node *kn);
+void pr_cont_kernfs_path_rcu(struct kernfs_node *kn);
 struct kernfs_node *kernfs_get_parent(struct kernfs_node *kn);
 struct kernfs_node *kernfs_find_and_get_ns(struct kernfs_node *parent,
 					   const char *name, const void *ns);
@@ -499,8 +499,8 @@ static inline int kernfs_path_from_node_rcu(struct kernfs_node *root_kn,
 					    char *buf, size_t buflen)
 { return -ENOSYS; }
 
-static inline void pr_cont_kernfs_name(struct kernfs_node *kn) { }
-static inline void pr_cont_kernfs_path(struct kernfs_node *kn) { }
+static inline void pr_cont_kernfs_name_rcu(struct kernfs_node *kn) { }
+static inline void pr_cont_kernfs_path_rcu(struct kernfs_node *kn) { }
 
 static inline struct kernfs_node *kernfs_get_parent(struct kernfs_node *kn)
 { return NULL; }
@@ -617,6 +617,24 @@ static inline int kernfs_path(struct kernfs_node *kn, char *buf, size_t buflen)
 	return kernfs_path_from_node(kn, NULL, buf, buflen);
 }
 
+/**
+ * kernfs_path_rcu - build full path of a given node
+ * @kn: kernfs_node of interest
+ * @buf: buffer to copy @kn's name into
+ * @buflen: size of @buf
+ *
+ * If @kn is NULL result will be "(null)". The root node must be with
+ * KERNFS_ROOT_SAME_PARENT.
+ *
+ * Returns the length of the full path.  If the full length is equal to or
+ * greater than @buflen, @buf contains the truncated path with the trailing
+ * '\0'.  On error, -errno is returned.
+ */
+static inline int kernfs_path_rcu(struct kernfs_node *kn, char *buf, size_t buflen)
+{
+	return kernfs_path_from_node_rcu(kn, NULL, buf, buflen);
+}
+
 static inline struct kernfs_node *
 kernfs_find_and_get(struct kernfs_node *kn, const char *name)
 {
diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
index 044c7ba1cc482..6f8d555529525 100644
--- a/kernel/cgroup/cgroup.c
+++ b/kernel/cgroup/cgroup.c
@@ -1906,7 +1906,7 @@ int cgroup_show_path(struct seq_file *sf, struct kernfs_node *kf_node,
 
 	spin_lock_irq(&css_set_lock);
 	ns_cgroup = current_cgns_cgroup_from_root(kf_cgroot);
-	len = kernfs_path_from_node(kf_node, ns_cgroup->kn, buf, PATH_MAX);
+	len = kernfs_path_from_node_rcu(kf_node, ns_cgroup->kn, buf, PATH_MAX);
 	spin_unlock_irq(&css_set_lock);
 
 	if (len == -E2BIG)
@@ -2118,7 +2118,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_SAME_PARENT,
 					   root_cgrp);
 	if (IS_ERR(root->kf_root)) {
 		ret = PTR_ERR(root->kf_root);
@@ -2387,7 +2388,7 @@ int cgroup_path_ns_locked(struct cgroup *cgrp, char *buf, size_t buflen,
 {
 	struct cgroup *root = cset_cgroup_from_root(ns->root_cset, cgrp->root);
 
-	return kernfs_path_from_node(cgrp->kn, root->kn, buf, buflen);
+	return kernfs_path_from_node_rcu(cgrp->kn, root->kn, buf, buflen);
 }
 
 int cgroup_path_ns(struct cgroup *cgrp, char *buf, size_t buflen,
@@ -6275,7 +6276,7 @@ void cgroup_path_from_kernfs_id(u64 id, char *buf, size_t buflen)
 	kn = kernfs_find_and_get_node_by_id(cgrp_dfl_root.kf_root, id);
 	if (!kn)
 		return;
-	kernfs_path(kn, buf, buflen);
+	kernfs_path_rcu(kn, buf, buflen);
 	kernfs_put(kn);
 }
 
-- 
2.45.2





[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux OMAP]     [Linux MIPS]     [eCos]     [Asterisk Internet PBX]     [Linux API]     [Monitors]

  Powered by Linux