Michal Koutný 249c98
From: Shakeel Butt <shakeelb@google.com>
Michal Koutný 249c98
Date: Sun, 24 Oct 2021 23:19:14 -0700
Michal Koutný 249c98
Subject: cgroup: reduce dependency on cgroup_mutex
Michal Koutný 249c98
Git-commit: be288169712f3dea0bc6b50c00b3ab53d85f1435
Michal Koutný 249c98
Patch-mainline: v5.16-rc1
Michal Koutný 249c98
References: bsc#1205650
Michal Koutný 249c98
Michal Koutný 249c98
Currently cgroup_get_from_path() and cgroup_get_from_id() grab
Michal Koutný 249c98
cgroup_mutex before traversing the default hierarchy to find the
Michal Koutný 249c98
kernfs_node corresponding to the path/id and then extract the linked
Michal Koutný 249c98
cgroup. Since cgroup_mutex is still held, it is guaranteed that the
Michal Koutný 249c98
cgroup will be alive and the reference can be taken on it.
Michal Koutný 249c98
Michal Koutný 249c98
However similar guarantee can be provided without depending on the
Michal Koutný 249c98
cgroup_mutex and potentially reducing avenues of cgroup_mutex contentions.
Michal Koutný 249c98
The kernfs_node's priv pointer is RCU protected pointer and with just
Michal Koutný 249c98
rcu read lock we can grab the reference on the cgroup without
Michal Koutný 249c98
cgroup_mutex. So, remove cgroup_mutex from them.
Michal Koutný 249c98
Michal Koutný 249c98
Signed-off-by: Shakeel Butt <shakeelb@google.com>
Michal Koutný 249c98
Signed-off-by: Tejun Heo <tj@kernel.org>
Michal Koutný 249c98
Acked-by: Michal Koutný <mkoutny@suse.com>
Michal Koutný 249c98
---
Michal Koutný 249c98
 kernel/cgroup/cgroup.c | 51 ++++++++++++++++++++++++++++----------------------
Michal Koutný 249c98
 1 file changed, 29 insertions(+), 22 deletions(-)
Michal Koutný 249c98
Michal Koutný 249c98
diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
Michal Koutný 249c98
index 2e98db4558f2..003204c85893 100644
Michal Koutný 249c98
--- a/kernel/cgroup/cgroup.c
Michal Koutný 249c98
+++ b/kernel/cgroup/cgroup.c
Michal Koutný 249c98
@@ -5932,17 +5932,20 @@ struct cgroup *cgroup_get_from_id(u64 id)
Michal Koutný 249c98
 	struct kernfs_node *kn;
Michal Koutný 249c98
 	struct cgroup *cgrp = NULL;
Michal Koutný 249c98
 
Michal Koutný 249c98
-	mutex_lock(&cgroup_mutex);
Michal Koutný 249c98
 	kn = kernfs_find_and_get_node_by_id(cgrp_dfl_root.kf_root, id);
Michal Koutný 249c98
 	if (!kn)
Michal Koutný 249c98
-		goto out_unlock;
Michal Koutný 249c98
+		goto out;
Michal Koutný 249c98
+
Michal Koutný 249c98
+	rcu_read_lock();
Michal Koutný 249c98
 
Michal Koutný 249c98
-	cgrp = kn->priv;
Michal Koutný 249c98
-	if (cgroup_is_dead(cgrp) || !cgroup_tryget(cgrp))
Michal Koutný 249c98
+	cgrp = rcu_dereference(*(void __rcu __force **)&kn->priv);
Michal Koutný 249c98
+	if (cgrp && !cgroup_tryget(cgrp))
Michal Koutný 249c98
 		cgrp = NULL;
Michal Koutný 249c98
+
Michal Koutný 249c98
+	rcu_read_unlock();
Michal Koutný 249c98
+
Michal Koutný 249c98
 	kernfs_put(kn);
