aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorKirill A. Shutemov <kirill@shutemov.name>2010-03-10 18:22:34 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2010-03-12 18:52:37 -0500
commit4ab78683c17d739c2a2077141dcf81a02b7fb57e (patch)
tree5884c1b7e20d1975d668d07dbf43202d737ec7bf /kernel
parentdaaf1e68874c078a15ae6ae827751839c4d81739 (diff)
cgroups: fix race between userspace and kernelspace
Notify userspace about cgroup removing only after rmdir of cgroup directory to avoid race between userspace and kernelspace. eventfd are used to notify about two types of event: - control file-specific, like crossing memory threshold; - cgroup removing. To understand what really happen, userspace can check if the cgroup still exists. To avoid race beetween userspace and kernelspace we have to notify userspace about cgroup removing only after rmdir of cgroup directory. Signed-off-by: Kirill A. Shutemov <kirill@shutemov.name> Reviewed-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Cc: Paul Menage <menage@google.com> Acked-by: Li Zefan <lizf@cn.fujitsu.com> Cc: Balbir Singh <balbir@linux.vnet.ibm.com> Cc: Pavel Emelyanov <xemul@openvz.org> Cc: Dan Malek <dan@embeddedalley.com> Cc: Daisuke Nishimura <nishimura@mxp.nes.nec.co.jp> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel')
-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}