diff options
Diffstat (limited to 'kernel/cgroup.c')
| -rw-r--r-- | kernel/cgroup.c | 19 |
1 files changed, 18 insertions, 1 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 781845a013ab..e91963302c0d 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
| @@ -4480,6 +4480,7 @@ static int cgroup_destroy_locked(struct cgroup *cgrp) | |||
| 4480 | struct dentry *d = cgrp->dentry; | 4480 | struct dentry *d = cgrp->dentry; |
| 4481 | struct cgroup_event *event, *tmp; | 4481 | struct cgroup_event *event, *tmp; |
| 4482 | struct cgroup_subsys *ss; | 4482 | struct cgroup_subsys *ss; |
| 4483 | struct cgroup *child; | ||
| 4483 | bool empty; | 4484 | bool empty; |
| 4484 | 4485 | ||
| 4485 | lockdep_assert_held(&d->d_inode->i_mutex); | 4486 | lockdep_assert_held(&d->d_inode->i_mutex); |
| @@ -4490,12 +4491,28 @@ static int cgroup_destroy_locked(struct cgroup *cgrp) | |||
| 4490 | * @cgrp from being removed while __put_css_set() is in progress. | 4491 | * @cgrp from being removed while __put_css_set() is in progress. |
| 4491 | */ | 4492 | */ |
| 4492 | read_lock(&css_set_lock); | 4493 | read_lock(&css_set_lock); |
| 4493 | empty = list_empty(&cgrp->cset_links) && list_empty(&cgrp->children); | 4494 | empty = list_empty(&cgrp->cset_links); |
| 4494 | read_unlock(&css_set_lock); | 4495 | read_unlock(&css_set_lock); |
| 4495 | if (!empty) | 4496 | if (!empty) |
| 4496 | return -EBUSY; | 4497 | return -EBUSY; |
| 4497 | 4498 | ||
| 4498 | /* | 4499 | /* |
| 4500 | * Make sure there's no live children. We can't test ->children | ||
| 4501 | * emptiness as dead children linger on it while being destroyed; | ||
| 4502 | * otherwise, "rmdir parent/child parent" may fail with -EBUSY. | ||
| 4503 | */ | ||
| 4504 | empty = true; | ||
| 4505 | rcu_read_lock(); | ||
| 4506 | list_for_each_entry_rcu(child, &cgrp->children, sibling) { | ||
| 4507 | empty = cgroup_is_dead(child); | ||
| 4508 | if (!empty) | ||
| 4509 | break; | ||
| 4510 | } | ||
| 4511 | rcu_read_unlock(); | ||
| 4512 | if (!empty) | ||
| 4513 | return -EBUSY; | ||
| 4514 | |||
| 4515 | /* | ||
| 4499 | * Block new css_tryget() by killing css refcnts. cgroup core | 4516 | * Block new css_tryget() by killing css refcnts. cgroup core |
| 4500 | * guarantees that, by the time ->css_offline() is invoked, no new | 4517 | * guarantees that, by the time ->css_offline() is invoked, no new |
| 4501 | * css reference will be given out via css_tryget(). We can't | 4518 | * css reference will be given out via css_tryget(). We can't |
