diff options
-rw-r--r-- | include/linux/cgroup.h | 2 | ||||
-rw-r--r-- | kernel/cgroup.c | 38 |
2 files changed, 28 insertions, 12 deletions
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index 81bfd0268e93..e345d8b90046 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h | |||
@@ -233,7 +233,7 @@ struct cgroup { | |||
233 | 233 | ||
234 | /* For RCU-protected deletion */ | 234 | /* For RCU-protected deletion */ |
235 | struct rcu_head rcu_head; | 235 | struct rcu_head rcu_head; |
236 | struct work_struct free_work; | 236 | struct work_struct destroy_work; |
237 | 237 | ||
238 | /* List of events which userspace want to receive */ | 238 | /* List of events which userspace want to receive */ |
239 | struct list_head event_list; | 239 | struct list_head event_list; |
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 | */ |
209 | static int need_forkexit_callback __read_mostly; | 209 | static int need_forkexit_callback __read_mostly; |
210 | 210 | ||
211 | static void cgroup_offline_fn(struct work_struct *work); | ||
211 | static int cgroup_destroy_locked(struct cgroup *cgrp); | 212 | static int cgroup_destroy_locked(struct cgroup *cgrp); |
212 | static int cgroup_addrm_files(struct cgroup *cgrp, struct cgroup_subsys *subsys, | 213 | static 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 | ||
831 | static void cgroup_free_fn(struct work_struct *work) | 832 | static 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 | ||
881 | static void cgroup_diput(struct dentry *dentry, struct inode *inode) | 883 | static 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 | |||
4433 | static 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 | ||
4452 | static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry) | 4468 | static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry) |