diff options
-rw-r--r-- | kernel/cgroup.c | 61 |
1 files changed, 35 insertions, 26 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 49bfd7b0bbda..5a1ddecc3cfa 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
@@ -4379,13 +4379,8 @@ static int cgroup_destroy_locked(struct cgroup *cgrp) | |||
4379 | 4379 | ||
4380 | /* | 4380 | /* |
4381 | * Block new css_tryget() by deactivating refcnt and mark @cgrp | 4381 | * Block new css_tryget() by deactivating refcnt and mark @cgrp |
4382 | * removed. This makes future css_tryget() and child creation | 4382 | * removed. This makes future css_tryget() attempts fail which we |
4383 | * attempts fail thus maintaining the removal conditions verified | 4383 | * guarantee to ->css_offline() callbacks. |
4384 | * above. | ||
4385 | * | ||
4386 | * Note that CGRP_DEAD assertion is depended upon by | ||
4387 | * cgroup_next_sibling() to resume iteration after dropping RCU | ||
4388 | * read lock. See cgroup_next_sibling() for details. | ||
4389 | */ | 4384 | */ |
4390 | for_each_subsys(cgrp->root, ss) { | 4385 | for_each_subsys(cgrp->root, ss) { |
4391 | struct cgroup_subsys_state *css = cgrp->subsys[ss->subsys_id]; | 4386 | struct cgroup_subsys_state *css = cgrp->subsys[ss->subsys_id]; |
@@ -4393,8 +4388,41 @@ static int cgroup_destroy_locked(struct cgroup *cgrp) | |||
4393 | WARN_ON(atomic_read(&css->refcnt) < 0); | 4388 | WARN_ON(atomic_read(&css->refcnt) < 0); |
4394 | atomic_add(CSS_DEACT_BIAS, &css->refcnt); | 4389 | atomic_add(CSS_DEACT_BIAS, &css->refcnt); |
4395 | } | 4390 | } |
4391 | |||
4392 | /* | ||
4393 | * Mark @cgrp dead. This prevents further task migration and child | ||
4394 | * creation by disabling cgroup_lock_live_group(). Note that | ||
4395 | * CGRP_DEAD assertion is depended upon by cgroup_next_sibling() to | ||
4396 | * resume iteration after dropping RCU read lock. See | ||
4397 | * cgroup_next_sibling() for details. | ||
4398 | */ | ||
4396 | set_bit(CGRP_DEAD, &cgrp->flags); | 4399 | set_bit(CGRP_DEAD, &cgrp->flags); |
4397 | 4400 | ||
4401 | /* CGRP_DEAD is set, remove from ->release_list for the last time */ | ||
4402 | raw_spin_lock(&release_list_lock); | ||
4403 | if (!list_empty(&cgrp->release_list)) | ||
4404 | list_del_init(&cgrp->release_list); | ||
4405 | raw_spin_unlock(&release_list_lock); | ||
4406 | |||
4407 | /* | ||
4408 | * Remove @cgrp directory. The removal puts the base ref but we | ||
4409 | * aren't quite done with @cgrp yet, so hold onto it. | ||
4410 | */ | ||
4411 | dget(d); | ||
4412 | cgroup_d_remove_dir(d); | ||
4413 | |||
4414 | /* | ||
4415 | * Unregister events and notify userspace. | ||
4416 | * Notify userspace about cgroup removing only after rmdir of cgroup | ||
4417 | * directory to avoid race between userspace and kernelspace. | ||
4418 | */ | ||
4419 | spin_lock(&cgrp->event_list_lock); | ||
4420 | list_for_each_entry_safe(event, tmp, &cgrp->event_list, list) { | ||
4421 | list_del_init(&event->list); | ||
4422 | schedule_work(&event->remove); | ||
4423 | } | ||
4424 | spin_unlock(&cgrp->event_list_lock); | ||
4425 | |||
4398 | /* tell subsystems to initate destruction */ | 4426 | /* tell subsystems to initate destruction */ |
4399 | for_each_subsys(cgrp->root, ss) | 4427 | for_each_subsys(cgrp->root, ss) |
4400 | offline_css(ss, cgrp); | 4428 | offline_css(ss, cgrp); |
@@ -4409,34 +4437,15 @@ static int cgroup_destroy_locked(struct cgroup *cgrp) | |||
4409 | for_each_subsys(cgrp->root, ss) | 4437 | for_each_subsys(cgrp->root, ss) |
4410 | css_put(cgrp->subsys[ss->subsys_id]); | 4438 | css_put(cgrp->subsys[ss->subsys_id]); |
4411 | 4439 | ||
4412 | raw_spin_lock(&release_list_lock); | ||
4413 | if (!list_empty(&cgrp->release_list)) | ||
4414 | list_del_init(&cgrp->release_list); | ||
4415 | raw_spin_unlock(&release_list_lock); | ||
4416 | |||
4417 | /* delete this cgroup from parent->children */ | 4440 | /* delete this cgroup from parent->children */ |
4418 | list_del_rcu(&cgrp->sibling); | 4441 | list_del_rcu(&cgrp->sibling); |
4419 | list_del_init(&cgrp->allcg_node); | 4442 | list_del_init(&cgrp->allcg_node); |
4420 | 4443 | ||
4421 | dget(d); | ||
4422 | cgroup_d_remove_dir(d); | ||
4423 | dput(d); | 4444 | dput(d); |
4424 | 4445 | ||
4425 | set_bit(CGRP_RELEASABLE, &parent->flags); | 4446 | set_bit(CGRP_RELEASABLE, &parent->flags); |
4426 | check_for_release(parent); | 4447 | check_for_release(parent); |
4427 | 4448 | ||
4428 | /* | ||
4429 | * Unregister events and notify userspace. | ||
4430 | * Notify userspace about cgroup removing only after rmdir of cgroup | ||
4431 | * directory to avoid race between userspace and kernelspace. | ||
4432 | */ | ||
4433 | spin_lock(&cgrp->event_list_lock); | ||
4434 | list_for_each_entry_safe(event, tmp, &cgrp->event_list, list) { | ||
4435 | list_del_init(&event->list); | ||
4436 | schedule_work(&event->remove); | ||
4437 | } | ||
4438 | spin_unlock(&cgrp->event_list_lock); | ||
4439 | |||
4440 | return 0; | 4449 | return 0; |
4441 | } | 4450 | } |
4442 | 4451 | ||