Skip to content

Commit 46307fd

Browse files
Werkovhtejun
authored andcommitted
cgroup: Reorganize css_set_lock and kernfs path processing
The commit 74e4b95 incorrectly wrapped kernfs_walk_and_get (might_sleep) under css_set_lock (spinlock). css_set_lock is needed by __cset_cgroup_from_root to ensure stable cset->cgrp_links but not for kernfs_walk_and_get. We only need to make sure that the returned root_cgrp won't be freed under us. This is given in the case of global root because it is static (cgrp_dfl_root.cgrp). When the root_cgrp is lower in the hierarchy, it is pinned by cgroup_ns->root_cset (and `current` task cannot switch namespace asynchronously so ns_proxy pins cgroup_ns). Note this reasoning won't hold for root cgroups in v1 hierarchies, therefore create a special-cased helper function just for the default hierarchy. Fixes: 74e4b95 ("cgroup: Honor caller's cgroup NS when resolving path") Reported-by: Dan Carpenter <[email protected]> Signed-off-by: Michal Koutný <[email protected]> Signed-off-by: Tejun Heo <[email protected]>
1 parent 4de65c5 commit 46307fd

File tree

1 file changed

+27
-13
lines changed

1 file changed

+27
-13
lines changed

kernel/cgroup/cgroup.c

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1392,6 +1392,9 @@ static void cgroup_destroy_root(struct cgroup_root *root)
13921392
cgroup_free_root(root);
13931393
}
13941394

1395+
/*
1396+
* Returned cgroup is without refcount but it's valid as long as cset pins it.
1397+
*/
13951398
static inline struct cgroup *__cset_cgroup_from_root(struct css_set *cset,
13961399
struct cgroup_root *root)
13971400
{
@@ -1403,6 +1406,7 @@ static inline struct cgroup *__cset_cgroup_from_root(struct css_set *cset,
14031406
res_cgroup = cset->dfl_cgrp;
14041407
} else {
14051408
struct cgrp_cset_link *link;
1409+
lockdep_assert_held(&css_set_lock);
14061410

14071411
list_for_each_entry(link, &cset->cgrp_links, cgrp_link) {
14081412
struct cgroup *c = link->cgrp;
@@ -1414,6 +1418,7 @@ static inline struct cgroup *__cset_cgroup_from_root(struct css_set *cset,
14141418
}
14151419
}
14161420

1421+
BUG_ON(!res_cgroup);
14171422
return res_cgroup;
14181423
}
14191424

@@ -1436,23 +1441,36 @@ current_cgns_cgroup_from_root(struct cgroup_root *root)
14361441

14371442
rcu_read_unlock();
14381443

1439-
BUG_ON(!res);
14401444
return res;
14411445
}
14421446

1447+
/*
1448+
* Look up cgroup associated with current task's cgroup namespace on the default
1449+
* hierarchy.
1450+
*
1451+
* Unlike current_cgns_cgroup_from_root(), this doesn't need locks:
1452+
* - Internal rcu_read_lock is unnecessary because we don't dereference any rcu
1453+
* pointers.
1454+
* - css_set_lock is not needed because we just read cset->dfl_cgrp.
1455+
* - As a bonus returned cgrp is pinned with the current because it cannot
1456+
* switch cgroup_ns asynchronously.
1457+
*/
1458+
static struct cgroup *current_cgns_cgroup_dfl(void)
1459+
{
1460+
struct css_set *cset;
1461+
1462+
cset = current->nsproxy->cgroup_ns->root_cset;
1463+
return __cset_cgroup_from_root(cset, &cgrp_dfl_root);
1464+
}
1465+
14431466
/* look up cgroup associated with given css_set on the specified hierarchy */
14441467
static struct cgroup *cset_cgroup_from_root(struct css_set *cset,
14451468
struct cgroup_root *root)
14461469
{
1447-
struct cgroup *res = NULL;
1448-
14491470
lockdep_assert_held(&cgroup_mutex);
14501471
lockdep_assert_held(&css_set_lock);
14511472

1452-
res = __cset_cgroup_from_root(cset, root);
1453-
1454-
BUG_ON(!res);
1455-
return res;
1473+
return __cset_cgroup_from_root(cset, root);
14561474
}
14571475

14581476
/*
@@ -6105,9 +6123,7 @@ struct cgroup *cgroup_get_from_id(u64 id)
61056123
if (!cgrp)
61066124
return ERR_PTR(-ENOENT);
61076125

6108-
spin_lock_irq(&css_set_lock);
6109-
root_cgrp = current_cgns_cgroup_from_root(&cgrp_dfl_root);
6110-
spin_unlock_irq(&css_set_lock);
6126+
root_cgrp = current_cgns_cgroup_dfl();
61116127
if (!cgroup_is_descendant(cgrp, root_cgrp)) {
61126128
cgroup_put(cgrp);
61136129
return ERR_PTR(-ENOENT);
@@ -6686,10 +6702,8 @@ struct cgroup *cgroup_get_from_path(const char *path)
66866702
struct cgroup *cgrp = ERR_PTR(-ENOENT);
66876703
struct cgroup *root_cgrp;
66886704

6689-
spin_lock_irq(&css_set_lock);
6690-
root_cgrp = current_cgns_cgroup_from_root(&cgrp_dfl_root);
6705+
root_cgrp = current_cgns_cgroup_dfl();
66916706
kn = kernfs_walk_and_get(root_cgrp->kn, path);
6692-
spin_unlock_irq(&css_set_lock);
66936707
if (!kn)
66946708
goto out;
66956709

0 commit comments

Comments
 (0)