diff options
Diffstat (limited to 'kernel/cgroup.c')
-rw-r--r-- | kernel/cgroup.c | 41 |
1 files changed, 31 insertions, 10 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 1193038d0729..0398f2a6673b 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -573,6 +573,24 @@ static int notify_on_release(const struct cgroup *cgrp) ; \ else +/* walk live descendants in preorder */ +#define cgroup_for_each_live_descendant_pre(dsct, d_css, cgrp) \ + css_for_each_descendant_pre((d_css), cgroup_css((cgrp), NULL)) \ + if (({ lockdep_assert_held(&cgroup_mutex); \ + (dsct) = (d_css)->cgroup; \ + cgroup_is_dead(dsct); })) \ + ; \ + else + +/* walk live descendants in postorder */ +#define cgroup_for_each_live_descendant_post(dsct, d_css, cgrp) \ + css_for_each_descendant_post((d_css), cgroup_css((cgrp), NULL)) \ + if (({ lockdep_assert_held(&cgroup_mutex); \ + (dsct) = (d_css)->cgroup; \ + cgroup_is_dead(dsct); })) \ + ; \ + else + static void cgroup_release_agent(struct work_struct *work); static void check_for_release(struct cgroup *cgrp); @@ -2967,11 +2985,11 @@ out_finish: /** * cgroup_drain_offline - wait for previously offlined csses to go away - * @cgrp: parent of the target cgroups + * @cgrp: root of the target subtree * * Because css offlining is asynchronous, userland may try to re-enable a * controller while the previous css is still around. This function drains - * the previous css instances of @cgrp's children. + * the previous css instances of @cgrp's subtree. * * Must be called with cgroup_mutex held. Returns %false if there were no * dying css instances. Returns %true if there were one or more and this @@ -2982,17 +3000,18 @@ out_finish: static bool cgroup_drain_offline(struct cgroup *cgrp) { struct cgroup *dsct; + struct cgroup_subsys_state *d_css; struct cgroup_subsys *ss; int ssid; lockdep_assert_held(&cgroup_mutex); - cgroup_for_each_live_child(dsct, cgrp) { + cgroup_for_each_live_descendant_post(dsct, d_css, cgrp) { for_each_subsys(ss, ssid) { struct cgroup_subsys_state *css = cgroup_css(dsct, ss); DEFINE_WAIT(wait); - if (!css) + if (!css || !percpu_ref_is_dying(&css->refcnt)) continue; cgroup_get(dsct); @@ -3014,9 +3033,9 @@ static bool cgroup_drain_offline(struct cgroup *cgrp) /** * cgroup_apply_control_enable - enable or show csses according to control - * @cgrp: parent of the target cgroups + * @cgrp: root of the target subtree * - * Walk @cgrp's children and create new csses or make the existing ones + * Walk @cgrp's subtree and create new csses or make the existing ones * visible. A css is created invisible if it's being implicitly enabled * through dependency. An invisible css is made visible when the userland * explicitly enables it. @@ -3028,10 +3047,11 @@ static bool cgroup_drain_offline(struct cgroup *cgrp) static int cgroup_apply_control_enable(struct cgroup *cgrp) { struct cgroup *dsct; + struct cgroup_subsys_state *d_css; struct cgroup_subsys *ss; int ssid, ret; - cgroup_for_each_live_child(dsct, cgrp) { + cgroup_for_each_live_descendant_pre(dsct, d_css, cgrp) { for_each_subsys(ss, ssid) { struct cgroup_subsys_state *css = cgroup_css(dsct, ss); @@ -3057,9 +3077,9 @@ static int cgroup_apply_control_enable(struct cgroup *cgrp) /** * cgroup_apply_control_disable - kill or hide csses according to control - * @cgrp: parent of the target cgroups + * @cgrp: root of the target subtree * - * Walk @cgrp's children and kill and hide csses so that they match + * Walk @cgrp's subtree and kill and hide csses so that they match * cgroup_ss_mask() and cgroup_visible_mask(). * * A css is hidden when the userland requests it to be disabled while other @@ -3071,10 +3091,11 @@ static int cgroup_apply_control_enable(struct cgroup *cgrp) static void cgroup_apply_control_disable(struct cgroup *cgrp) { struct cgroup *dsct; + struct cgroup_subsys_state *d_css; struct cgroup_subsys *ss; int ssid; - cgroup_for_each_live_child(dsct, cgrp) { + cgroup_for_each_live_descendant_post(dsct, d_css, cgrp) { for_each_subsys(ss, ssid) { struct cgroup_subsys_state *css = cgroup_css(dsct, ss); |