aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/cgroup.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/cgroup.c')
-rw-r--r--kernel/cgroup.c32
1 files changed, 17 insertions, 15 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index ea94984a3895..87441fc75663 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -795,28 +795,15 @@ static struct inode *cgroup_new_inode(mode_t mode, struct super_block *sb)
795static int cgroup_call_pre_destroy(struct cgroup *cgrp) 795static int cgroup_call_pre_destroy(struct cgroup *cgrp)
796{ 796{
797 struct cgroup_subsys *ss; 797 struct cgroup_subsys *ss;
798 struct cgroup_event *event, *tmp;
799 int ret = 0; 798 int ret = 0;
800 799
801 for_each_subsys(cgrp->root, ss) 800 for_each_subsys(cgrp->root, ss)
802 if (ss->pre_destroy) { 801 if (ss->pre_destroy) {
803 ret = ss->pre_destroy(ss, cgrp); 802 ret = ss->pre_destroy(ss, cgrp);
804 if (ret) 803 if (ret)
805 goto out; 804 break;
806 } 805 }
807 806
808 /*
809 * Unregister events and notify userspace.
810 */
811 spin_lock(&cgrp->event_list_lock);
812 list_for_each_entry_safe(event, tmp, &cgrp->event_list, list) {
813 list_del(&event->list);
814 eventfd_signal(event->eventfd, 1);
815 schedule_work(&event->remove);
816 }
817 spin_unlock(&cgrp->event_list_lock);
818
819out:
820 return ret; 807 return ret;
821} 808}
822 809
@@ -3006,7 +2993,6 @@ static void cgroup_event_remove(struct work_struct *work)
3006 event->cft->unregister_event(cgrp, event->cft, event->eventfd); 2993 event->cft->unregister_event(cgrp, event->cft, event->eventfd);
3007 2994
3008 eventfd_ctx_put(event->eventfd); 2995 eventfd_ctx_put(event->eventfd);
3009 remove_wait_queue(event->wqh, &event->wait);
3010 kfree(event); 2996 kfree(event);
3011} 2997}
3012 2998
@@ -3024,6 +3010,7 @@ static int cgroup_event_wake(wait_queue_t *wait, unsigned mode,
3024 unsigned long flags = (unsigned long)key; 3010 unsigned long flags = (unsigned long)key;
3025 3011
3026 if (flags & POLLHUP) { 3012 if (flags & POLLHUP) {
3013 remove_wait_queue_locked(event->wqh, &event->wait);
3027 spin_lock(&cgrp->event_list_lock); 3014 spin_lock(&cgrp->event_list_lock);
3028 list_del(&event->list); 3015 list_del(&event->list);
3029 spin_unlock(&cgrp->event_list_lock); 3016 spin_unlock(&cgrp->event_list_lock);
@@ -3472,6 +3459,7 @@ static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry)
3472 struct dentry *d; 3459 struct dentry *d;
3473 struct cgroup *parent; 3460 struct cgroup *parent;
3474 DEFINE_WAIT(wait); 3461 DEFINE_WAIT(wait);
3462 struct cgroup_event *event, *tmp;
3475 int ret; 3463 int ret;
3476 3464
3477 /* the vfs holds both inode->i_mutex already */ 3465 /* the vfs holds both inode->i_mutex already */
@@ -3555,6 +3543,20 @@ again:
3555 set_bit(CGRP_RELEASABLE, &parent->flags); 3543 set_bit(CGRP_RELEASABLE, &parent->flags);
3556 check_for_release(parent); 3544 check_for_release(parent);
3557 3545
3546 /*
3547 * Unregister events and notify userspace.
3548 * Notify userspace about cgroup removing only after rmdir of cgroup
3549 * directory to avoid race between userspace and kernelspace
3550 */
3551 spin_lock(&cgrp->event_list_lock);
3552 list_for_each_entry_safe(event, tmp, &cgrp->event_list, list) {
3553 list_del(&event->list);
3554 remove_wait_queue(event->wqh, &event->wait);
3555 eventfd_signal(event->eventfd, 1);
3556 schedule_work(&event->remove);
3557 }
3558 spin_unlock(&cgrp->event_list_lock);
3559
3558 mutex_unlock(&cgroup_mutex); 3560 mutex_unlock(&cgroup_mutex);
3559 return 0; 3561 return 0;
3560} 3562}