diff options
author | Tejun Heo <tj@kernel.org> | 2013-08-13 20:22:50 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2013-08-13 20:22:50 -0400 |
commit | f20104de55a212a9742d8df1807f1f29dc95b748 (patch) | |
tree | c7686dae4a73615ba67dc6fd4cfe9e7b89cf9708 /kernel/cgroup.c | |
parent | 223dbc38d2a8745a93749dc75ed909e274ce075d (diff) |
cgroup: replace cgroup->css_kill_cnt with ->nr_css
Currently, css (cgroup_subsys_state) lifetime is tied to that of the
associated cgroup. With the planned unified hierarchy, css's will be
dynamically created and destroyed within the lifetime of a cgroup. To
enable such usages, css's will be individually RCU protected instead
of being tied to the cgroup.
cgroup->css_kill_cnt is used during cgroup destruction to wait for css
reference count disable; however, this model doesn't work once css's
lifetimes are managed separately from cgroup's. This patch replaces
it with cgroup->nr_css which is an cgroup_mutex protected integer
counting the number of attached css's. The count is incremented from
online_css() and decremented after refcnt kill is confirmed. If the
count reaches zero and the cgroup is marked dead, the second stage of
cgroup destruction is kicked off. If a cgroup doesn't have any css
attached at the time of rmdir, cgroup_destroy_locked() now invokes the
second stage directly as no css kill confirmation would happen.
cgroup_offline_fn() - the second step of cgroup destruction - is
renamed to cgroup_destroy_css_killed() and now expects to be called
with cgroup_mutex held.
While this patch changes how css destruction is punted to work items,
it shouldn't change any visible behavior.
Signed-off-by: Tejun Heo <tj@kernel.org>
Acked-by: Li Zefan <lizefan@huawei.com>
Diffstat (limited to 'kernel/cgroup.c')
-rw-r--r-- | kernel/cgroup.c | 52 |
1 files changed, 28 insertions, 24 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 398ffbbee32f..174f4c3d72ef 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
@@ -218,7 +218,7 @@ static int need_forkexit_callback __read_mostly; | |||
218 | 218 | ||
219 | static struct cftype cgroup_base_files[]; | 219 | static struct cftype cgroup_base_files[]; |
220 | 220 | ||
221 | static void cgroup_offline_fn(struct work_struct *work); | 221 | static void cgroup_destroy_css_killed(struct cgroup *cgrp); |
222 | static int cgroup_destroy_locked(struct cgroup *cgrp); | 222 | static int cgroup_destroy_locked(struct cgroup *cgrp); |
223 | static int cgroup_addrm_files(struct cgroup *cgrp, struct cftype cfts[], | 223 | static int cgroup_addrm_files(struct cgroup *cgrp, struct cftype cfts[], |
224 | bool is_add); | 224 | bool is_add); |
@@ -4335,6 +4335,7 @@ static int online_css(struct cgroup_subsys_state *css) | |||
4335 | ret = ss->css_online(css); | 4335 | ret = ss->css_online(css); |
4336 | if (!ret) { | 4336 | if (!ret) { |
4337 | css->flags |= CSS_ONLINE; | 4337 | css->flags |= CSS_ONLINE; |
4338 | css->cgroup->nr_css++; | ||
4338 | rcu_assign_pointer(css->cgroup->subsys[ss->subsys_id], css); | 4339 | rcu_assign_pointer(css->cgroup->subsys[ss->subsys_id], css); |
4339 | } | 4340 | } |
4340 | return ret; | 4341 | return ret; |
@@ -4545,16 +4546,6 @@ static int cgroup_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) | |||
4545 | return cgroup_create(c_parent, dentry, mode | S_IFDIR); | 4546 | return cgroup_create(c_parent, dentry, mode | S_IFDIR); |
4546 | } | 4547 | } |
4547 | 4548 | ||
4548 | static void cgroup_css_killed(struct cgroup *cgrp) | ||
4549 | { | ||
4550 | if (!atomic_dec_and_test(&cgrp->css_kill_cnt)) | ||
4551 | return; | ||
4552 | |||
4553 | /* percpu ref's of all css's are killed, kick off the next step */ | ||
4554 | INIT_WORK(&cgrp->destroy_work, cgroup_offline_fn); | ||
4555 | schedule_work(&cgrp->destroy_work); | ||
4556 | } | ||
4557 | |||
4558 | /* | 4549 | /* |
4559 | * This is called when the refcnt of a css is confirmed to be killed. | 4550 | * This is called when the refcnt of a css is confirmed to be killed. |
4560 | * css_tryget() is now guaranteed to fail. | 4551 | * css_tryget() is now guaranteed to fail. |
@@ -4565,7 +4556,17 @@ static void css_killed_work_fn(struct work_struct *work) | |||
4565 | container_of(work, struct cgroup_subsys_state, destroy_work); | 4556 | container_of(work, struct cgroup_subsys_state, destroy_work); |
4566 | struct cgroup *cgrp = css->cgroup; | 4557 | struct cgroup *cgrp = css->cgroup; |
4567 | 4558 | ||
4568 | cgroup_css_killed(cgrp); | 4559 | mutex_lock(&cgroup_mutex); |
4560 | |||
4561 | /* | ||
4562 | * If @cgrp is marked dead, it's waiting for refs of all css's to | ||
4563 | * be disabled before proceeding to the second phase of cgroup | ||
4564 | * destruction. If we are the last one, kick it off. | ||
4565 | */ | ||
4566 | if (!--cgrp->nr_css && cgroup_is_dead(cgrp)) | ||
4567 | cgroup_destroy_css_killed(cgrp); | ||
4568 | |||
4569 | mutex_unlock(&cgroup_mutex); | ||
4569 | } | 4570 | } |
4570 | 4571 | ||
4571 | /* css kill confirmation processing requires process context, bounce */ | 4572 | /* css kill confirmation processing requires process context, bounce */ |
@@ -4634,11 +4635,10 @@ static int cgroup_destroy_locked(struct cgroup *cgrp) | |||
4634 | * Use percpu_ref_kill_and_confirm() to get notifications as each | 4635 | * Use percpu_ref_kill_and_confirm() to get notifications as each |
4635 | * css is confirmed to be seen as killed on all CPUs. The | 4636 | * css is confirmed to be seen as killed on all CPUs. The |
4636 | * notification callback keeps track of the number of css's to be | 4637 | * notification callback keeps track of the number of css's to be |
4637 | * killed and schedules cgroup_offline_fn() to perform the rest of | 4638 | * killed and invokes cgroup_destroy_css_killed() to perform the |
4638 | * destruction once the percpu refs of all css's are confirmed to | 4639 | * rest of destruction once the percpu refs of all css's are |
4639 | * be killed. | 4640 | * confirmed to be killed. |
4640 | */ | 4641 | */ |
4641 | atomic_set(&cgrp->css_kill_cnt, 1); | ||
4642 | for_each_root_subsys(cgrp->root, ss) { | 4642 | for_each_root_subsys(cgrp->root, ss) { |
4643 | struct cgroup_subsys_state *css = cgroup_css(cgrp, ss->subsys_id); | 4643 | struct cgroup_subsys_state *css = cgroup_css(cgrp, ss->subsys_id); |
4644 | 4644 | ||
@@ -4648,10 +4648,8 @@ static int cgroup_destroy_locked(struct cgroup *cgrp) | |||
4648 | */ | 4648 | */ |
4649 | percpu_ref_get(&css->refcnt); | 4649 | percpu_ref_get(&css->refcnt); |
4650 | 4650 | ||
4651 | atomic_inc(&cgrp->css_kill_cnt); | ||
4652 | percpu_ref_kill_and_confirm(&css->refcnt, css_killed_ref_fn); | 4651 | percpu_ref_kill_and_confirm(&css->refcnt, css_killed_ref_fn); |
4653 | } | 4652 | } |
4654 | cgroup_css_killed(cgrp); | ||
4655 | 4653 | ||
4656 | /* | 4654 | /* |
4657 | * Mark @cgrp dead. This prevents further task migration and child | 4655 | * Mark @cgrp dead. This prevents further task migration and child |
@@ -4669,6 +4667,15 @@ static int cgroup_destroy_locked(struct cgroup *cgrp) | |||
4669 | raw_spin_unlock(&release_list_lock); | 4667 | raw_spin_unlock(&release_list_lock); |
4670 | 4668 | ||
4671 | /* | 4669 | /* |
4670 | * If @cgrp has css's attached, the second stage of cgroup | ||
4671 | * destruction is kicked off from css_killed_work_fn() after the | ||
4672 | * refs of all attached css's are killed. If @cgrp doesn't have | ||
4673 | * any css, we kick it off here. | ||
4674 | */ | ||
4675 | if (!cgrp->nr_css) | ||
4676 | cgroup_destroy_css_killed(cgrp); | ||
4677 | |||
4678 | /* | ||
4672 | * Clear and remove @cgrp directory. The removal puts the base ref | 4679 | * Clear and remove @cgrp directory. The removal puts the base ref |
4673 | * but we aren't quite done with @cgrp yet, so hold onto it. | 4680 | * but we aren't quite done with @cgrp yet, so hold onto it. |
4674 | */ | 4681 | */ |
@@ -4693,7 +4700,7 @@ static int cgroup_destroy_locked(struct cgroup *cgrp) | |||
4693 | }; | 4700 | }; |
4694 | 4701 | ||
4695 | /** | 4702 | /** |
4696 | * cgroup_offline_fn - the second step of cgroup destruction | 4703 | * cgroup_destroy_css_killed - the second step of cgroup destruction |
4697 | * @work: cgroup->destroy_free_work | 4704 | * @work: cgroup->destroy_free_work |
4698 | * | 4705 | * |
4699 | * This function is invoked from a work item for a cgroup which is being | 4706 | * This function is invoked from a work item for a cgroup which is being |
@@ -4702,14 +4709,13 @@ static int cgroup_destroy_locked(struct cgroup *cgrp) | |||
4702 | * is the second step of destruction described in the comment above | 4709 | * is the second step of destruction described in the comment above |
4703 | * cgroup_destroy_locked(). | 4710 | * cgroup_destroy_locked(). |
4704 | */ | 4711 | */ |
4705 | static void cgroup_offline_fn(struct work_struct *work) | 4712 | static void cgroup_destroy_css_killed(struct cgroup *cgrp) |
4706 | { | 4713 | { |
4707 | struct cgroup *cgrp = container_of(work, struct cgroup, destroy_work); | ||
4708 | struct cgroup *parent = cgrp->parent; | 4714 | struct cgroup *parent = cgrp->parent; |
4709 | struct dentry *d = cgrp->dentry; | 4715 | struct dentry *d = cgrp->dentry; |
4710 | struct cgroup_subsys *ss; | 4716 | struct cgroup_subsys *ss; |
4711 | 4717 | ||
4712 | mutex_lock(&cgroup_mutex); | 4718 | lockdep_assert_held(&cgroup_mutex); |
4713 | 4719 | ||
4714 | /* | 4720 | /* |
4715 | * css_tryget() is guaranteed to fail now. Tell subsystems to | 4721 | * css_tryget() is guaranteed to fail now. Tell subsystems to |
@@ -4743,8 +4749,6 @@ static void cgroup_offline_fn(struct work_struct *work) | |||
4743 | 4749 | ||
4744 | set_bit(CGRP_RELEASABLE, &parent->flags); | 4750 | set_bit(CGRP_RELEASABLE, &parent->flags); |
4745 | check_for_release(parent); | 4751 | check_for_release(parent); |
4746 | |||
4747 | mutex_unlock(&cgroup_mutex); | ||
4748 | } | 4752 | } |
4749 | 4753 | ||
4750 | static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry) | 4754 | static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry) |