Michal Koutný 249c98
-out_unlock:
Michal Koutný 249c98
-	mutex_unlock(&cgroup_mutex);
Michal Koutný 249c98
+out:
Michal Koutný 249c98
 	return cgrp;
Michal Koutný 249c98
 }
Michal Koutný 249c98
 EXPORT_SYMBOL_GPL(cgroup_get_from_id);
Michal Koutný 249c98
@@ -6495,30 +6498,34 @@ struct cgroup_subsys_state *css_from_id(int id, struct cgroup_subsys *ss)
Michal Koutný 249c98
  *
Michal Koutný 249c98
  * Find the cgroup at @path on the default hierarchy, increment its
Michal Koutný 249c98
  * reference count and return it.  Returns pointer to the found cgroup on
Michal Koutný 249c98
- * success, ERR_PTR(-ENOENT) if @path doesn't exist and ERR_PTR(-ENOTDIR)
Michal Koutný 249c98
- * if @path points to a non-directory.
Michal Koutný 249c98
+ * success, ERR_PTR(-ENOENT) if @path doesn't exist or if the cgroup has already
Michal Koutný 249c98
+ * been released and ERR_PTR(-ENOTDIR) if @path points to a non-directory.
Michal Koutný 249c98
  */
Michal Koutný 249c98
 struct cgroup *cgroup_get_from_path(const char *path)
Michal Koutný 249c98
 {
Michal Koutný 249c98
 	struct kernfs_node *kn;
Michal Koutný 249c98
-	struct cgroup *cgrp;
Michal Koutný 249c98
-
Michal Koutný 249c98
-	mutex_lock(&cgroup_mutex);
Michal Koutný 249c98
+	struct cgroup *cgrp = ERR_PTR(-ENOENT);
Michal Koutný 249c98
 
Michal Koutný 249c98
 	kn = kernfs_walk_and_get(cgrp_dfl_root.cgrp.kn, path);
Michal Koutný 249c98
-	if (kn) {
Michal Koutný 249c98
-		if (kernfs_type(kn) == KERNFS_DIR) {
Michal Koutný 249c98
-			cgrp = kn->priv;
Michal Koutný 249c98
-			cgroup_get_live(cgrp);
Michal Koutný 249c98
-		} else {
Michal Koutný 249c98
-			cgrp = ERR_PTR(-ENOTDIR);
Michal Koutný 249c98
-		}
Michal Koutný 249c98
-		kernfs_put(kn);
Michal Koutný 249c98
-	} else {
Michal Koutný 249c98
-		cgrp = ERR_PTR(-ENOENT);
Michal Koutný 249c98
+	if (!kn)
Michal Koutný 249c98
+		goto out;
Michal Koutný 249c98
+
Michal Koutný 249c98
+	if (kernfs_type(kn) != KERNFS_DIR) {
Michal Koutný 249c98
+		cgrp = ERR_PTR(-ENOTDIR);
Michal Koutný 249c98
+		goto out_kernfs;
Michal Koutný 249c98
 	}
Michal Koutný 249c98
 
Michal Koutný 249c98
-	mutex_unlock(&cgroup_mutex);
Michal Koutný 249c98
+	rcu_read_lock();
Michal Koutný 249c98
+
Michal Koutný 249c98
+	cgrp = rcu_dereference(*(void __rcu __force **)&kn->priv);
Michal Koutný 249c98
+	if (!cgrp || !cgroup_tryget(cgrp))
Michal Koutný 249c98
+		cgrp = ERR_PTR(-ENOENT);
Michal Koutný 249c98
+
Michal Koutný 249c98
+	rcu_read_unlock();
Michal Koutný 249c98
+
Michal Koutný 249c98
+out_kernfs:
Michal Koutný 249c98
+	kernfs_put(kn);
Michal Koutný 249c98
+out:
Michal Koutný 249c98
 	return cgrp;
Michal Koutný 249c98
 }
Michal Koutný 249c98
 EXPORT_SYMBOL_GPL(cgroup_get_from_path);
Michal Koutný 249c98