aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/cgroup.c
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2013-06-13 22:27:42 -0400
committerTejun Heo <tj@kernel.org>2013-06-13 22:27:42 -0400
commitea15f8ccdb430af1e8bc9b4e19a230eb4c356777 (patch)
treee75aa3f5ddac2a7092c0f16361d72f9b25232832 /kernel/cgroup.c
parent455050d23e1bfc47ca98e943ad5b2f3a9bbe45fb (diff)
cgroup: split cgroup destruction into two steps
Split cgroup_destroy_locked() into two steps and put the latter half into cgroup_offline_fn() which is executed from a work item. The latter half is responsible for offlining the css's, removing the cgroup from internal lists, and propagating release notification to the parent. The separation is to allow using percpu refcnt for css. Note that this allows for other cgroup operations to happen between the first and second halves of destruction, including creating a new cgroup with the same name. As the target cgroup is marked DEAD in the first half and cgroup internals don't care about the names of cgroups, this should be fine. A comment explaining this will be added by the next patch which implements the actual percpu refcnting. As RCU freeing is guaranteed to happen after the second step of destruction, we can use the same work item for both. This patch renames cgroup->free_work to ->destroy_work and uses it for both purposes. INIT_WORK() is now performed right before queueing the work item. 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.c38
1 files changed, 27 insertions, 11 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 5a1ddecc3cfa..df6814706cca 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -208,6 +208,7 @@ static struct cgroup_name root_cgroup_name = { .name = "/" };
208 */ 208 */
209static int need_forkexit_callback __read_mostly; 209static int need_forkexit_callback __read_mostly;
210 210
211static void cgroup_offline_fn(struct work_struct *work);
211static int cgroup_destroy_locked(struct cgroup *cgrp); 212static int cgroup_destroy_locked(struct cgroup *cgrp);
212static int cgroup_addrm_files(struct cgroup *cgrp, struct cgroup_subsys *subsys, 213static int cgroup_addrm_files(struct cgroup *cgrp, struct cgroup_subsys *subsys,
213 struct cftype cfts[], bool is_add); 214 struct cftype cfts[], bool is_add);
@@ -830,7 +831,7 @@ static struct cgroup_name *cgroup_alloc_name(struct dentry *dentry)
830 831
831static void cgroup_free_fn(struct work_struct *work) 832static void cgroup_free_fn(struct work_struct *work)
832{ 833{
833 struct cgroup *cgrp = container_of(work, struct cgroup, free_work); 834 struct cgroup *cgrp = container_of(work, struct cgroup, destroy_work);
834 struct cgroup_subsys *ss; 835 struct cgroup_subsys *ss;
835 836
836 mutex_lock(&cgroup_mutex); 837 mutex_lock(&cgroup_mutex);
@@ -875,7 +876,8 @@ static void cgroup_free_rcu(struct rcu_head *head)
875{ 876{
876 struct cgroup *cgrp = container_of(head, struct cgroup, rcu_head); 877 struct cgroup *cgrp = container_of(head, struct cgroup, rcu_head);
877 878
878 schedule_work(&cgrp->free_work); 879 INIT_WORK(&cgrp->destroy_work, cgroup_free_fn);
880 schedule_work(&cgrp->destroy_work);
879} 881}
880 882
881static void cgroup_diput(struct dentry *dentry, struct inode *inode) 883static void cgroup_diput(struct dentry *dentry, struct inode *inode)
@@ -1407,7 +1409,6 @@ static void init_cgroup_housekeeping(struct cgroup *cgrp)
1407 INIT_LIST_HEAD(&cgrp->allcg_node); 1409 INIT_LIST_HEAD(&cgrp->allcg_node);
1408 INIT_LIST_HEAD(&cgrp->release_list); 1410 INIT_LIST_HEAD(&cgrp->release_list);
1409 INIT_LIST_HEAD(&cgrp->pidlists); 1411 INIT_LIST_HEAD(&cgrp->pidlists);
1410 INIT_WORK(&cgrp->free_work, cgroup_free_fn);
1411 mutex_init(&cgrp->pidlist_mutex); 1412 mutex_init(&cgrp->pidlist_mutex);
1412 INIT_LIST_HEAD(&cgrp->event_list); 1413 INIT_LIST_HEAD(&cgrp->event_list);
1413 spin_lock_init(&cgrp->event_list_lock); 1414 spin_lock_init(&cgrp->event_list_lock);
@@ -2991,12 +2992,13 @@ struct cgroup *cgroup_next_sibling(struct cgroup *pos)
2991 /* 2992 /*
2992 * @pos could already have been removed. Once a cgroup is removed, 2993 * @pos could already have been removed. Once a cgroup is removed,
2993 * its ->sibling.next is no longer updated when its next sibling 2994 * its ->sibling.next is no longer updated when its next sibling
2994 * changes. As CGRP_DEAD is set on removal which is fully 2995 * changes. As CGRP_DEAD assertion is serialized and happens
2995 * serialized, if we see it unasserted, it's guaranteed that the 2996 * before the cgroup is taken off the ->sibling list, if we see it
2996 * next sibling hasn't finished its grace period even if it's 2997 * unasserted, it's guaranteed that the next sibling hasn't
2997 * already removed, and thus safe to dereference from this RCU 2998 * finished its grace period even if it's already removed, and thus
2998 * critical section. If ->sibling.next is inaccessible, 2999 * safe to dereference from this RCU critical section. If
2999 * cgroup_is_dead() is guaranteed to be visible as %true here. 3000 * ->sibling.next is inaccessible, cgroup_is_dead() is guaranteed
3001 * to be visible as %true here.
3000 */ 3002 */
3001 if (likely(!cgroup_is_dead(pos))) { 3003 if (likely(!cgroup_is_dead(pos))) {
3002 next = list_entry_rcu(pos->sibling.next, struct cgroup, sibling); 3004 next = list_entry_rcu(pos->sibling.next, struct cgroup, sibling);
@@ -4359,7 +4361,6 @@ static int cgroup_destroy_locked(struct cgroup *cgrp)
4359 __releases(&cgroup_mutex) __acquires(&cgroup_mutex) 4361 __releases(&cgroup_mutex) __acquires(&cgroup_mutex)
4360{ 4362{
4361 struct dentry *d = cgrp->dentry; 4363 struct dentry *d = cgrp->dentry;
4362 struct cgroup *parent = cgrp->parent;
4363 struct cgroup_event *event, *tmp; 4364 struct cgroup_event *event, *tmp;
4364 struct cgroup_subsys *ss; 4365 struct cgroup_subsys *ss;
4365 bool empty; 4366 bool empty;
@@ -4423,6 +4424,21 @@ static int cgroup_destroy_locked(struct cgroup *cgrp)
4423 } 4424 }
4424 spin_unlock(&cgrp->event_list_lock); 4425 spin_unlock(&cgrp->event_list_lock);
4425 4426
4427 INIT_WORK(&cgrp->destroy_work, cgroup_offline_fn);
4428 schedule_work(&cgrp->destroy_work);
4429
4430 return 0;
4431};
4432
4433static void cgroup_offline_fn(struct work_struct *work)
4434{
4435 struct cgroup *cgrp = container_of(work, struct cgroup, destroy_work);
4436 struct cgroup *parent = cgrp->parent;
4437 struct dentry *d = cgrp->dentry;
4438 struct cgroup_subsys *ss;
4439
4440 mutex_lock(&cgroup_mutex);
4441
4426 /* tell subsystems to initate destruction */ 4442 /* tell subsystems to initate destruction */
4427 for_each_subsys(cgrp->root, ss) 4443 for_each_subsys(cgrp->root, ss)
4428 offline_css(ss, cgrp); 4444 offline_css(ss, cgrp);
@@ -4446,7 +4462,7 @@ static int cgroup_destroy_locked(struct cgroup *cgrp)
4446 set_bit(CGRP_RELEASABLE, &parent->flags); 4462 set_bit(CGRP_RELEASABLE, &parent->flags);
4447 check_for_release(parent); 4463 check_for_release(parent);
4448 4464
4449 return 0; 4465 mutex_unlock(&cgroup_mutex);
4450} 4466}
4451 4467
4452static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry) 4468static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry)