mirror of https://gitee.com/openkylin/linux.git
cgroup: reorder the operations in cgroup_destroy_locked()
This patch reorders the operations in cgroup_destroy_locked() such that the userland visible parts happen before css offlining and removal from the ->sibling list. This will be used to make css use percpu refcnt. While at it, split out CGRP_DEAD related comment from the refcnt deactivation one and correct / clarify how different guarantees are met. While this patch changes the specific order of operations, it shouldn't cause any noticeable behavior difference. Signed-off-by: Tejun Heo <tj@kernel.org> Acked-by: Li Zefan <lizefan@huawei.com>
This commit is contained in:
parent
6f3d828f0f
commit
455050d23e
|
@ -4379,13 +4379,8 @@ static int cgroup_destroy_locked(struct cgroup *cgrp)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Block new css_tryget() by deactivating refcnt and mark @cgrp
|
* Block new css_tryget() by deactivating refcnt and mark @cgrp
|
||||||
* removed. This makes future css_tryget() and child creation
|
* removed. This makes future css_tryget() attempts fail which we
|
||||||
* attempts fail thus maintaining the removal conditions verified
|
* guarantee to ->css_offline() callbacks.
|
||||||
* above.
|
|
||||||
*
|
|
||||||
* Note that CGRP_DEAD assertion is depended upon by
|
|
||||||
* cgroup_next_sibling() to resume iteration after dropping RCU
|
|
||||||
* read lock. See cgroup_next_sibling() for details.
|
|
||||||
*/
|
*/
|
||||||
for_each_subsys(cgrp->root, ss) {
|
for_each_subsys(cgrp->root, ss) {
|
||||||
struct cgroup_subsys_state *css = cgrp->subsys[ss->subsys_id];
|
struct cgroup_subsys_state *css = cgrp->subsys[ss->subsys_id];
|
||||||
|
@ -4393,8 +4388,41 @@ static int cgroup_destroy_locked(struct cgroup *cgrp)
|
||||||
WARN_ON(atomic_read(&css->refcnt) < 0);
|
WARN_ON(atomic_read(&css->refcnt) < 0);
|
||||||
atomic_add(CSS_DEACT_BIAS, &css->refcnt);
|
atomic_add(CSS_DEACT_BIAS, &css->refcnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mark @cgrp dead. This prevents further task migration and child
|
||||||
|
* creation by disabling cgroup_lock_live_group(). Note that
|
||||||
|
* CGRP_DEAD assertion is depended upon by cgroup_next_sibling() to
|
||||||
|
* resume iteration after dropping RCU read lock. See
|
||||||
|
* cgroup_next_sibling() for details.
|
||||||
|
*/
|
||||||
set_bit(CGRP_DEAD, &cgrp->flags);
|
set_bit(CGRP_DEAD, &cgrp->flags);
|
||||||
|
|
||||||
|
/* CGRP_DEAD is set, remove from ->release_list for the last time */
|
||||||
|
raw_spin_lock(&release_list_lock);
|
||||||
|
if (!list_empty(&cgrp->release_list))
|
||||||
|
list_del_init(&cgrp->release_list);
|
||||||
|
raw_spin_unlock(&release_list_lock);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remove @cgrp directory. The removal puts the base ref but we
|
||||||
|
* aren't quite done with @cgrp yet, so hold onto it.
|
||||||
|
*/
|
||||||
|
dget(d);
|
||||||
|
cgroup_d_remove_dir(d);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unregister events and notify userspace.
|
||||||
|
* Notify userspace about cgroup removing only after rmdir of cgroup
|
||||||
|
* directory to avoid race between userspace and kernelspace.
|
||||||
|
*/
|
||||||
|
spin_lock(&cgrp->event_list_lock);
|
||||||
|
list_for_each_entry_safe(event, tmp, &cgrp->event_list, list) {
|
||||||
|
list_del_init(&event->list);
|
||||||
|
schedule_work(&event->remove);
|
||||||
|
}
|
||||||
|
spin_unlock(&cgrp->event_list_lock);
|
||||||
|
|
||||||
/* tell subsystems to initate destruction */
|
/* tell subsystems to initate destruction */
|
||||||
for_each_subsys(cgrp->root, ss)
|
for_each_subsys(cgrp->root, ss)
|
||||||
offline_css(ss, cgrp);
|
offline_css(ss, cgrp);
|
||||||
|
@ -4409,34 +4437,15 @@ static int cgroup_destroy_locked(struct cgroup *cgrp)
|
||||||
for_each_subsys(cgrp->root, ss)
|
for_each_subsys(cgrp->root, ss)
|
||||||
css_put(cgrp->subsys[ss->subsys_id]);
|
css_put(cgrp->subsys[ss->subsys_id]);
|
||||||
|
|
||||||
raw_spin_lock(&release_list_lock);
|
|
||||||
if (!list_empty(&cgrp->release_list))
|
|
||||||
list_del_init(&cgrp->release_list);
|
|
||||||
raw_spin_unlock(&release_list_lock);
|
|
||||||
|
|
||||||
/* delete this cgroup from parent->children */
|
/* delete this cgroup from parent->children */
|
||||||
list_del_rcu(&cgrp->sibling);
|
list_del_rcu(&cgrp->sibling);
|
||||||
list_del_init(&cgrp->allcg_node);
|
list_del_init(&cgrp->allcg_node);
|
||||||
|
|
||||||
dget(d);
|
|
||||||
cgroup_d_remove_dir(d);
|
|
||||||
dput(d);
|
dput(d);
|
||||||
|
|
||||||
set_bit(CGRP_RELEASABLE, &parent->flags);
|
set_bit(CGRP_RELEASABLE, &parent->flags);
|
||||||
check_for_release(parent);
|
check_for_release(parent);
|
||||||
|
|
||||||
/*
|
|
||||||
* Unregister events and notify userspace.
|
|
||||||
* Notify userspace about cgroup removing only after rmdir of cgroup
|
|
||||||
* directory to avoid race between userspace and kernelspace.
|
|
||||||
*/
|
|
||||||
spin_lock(&cgrp->event_list_lock);
|
|
||||||
list_for_each_entry_safe(event, tmp, &cgrp->event_list, list) {
|
|
||||||
list_del_init(&event->list);
|
|
||||||
schedule_work(&event->remove);
|
|
||||||
}
|
|
||||||
spin_unlock(&cgrp->event_list_lock);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue