diff options
author | Tejun Heo <tj@kernel.org> | 2014-04-23 11:13:14 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2014-04-23 11:13:14 -0400 |
commit | aec3dfcb2e43892180ee053e8c260dcdeccf4392 (patch) | |
tree | 525148ea349802915f4918e7d97ca73ab3386d92 /kernel | |
parent | f392e51cd6ae6f6ee5b9b6d611cdc282b4c1711e (diff) |
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>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/cgroup.c | 83 |
1 files changed, 64 insertions, 19 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index f944619077f4..4eb2dd1bb5b1 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
@@ -208,6 +208,34 @@ static struct cgroup_subsys_state *cgroup_css(struct cgroup *cgrp, | |||
208 | return &cgrp->dummy_css; | 208 | return &cgrp->dummy_css; |
209 | } | 209 | } |
210 | 210 | ||
211 | /** | ||
212 | * cgroup_e_css - obtain a cgroup's effective css for the specified subsystem | ||
213 | * @cgrp: the cgroup of interest | ||
214 | * @ss: the subsystem of interest (%NULL returns the dummy_css) | ||
215 | * | ||
216 | * Similar to cgroup_css() but returns the effctive css, which is defined | ||
217 | * as the matching css of the nearest ancestor including self which has @ss | ||
218 | * enabled. If @ss is associated with the hierarchy @cgrp is on, this | ||
219 | * function is guaranteed to return non-NULL css. | ||
220 | */ | ||
221 | static struct cgroup_subsys_state *cgroup_e_css(struct cgroup *cgrp, | ||
222 | struct cgroup_subsys *ss) | ||
223 | { | ||
224 | lockdep_assert_held(&cgroup_mutex); | ||
225 | |||
226 | if (!ss) | ||
227 | return &cgrp->dummy_css; | ||
228 | |||
229 | if (!(cgrp->root->subsys_mask & (1 << ss->id))) | ||
230 | return NULL; | ||
231 | |||
232 | while (cgrp->parent && | ||
233 | !(cgrp->parent->child_subsys_mask & (1 << ss->id))) | ||
234 | cgrp = cgrp->parent; | ||
235 | |||
236 | return cgroup_css(cgrp, ss); | ||
237 | } | ||
238 | |||
211 | /* convenient tests for these bits */ | 239 | /* convenient tests for these bits */ |
212 | static inline bool cgroup_is_dead(const struct cgroup *cgrp) | 240 | static inline bool cgroup_is_dead(const struct cgroup *cgrp) |
213 | { | 241 | { |
@@ -273,7 +301,7 @@ static int notify_on_release(const struct cgroup *cgrp) | |||
273 | * @ssid: the index of the subsystem, CGROUP_SUBSYS_COUNT after reaching the end | 301 | * @ssid: the index of the subsystem, CGROUP_SUBSYS_COUNT after reaching the end |
274 | * @cgrp: the target cgroup to iterate css's of | 302 | * @cgrp: the target cgroup to iterate css's of |
275 | * | 303 | * |
276 | * Should be called under cgroup_mutex. | 304 | * Should be called under cgroup_[tree_]mutex. |
277 | */ | 305 | */ |
278 | #define for_each_css(css, ssid, cgrp) \ | 306 | #define for_each_css(css, ssid, cgrp) \ |
279 | for ((ssid) = 0; (ssid) < CGROUP_SUBSYS_COUNT; (ssid)++) \ | 307 | for ((ssid) = 0; (ssid) < CGROUP_SUBSYS_COUNT; (ssid)++) \ |
@@ -284,6 +312,20 @@ static int notify_on_release(const struct cgroup *cgrp) | |||
284 | else | 312 | else |
285 | 313 | ||
286 | /** | 314 | /** |
315 | * for_each_e_css - iterate all effective css's of a cgroup | ||
316 | * @css: the iteration cursor | ||
317 | * @ssid: the index of the subsystem, CGROUP_SUBSYS_COUNT after reaching the end | ||
318 | * @cgrp: the target cgroup to iterate css's of | ||
319 | * | ||
320 | * Should be called under cgroup_[tree_]mutex. | ||
321 | */ | ||
322 | #define for_each_e_css(css, ssid, cgrp) \ | ||
323 | for ((ssid) = 0; (ssid) < CGROUP_SUBSYS_COUNT; (ssid)++) \ | ||
324 | if (!((css) = cgroup_e_css(cgrp, cgroup_subsys[(ssid)]))) \ | ||
325 | ; \ | ||
326 | else | ||
327 | |||
328 | /** | ||
287 | * for_each_subsys - iterate all enabled cgroup subsystems | 329 | * for_each_subsys - iterate all enabled cgroup subsystems |
288 | * @ss: the iteration cursor | 330 | * @ss: the iteration cursor |
289 | * @ssid: the index of @ss, CGROUP_SUBSYS_COUNT after reaching the end | 331 | * @ssid: the index of @ss, CGROUP_SUBSYS_COUNT after reaching the end |
@@ -452,20 +494,20 @@ static bool compare_css_sets(struct css_set *cset, | |||
452 | { | 494 | { |
453 | struct list_head *l1, *l2; | 495 | struct list_head *l1, *l2; |
454 | 496 | ||
455 | if (memcmp(template, cset->subsys, sizeof(cset->subsys))) { | 497 | /* |
456 | /* Not all subsystems matched */ | 498 | * On the default hierarchy, there can be csets which are |
499 | * associated with the same set of cgroups but different csses. | ||
500 | * Let's first ensure that csses match. | ||
501 | */ | ||
502 | if (memcmp(template, cset->subsys, sizeof(cset->subsys))) | ||
457 | return false; | 503 | return false; |
458 | } | ||
459 | 504 | ||
460 | /* | 505 | /* |
461 | * Compare cgroup pointers in order to distinguish between | 506 | * Compare cgroup pointers in order to distinguish between |
462 | * different cgroups in heirarchies with no subsystems. We | 507 | * different cgroups in hierarchies. As different cgroups may |
463 | * could get by with just this check alone (and skip the | 508 | * share the same effective css, this comparison is always |
464 | * memcmp above) but on most setups the memcmp check will | 509 | * necessary. |
465 | * avoid the need for this more expensive check on almost all | ||
466 | * candidates. | ||
467 | */ | 510 | */ |
468 | |||
469 | l1 = &cset->cgrp_links; | 511 | l1 = &cset->cgrp_links; |
470 | l2 = &old_cset->cgrp_links; | 512 | l2 = &old_cset->cgrp_links; |
471 | while (1) { | 513 | while (1) { |
@@ -530,13 +572,16 @@ static struct css_set *find_existing_css_set(struct css_set *old_cset, | |||
530 | */ | 572 | */ |
531 | for_each_subsys(ss, i) { | 573 | for_each_subsys(ss, i) { |
532 | if (root->subsys_mask & (1UL << i)) { | 574 | if (root->subsys_mask & (1UL << i)) { |
533 | /* Subsystem is in this hierarchy. So we want | 575 | /* |
534 | * the subsystem state from the new | 576 | * @ss is in this hierarchy, so we want the |
535 | * cgroup */ | 577 | * effective css from @cgrp. |
536 | template[i] = cgroup_css(cgrp, ss); | 578 | */ |
579 | template[i] = cgroup_e_css(cgrp, ss); | ||
537 | } else { | 580 | } else { |
538 | /* Subsystem is not in this hierarchy, so we | 581 | /* |
539 | * don't want to change the subsystem state */ | 582 | * @ss is not in this hierarchy, so we don't want |
583 | * to change the css. | ||
584 | */ | ||
540 | template[i] = old_cset->subsys[i]; | 585 | template[i] = old_cset->subsys[i]; |
541 | } | 586 | } |
542 | } | 587 | } |
@@ -1969,7 +2014,7 @@ static int cgroup_migrate(struct cgroup *cgrp, struct task_struct *leader, | |||
1969 | return 0; | 2014 | return 0; |
1970 | 2015 | ||
1971 | /* check that we can legitimately attach to the cgroup */ | 2016 | /* check that we can legitimately attach to the cgroup */ |
1972 | for_each_css(css, i, cgrp) { | 2017 | for_each_e_css(css, i, cgrp) { |
1973 | if (css->ss->can_attach) { | 2018 | if (css->ss->can_attach) { |
1974 | ret = css->ss->can_attach(css, &tset); | 2019 | ret = css->ss->can_attach(css, &tset); |
1975 | if (ret) { | 2020 | if (ret) { |
@@ -1999,7 +2044,7 @@ static int cgroup_migrate(struct cgroup *cgrp, struct task_struct *leader, | |||
1999 | */ | 2044 | */ |
2000 | tset.csets = &tset.dst_csets; | 2045 | tset.csets = &tset.dst_csets; |
2001 | 2046 | ||
2002 | for_each_css(css, i, cgrp) | 2047 | for_each_e_css(css, i, cgrp) |
2003 | if (css->ss->attach) | 2048 | if (css->ss->attach) |
2004 | css->ss->attach(css, &tset); | 2049 | css->ss->attach(css, &tset); |
2005 | 2050 | ||
@@ -2007,7 +2052,7 @@ static int cgroup_migrate(struct cgroup *cgrp, struct task_struct *leader, | |||
2007 | goto out_release_tset; | 2052 | goto out_release_tset; |
2008 | 2053 | ||
2009 | out_cancel_attach: | 2054 | out_cancel_attach: |
2010 | for_each_css(css, i, cgrp) { | 2055 | for_each_e_css(css, i, cgrp) { |
2011 | if (css == failed_css) | 2056 | if (css == failed_css) |
2012 | break; | 2057 | break; |
2013 | if (css->ss->cancel_attach) | 2058 | if (css->ss->cancel_attach) |