diff options
author | Li Zefan <lizefan@huawei.com> | 2013-06-18 06:41:10 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-07-21 21:21:25 -0400 |
commit | 83d0eb79752482bb888fb6d86ceed8971272f8b4 (patch) | |
tree | 626f556740e4aa16fb6bba39b28977b61a728cda /kernel/cgroup.c | |
parent | 5eb2698932989f855e3427b0860771611f831a69 (diff) |
cgroup: fix umount vs cgroup_event_remove() race
commit 1c8158eeae0f37d0eee9f1fbe68080df6a408df2 upstream.
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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'kernel/cgroup.c')
-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 a7c9e6ddb979..c6e77ef2a0a6 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
@@ -3727,6 +3727,23 @@ static int cgroup_write_notify_on_release(struct cgroup *cgrp, | |||
3727 | } | 3727 | } |
3728 | 3728 | ||
3729 | /* | 3729 | /* |
3730 | * When dput() is called asynchronously, if umount has been done and | ||
3731 | * then deactivate_super() in cgroup_free_fn() kills the superblock, | ||
3732 | * there's a small window that vfs will see the root dentry with non-zero | ||
3733 | * refcnt and trigger BUG(). | ||
3734 | * | ||
3735 | * That's why we hold a reference before dput() and drop it right after. | ||
3736 | */ | ||
3737 | static void cgroup_dput(struct cgroup *cgrp) | ||
3738 | { | ||
3739 | struct super_block *sb = cgrp->root->sb; | ||
3740 | |||
3741 | atomic_inc(&sb->s_active); | ||
3742 | dput(cgrp->dentry); | ||
3743 | deactivate_super(sb); | ||
3744 | } | ||
3745 | |||
3746 | /* | ||
3730 | * Unregister event and free resources. | 3747 | * Unregister event and free resources. |
3731 | * | 3748 | * |
3732 | * Gets called from workqueue. | 3749 | * Gets called from workqueue. |
@@ -3746,7 +3763,7 @@ static void cgroup_event_remove(struct work_struct *work) | |||
3746 | 3763 | ||
3747 | eventfd_ctx_put(event->eventfd); | 3764 | eventfd_ctx_put(event->eventfd); |
3748 | kfree(event); | 3765 | kfree(event); |
3749 | dput(cgrp->dentry); | 3766 | cgroup_dput(cgrp); |
3750 | } | 3767 | } |
3751 | 3768 | ||
3752 | /* | 3769 | /* |
@@ -4031,12 +4048,8 @@ static void css_dput_fn(struct work_struct *work) | |||
4031 | { | 4048 | { |
4032 | struct cgroup_subsys_state *css = | 4049 | struct cgroup_subsys_state *css = |
4033 | container_of(work, struct cgroup_subsys_state, dput_work); | 4050 | container_of(work, struct cgroup_subsys_state, dput_work); |
4034 | struct dentry *dentry = css->cgroup->dentry; | ||
4035 | struct super_block *sb = dentry->d_sb; | ||
4036 | 4051 | ||
4037 | atomic_inc(&sb->s_active); | 4052 | cgroup_dput(css->cgroup); |
4038 | dput(dentry); | ||
4039 | deactivate_super(sb); | ||
4040 | } | 4053 | } |
4041 | 4054 | ||
4042 | static void init_cgroup_css(struct cgroup_subsys_state *css, | 4055 | static void init_cgroup_css(struct cgroup_subsys_state *css, |