Skip to content

Commit be28816

Browse files
shakeelbhtejun
authored andcommitted
cgroup: reduce dependency on cgroup_mutex
Currently cgroup_get_from_path() and cgroup_get_from_id() grab cgroup_mutex before traversing the default hierarchy to find the kernfs_node corresponding to the path/id and then extract the linked cgroup. Since cgroup_mutex is still held, it is guaranteed that the cgroup will be alive and the reference can be taken on it. However similar guarantee can be provided without depending on the cgroup_mutex and potentially reducing avenues of cgroup_mutex contentions. The kernfs_node's priv pointer is RCU protected pointer and with just rcu read lock we can grab the reference on the cgroup without cgroup_mutex. So, remove cgroup_mutex from them. Signed-off-by: Shakeel Butt <[email protected]> Signed-off-by: Tejun Heo <[email protected]>
1 parent 0061270 commit be28816

File tree

1 file changed

+29
-22
lines changed

1 file changed

+29
-22
lines changed

kernel/cgroup/cgroup.c

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5932,17 +5932,20 @@ struct cgroup *cgroup_get_from_id(u64 id)
59325932
struct kernfs_node *kn;
59335933
struct cgroup *cgrp = NULL;
59345934

5935-
mutex_lock(&cgroup_mutex);
59365935
kn = kernfs_find_and_get_node_by_id(cgrp_dfl_root.kf_root, id);
59375936
if (!kn)
5938-
goto out_unlock;
5937+
goto out;
5938+
5939+
rcu_read_lock();
59395940

5940-
cgrp = kn->priv;
5941-
if (cgroup_is_dead(cgrp) || !cgroup_tryget(cgrp))
5941+
cgrp = rcu_dereference(*(void __rcu __force **)&kn->priv);
5942+
if (cgrp && !cgroup_tryget(cgrp))
59425943
cgrp = NULL;
5944+
5945+
rcu_read_unlock();
5946+
59435947
kernfs_put(kn);
5944-
out_unlock:
5945-
mutex_unlock(&cgroup_mutex);
5948+
out:
59465949
return cgrp;
59475950
}
59485951
EXPORT_SYMBOL_GPL(cgroup_get_from_id);
@@ -6495,30 +6498,34 @@ struct cgroup_subsys_state *css_from_id(int id, struct cgroup_subsys *ss)
64956498
*
64966499
* Find the cgroup at @path on the default hierarchy, increment its
64976500
* reference count and return it. Returns pointer to the found cgroup on
6498-
* success, ERR_PTR(-ENOENT) if @path doesn't exist and ERR_PTR(-ENOTDIR)
6499-
* if @path points to a non-directory.
6501+
* success, ERR_PTR(-ENOENT) if @path doesn't exist or if the cgroup has already
6502+
* been released and ERR_PTR(-ENOTDIR) if @path points to a non-directory.
65006503
*/
65016504
struct cgroup *cgroup_get_from_path(const char *path)
65026505
{
65036506
struct kernfs_node *kn;
6504-
struct cgroup *cgrp;
6505-
6506-
mutex_lock(&cgroup_mutex);
6507+
struct cgroup *cgrp = ERR_PTR(-ENOENT);
65076508

65086509
kn = kernfs_walk_and_get(cgrp_dfl_root.cgrp.kn, path);
6509-
if (kn) {
6510-
if (kernfs_type(kn) == KERNFS_DIR) {
6511-
cgrp = kn->priv;
6512-
cgroup_get_live(cgrp);
6513-
} else {
6514-
cgrp = ERR_PTR(-ENOTDIR);
6515-
}
6516-
kernfs_put(kn);
6517-
} else {
6518-
cgrp = ERR_PTR(-ENOENT);
6510+
if (!kn)
6511+
goto out;
6512+
6513+
if (kernfs_type(kn) != KERNFS_DIR) {
6514+
cgrp = ERR_PTR(-ENOTDIR);
6515+
goto out_kernfs;
65196516
}
65206517

6521-
mutex_unlock(&cgroup_mutex);
6518+
rcu_read_lock();
6519+
6520+
cgrp = rcu_dereference(*(void __rcu __force **)&kn->priv);
6521+
if (!cgrp || !cgroup_tryget(cgrp))
6522+
cgrp = ERR_PTR(-ENOENT);
6523+
6524+
rcu_read_unlock();
6525+
6526+
out_kernfs:
6527+
kernfs_put(kn);
6528+
out:
65226529
return cgrp;
65236530
}
65246531
EXPORT_SYMBOL_GPL(cgroup_get_from_path);

0 commit comments

Comments
 (0)