cgroup: introduce effective cgroup_subsys_state
In the planned default unified hierarchy, controllers may get dynamically attached to and detached from a cgroup and a cgroup may not have csses for all the controllers associated with the hierarchy. When a cgroup doesn't have its own css for a given controller, the css of the nearest ancestor with the controller enabled will be used, which is called the effective css. This patch introduces cgroup_e_css() and for_each_e_css() to access the effective csses and convert compare_css_sets(), find_existing_css_set() and cgroup_migrate() to use the effective csses so that they can handle cgroups with partial csses correctly. This means that for two css_sets to be considered identical, they should have both matching csses and cgroups. compare_css_sets() already compares both, not for correctness but for optimization. As this now becomes a matter of correctness, update the comments accordingly. For all !default hierarchies, cgroup_e_css() always equals cgroup_css(), so this patch doesn't change behavior. While at it, fix incorrect locking comment for for_each_css(). Signed-off-by: Tejun Heo <tj@kernel.org> Acked-by: Li Zefan <lizefan@huawei.com>
This commit is contained in:
parent
f392e51cd6
commit
aec3dfcb2e
1 changed files with 64 additions and 19 deletions
|
@ -208,6 +208,34 @@ static struct cgroup_subsys_state *cgroup_css(struct cgroup *cgrp,
|
||||||
return &cgrp->dummy_css;
|
return &cgrp->dummy_css;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cgroup_e_css - obtain a cgroup's effective css for the specified subsystem
|
||||||
|
* @cgrp: the cgroup of interest
|
||||||
|
* @ss: the subsystem of interest (%NULL returns the dummy_css)
|
||||||
|
*
|
||||||
|
* Similar to cgroup_css() but returns the effctive css, which is defined
|
||||||
|
* as the matching css of the nearest ancestor including self which has @ss
|
||||||
|
* enabled. If @ss is associated with the hierarchy @cgrp is on, this
|
||||||
|
* function is guaranteed to return non-NULL css.
|
||||||
|
*/
|
||||||
|
static struct cgroup_subsys_state *cgroup_e_css(struct cgroup *cgrp,
|
||||||
|
struct cgroup_subsys *ss)
|
||||||
|
{
|
||||||
|
lockdep_assert_held(&cgroup_mutex);
|
||||||
|
|
||||||
|
if (!ss)
|
||||||
|
return &cgrp->dummy_css;
|
||||||
|
|
||||||
|
if (!(cgrp->root->subsys_mask & (1 << ss->id)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
while (cgrp->parent &&
|
||||||
|
!(cgrp->parent->child_subsys_mask & (1 << ss->id)))
|
||||||
|
cgrp = cgrp->parent;
|
||||||
|
|
||||||
|
return cgroup_css(cgrp, ss);
|
||||||
|
}
|
||||||
|
|
||||||
/* convenient tests for these bits */
|
/* convenient tests for these bits */
|
||||||
static inline bool cgroup_is_dead(const struct cgroup *cgrp)
|
static inline bool cgroup_is_dead(const struct cgroup *cgrp)
|
||||||
{
|
{
|
||||||
|
@ -273,7 +301,7 @@ static int notify_on_release(const struct cgroup *cgrp)
|
||||||
* @ssid: the index of the subsystem, CGROUP_SUBSYS_COUNT after reaching the end
|
* @ssid: the index of the subsystem, CGROUP_SUBSYS_COUNT after reaching the end
|
||||||
* @cgrp: the target cgroup to iterate css's of
|
* @cgrp: the target cgroup to iterate css's of
|
||||||
*
|
*
|
||||||
* Should be called under cgroup_mutex.
|
* Should be called under cgroup_[tree_]mutex.
|
||||||
*/
|
*/
|
||||||
#define for_each_css(css, ssid, cgrp) \
|
#define for_each_css(css, ssid, cgrp) \
|
||||||
for ((ssid) = 0; (ssid) < CGROUP_SUBSYS_COUNT; (ssid)++) \
|
for ((ssid) = 0; (ssid) < CGROUP_SUBSYS_COUNT; (ssid)++) \
|
||||||
|
@ -283,6 +311,20 @@ static int notify_on_release(const struct cgroup *cgrp)
|
||||||
lockdep_is_held(&cgroup_mutex)))) { } \
|
lockdep_is_held(&cgroup_mutex)))) { } \
|
||||||
else
|
else
|
||||||
|
|
||||||
|
/**
|
||||||
|
* for_each_e_css - iterate all effective css's of a cgroup
|
||||||
|
* @css: the iteration cursor
|
||||||
|
* @ssid: the index of the subsystem, CGROUP_SUBSYS_COUNT after reaching the end
|
||||||
|
* @cgrp: the target cgroup to iterate css's of
|
||||||
|
*
|
||||||
|
* Should be called under cgroup_[tree_]mutex.
|
||||||
|
*/
|
||||||
|
#define for_each_e_css(css, ssid, cgrp) \
|
||||||
|
for ((ssid) = 0; (ssid) < CGROUP_SUBSYS_COUNT; (ssid)++) \
|
||||||
|
if (!((css) = cgroup_e_css(cgrp, cgroup_subsys[(ssid)]))) \
|
||||||
|
; \
|
||||||
|
else
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* for_each_subsys - iterate all enabled cgroup subsystems
|
* for_each_subsys - iterate all enabled cgroup subsystems
|
||||||
* @ss: the iteration cursor
|
* @ss: the iteration cursor
|
||||||
|
@ -452,20 +494,20 @@ static bool compare_css_sets(struct css_set *cset,
|
||||||
{
|
{
|
||||||
struct list_head *l1, *l2;
|
struct list_head *l1, *l2;
|
||||||
|
|
||||||
if (memcmp(template, cset->subsys, sizeof(cset->subsys))) {
|
/*
|
||||||
/* Not all subsystems matched */
|
* On the default hierarchy, there can be csets which are
|
||||||
|
* associated with the same set of cgroups but different csses.
|
||||||
|
* Let's first ensure that csses match.
|
||||||
|
*/
|
||||||
|
if (memcmp(template, cset->subsys, sizeof(cset->subsys)))
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compare cgroup pointers in order to distinguish between
|
* Compare cgroup pointers in order to distinguish between
|
||||||
* different cgroups in heirarchies with no subsystems. We
|
* different cgroups in hierarchies. As different cgroups may
|
||||||
* could get by with just this check alone (and skip the
|
* share the same effective css, this comparison is always
|
||||||
* memcmp above) but on most setups the memcmp check will
|
* necessary.
|
||||||
* avoid the need for this more expensive check on almost all
|
|
||||||
* candidates.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
l1 = &cset->cgrp_links;
|
l1 = &cset->cgrp_links;
|
||||||
l2 = &old_cset->cgrp_links;
|
l2 = &old_cset->cgrp_links;
|
||||||
while (1) {
|
while (1) {
|
||||||
|
@ -530,13 +572,16 @@ static struct css_set *find_existing_css_set(struct css_set *old_cset,
|
||||||
*/
|
*/
|
||||||
for_each_subsys(ss, i) {
|
for_each_subsys(ss, i) {
|
||||||
if (root->subsys_mask & (1UL << i)) {
|
if (root->subsys_mask & (1UL << i)) {
|
||||||
/* Subsystem is in this hierarchy. So we want
|
/*
|
||||||
* the subsystem state from the new
|
* @ss is in this hierarchy, so we want the
|
||||||
* cgroup */
|
* effective css from @cgrp.
|
||||||
template[i] = cgroup_css(cgrp, ss);
|
*/
|
||||||
|
template[i] = cgroup_e_css(cgrp, ss);
|
||||||
} else {
|
} else {
|
||||||
/* Subsystem is not in this hierarchy, so we
|
/*
|
||||||
* don't want to change the subsystem state */
|
* @ss is not in this hierarchy, so we don't want
|
||||||
|
* to change the css.
|
||||||
|
*/
|
||||||
template[i] = old_cset->subsys[i];
|
template[i] = old_cset->subsys[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1969,7 +2014,7 @@ static int cgroup_migrate(struct cgroup *cgrp, struct task_struct *leader,
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* check that we can legitimately attach to the cgroup */
|
/* check that we can legitimately attach to the cgroup */
|
||||||
for_each_css(css, i, cgrp) {
|
for_each_e_css(css, i, cgrp) {
|
||||||
if (css->ss->can_attach) {
|
if (css->ss->can_attach) {
|
||||||
ret = css->ss->can_attach(css, &tset);
|
ret = css->ss->can_attach(css, &tset);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
@ -1999,7 +2044,7 @@ static int cgroup_migrate(struct cgroup *cgrp, struct task_struct *leader,
|
||||||
*/
|
*/
|
||||||
tset.csets = &tset.dst_csets;
|
tset.csets = &tset.dst_csets;
|
||||||
|
|
||||||
for_each_css(css, i, cgrp)
|
for_each_e_css(css, i, cgrp)
|
||||||
if (css->ss->attach)
|
if (css->ss->attach)
|
||||||
css->ss->attach(css, &tset);
|
css->ss->attach(css, &tset);
|
||||||
|
|
||||||
|
@ -2007,7 +2052,7 @@ static int cgroup_migrate(struct cgroup *cgrp, struct task_struct *leader,
|
||||||
goto out_release_tset;
|
goto out_release_tset;
|
||||||
|
|
||||||
out_cancel_attach:
|
out_cancel_attach:
|
||||||
for_each_css(css, i, cgrp) {
|
for_each_e_css(css, i, cgrp) {
|
||||||
if (css == failed_css)
|
if (css == failed_css)
|
||||||
break;
|
break;
|
||||||
if (css->ss->cancel_attach)
|
if (css->ss->cancel_attach)
|
||||||
|
|
Loading…
Add table
Reference in a new issue