diff options
| -rw-r--r-- | include/linux/cgroup.h | 2 | ||||
| -rw-r--r-- | kernel/cgroup.c | 32 |
2 files changed, 22 insertions, 12 deletions
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index 51a339c99eb6..b76999954beb 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h | |||
| @@ -873,6 +873,8 @@ css_next_descendant_post(struct cgroup_subsys_state *pos, | |||
| 873 | for ((pos) = css_next_descendant_post(NULL, (css)); (pos); \ | 873 | for ((pos) = css_next_descendant_post(NULL, (css)); (pos); \ |
| 874 | (pos) = css_next_descendant_post((pos), (css))) | 874 | (pos) = css_next_descendant_post((pos), (css))) |
| 875 | 875 | ||
| 876 | bool css_has_online_children(struct cgroup_subsys_state *css); | ||
| 877 | |||
| 876 | /* A css_task_iter should be treated as an opaque object */ | 878 | /* A css_task_iter should be treated as an opaque object */ |
| 877 | struct css_task_iter { | 879 | struct css_task_iter { |
| 878 | struct cgroup_subsys *ss; | 880 | struct cgroup_subsys *ss; |
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 004004fd0ded..082bb842b11a 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
| @@ -175,7 +175,6 @@ static int need_forkexit_callback __read_mostly; | |||
| 175 | static struct cftype cgroup_base_files[]; | 175 | static struct cftype cgroup_base_files[]; |
| 176 | 176 | ||
| 177 | static void cgroup_put(struct cgroup *cgrp); | 177 | static void cgroup_put(struct cgroup *cgrp); |
| 178 | static bool cgroup_has_live_children(struct cgroup *cgrp); | ||
| 179 | static int rebind_subsystems(struct cgroup_root *dst_root, | 178 | static int rebind_subsystems(struct cgroup_root *dst_root, |
| 180 | unsigned int ss_mask); | 179 | unsigned int ss_mask); |
| 181 | static int cgroup_destroy_locked(struct cgroup *cgrp); | 180 | static int cgroup_destroy_locked(struct cgroup *cgrp); |
| @@ -1769,7 +1768,7 @@ static void cgroup_kill_sb(struct super_block *sb) | |||
| 1769 | * This prevents new mounts by disabling percpu_ref_tryget_live(). | 1768 | * This prevents new mounts by disabling percpu_ref_tryget_live(). |
| 1770 | * cgroup_mount() may wait for @root's release. | 1769 | * cgroup_mount() may wait for @root's release. |
| 1771 | */ | 1770 | */ |
| 1772 | if (cgroup_has_live_children(&root->cgrp)) | 1771 | if (css_has_online_children(&root->cgrp.self)) |
| 1773 | cgroup_put(&root->cgrp); | 1772 | cgroup_put(&root->cgrp); |
| 1774 | else | 1773 | else |
| 1775 | percpu_ref_kill(&root->cgrp.self.refcnt); | 1774 | percpu_ref_kill(&root->cgrp.self.refcnt); |
| @@ -3291,19 +3290,28 @@ css_next_descendant_post(struct cgroup_subsys_state *pos, | |||
| 3291 | return pos->parent; | 3290 | return pos->parent; |
| 3292 | } | 3291 | } |
| 3293 | 3292 | ||
| 3294 | static bool cgroup_has_live_children(struct cgroup *cgrp) | 3293 | /** |
| 3294 | * css_has_online_children - does a css have online children | ||
| 3295 | * @css: the target css | ||
| 3296 | * | ||
| 3297 | * Returns %true if @css has any online children; otherwise, %false. This | ||
| 3298 | * function can be called from any context but the caller is responsible | ||
| 3299 | * for synchronizing against on/offlining as necessary. | ||
| 3300 | */ | ||
| 3301 | bool css_has_online_children(struct cgroup_subsys_state *css) | ||
| 3295 | { | 3302 | { |
| 3296 | struct cgroup *child; | 3303 | struct cgroup_subsys_state *child; |
| 3304 | bool ret = false; | ||
| 3297 | 3305 | ||
| 3298 | rcu_read_lock(); | 3306 | rcu_read_lock(); |
| 3299 | list_for_each_entry_rcu(child, &cgrp->self.children, self.sibling) { | 3307 | css_for_each_child(child, css) { |
| 3300 | if (!cgroup_is_dead(child)) { | 3308 | if (css->flags & CSS_ONLINE) { |
| 3301 | rcu_read_unlock(); | 3309 | ret = true; |
| 3302 | return true; | 3310 | break; |
| 3303 | } | 3311 | } |
| 3304 | } | 3312 | } |
| 3305 | rcu_read_unlock(); | 3313 | rcu_read_unlock(); |
| 3306 | return false; | 3314 | return ret; |
| 3307 | } | 3315 | } |
| 3308 | 3316 | ||
| 3309 | /** | 3317 | /** |
| @@ -4535,7 +4543,7 @@ static int cgroup_destroy_locked(struct cgroup *cgrp) | |||
| 4535 | * ->self.children as dead children linger on it while being | 4543 | * ->self.children as dead children linger on it while being |
| 4536 | * drained; otherwise, "rmdir parent/child parent" may fail. | 4544 | * drained; otherwise, "rmdir parent/child parent" may fail. |
| 4537 | */ | 4545 | */ |
| 4538 | if (cgroup_has_live_children(cgrp)) | 4546 | if (css_has_online_children(&cgrp->self)) |
| 4539 | return -EBUSY; | 4547 | return -EBUSY; |
| 4540 | 4548 | ||
| 4541 | /* | 4549 | /* |
| @@ -5014,8 +5022,8 @@ void cgroup_exit(struct task_struct *tsk) | |||
| 5014 | 5022 | ||
| 5015 | static void check_for_release(struct cgroup *cgrp) | 5023 | static void check_for_release(struct cgroup *cgrp) |
| 5016 | { | 5024 | { |
| 5017 | if (cgroup_is_releasable(cgrp) && | 5025 | if (cgroup_is_releasable(cgrp) && list_empty(&cgrp->cset_links) && |
| 5018 | list_empty(&cgrp->cset_links) && !cgroup_has_live_children(cgrp)) { | 5026 | !css_has_online_children(&cgrp->self)) { |
| 5019 | /* | 5027 | /* |
| 5020 | * Control Group is currently removeable. If it's not | 5028 | * Control Group is currently removeable. If it's not |
| 5021 | * already queued for a userspace notification, queue | 5029 | * already queued for a userspace notification, queue |
