diff options
author | Li Zefan <lizefan@huawei.com> | 2013-06-18 06:41:10 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2013-06-18 12:04:30 -0400 |
commit | 1c8158eeae0f37d0eee9f1fbe68080df6a408df2 (patch) | |
tree | 9cf764df3ac232b0816d886c6d0ce85cd7967f62 /kernel | |
parent | 084457f284abf6789d90509ee11dae383842b23b (diff) |
cgroup: fix umount vs cgroup_event_remove() race
commit 5db9a4d99b0157a513944e9a44d29c9cec2e91dc
Author: Tejun Heo <tj@kernel.org>
Date: Sat Jul 7 16:08:18 2012 -0700
cgroup: fix cgroup hierarchy umount race
This commit fixed a race caused by the dput() in css_dput_fn(), but
the dput() in cgroup_event_remove() can also lead to the same BUG().
Signed-off-by: Li Zefan <lizefan@huawei.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: stable@vger.kernel.org
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/cgroup.c | 25 |
1 files changed, 19 insertions, 6 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 0224f6b3103e..7db2940bfc77 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
@@ -3822,6 +3822,23 @@ static int cgroup_write_notify_on_release(struct cgroup *cgrp, | |||
3822 | } | 3822 | } |
3823 | 3823 | ||
3824 | /* | 3824 | /* |
3825 | * When dput() is called asynchronously, if umount has been done and | ||
3826 | * then deactivate_super() in cgroup_free_fn() kills the superblock, | ||
3827 | * there's a small window that vfs will see the root dentry with non-zero | ||
3828 | * refcnt and trigger BUG(). | ||
3829 | * | ||
3830 | * That's why we hold a reference before dput() and drop it right after. | ||
3831 | */ | ||
3832 | static void cgroup_dput(struct cgroup *cgrp) | ||
3833 | { | ||
3834 | struct super_block *sb = cgrp->root->sb; | ||
3835 | |||
3836 | atomic_inc(&sb->s_active); | ||
3837 | dput(cgrp->dentry); | ||
3838 | deactivate_super(sb); | ||
3839 | } | ||
3840 | |||
3841 | /* | ||
3825 | * Unregister event and free resources. | 3842 | * Unregister event and free resources. |
3826 | * | 3843 | * |
3827 | * Gets called from workqueue. | 3844 | * Gets called from workqueue. |
@@ -3841,7 +3858,7 @@ static void cgroup_event_remove(struct work_struct *work) | |||
3841 | 3858 | ||
3842 | eventfd_ctx_put(event->eventfd); | 3859 | eventfd_ctx_put(event->eventfd); |
3843 | kfree(event); | 3860 | kfree(event); |
3844 | dput(cgrp->dentry); | 3861 | cgroup_dput(cgrp); |
3845 | } | 3862 | } |
3846 | 3863 | ||
3847 | /* | 3864 | /* |
@@ -4129,12 +4146,8 @@ static void css_dput_fn(struct work_struct *work) | |||
4129 | { | 4146 | { |
4130 | struct cgroup_subsys_state *css = | 4147 | struct cgroup_subsys_state *css = |
4131 | container_of(work, struct cgroup_subsys_state, dput_work); | 4148 | container_of(work, struct cgroup_subsys_state, dput_work); |
4132 | struct dentry *dentry = css->cgroup->dentry; | ||
4133 | struct super_block *sb = dentry->d_sb; | ||
4134 | 4149 | ||
4135 | atomic_inc(&sb->s_active); | 4150 | cgroup_dput(css->cgroup); |
4136 | dput(dentry); | ||
4137 | deactivate_super(sb); | ||
4138 | } | 4151 | } |
4139 | 4152 | ||
4140 | static void css_release(struct percpu_ref *ref) | 4153 | static void css_release(struct percpu_ref *ref) |