diff options
Diffstat (limited to 'kernel/cgroup.c')
-rw-r--r-- | kernel/cgroup.c | 32 |
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) | |||
795 | static int cgroup_call_pre_destroy(struct cgroup *cgrp) | 795 | static 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 | |||
819 | out: | ||
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 | } |