diff options
author | Li Zefan <lizefan@huawei.com> | 2013-06-18 18:41:10 +0800 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2013-06-18 09:04:30 -0700 |
commit | 1c8158eeae0f37d0eee9f1fbe68080df6a408df2 (patch) | |
tree | 9cf764df3ac232b0816d886c6d0ce85cd7967f62 /kernel | |
parent | 084457f284abf6789d90509ee11dae383842b23b (diff) | |
download | linux-1c8158eeae0f37d0eee9f1fbe68080df6a408df2.tar.gz linux-1c8158eeae0f37d0eee9f1fbe68080df6a408df2.tar.bz2 linux-1c8158eeae0f37d0eee9f1fbe68080df6a408df2.zip |
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, } /* + * When dput() is called asynchronously, if umount has been done and + * then deactivate_super() in cgroup_free_fn() kills the superblock, + * there's a small window that vfs will see the root dentry with non-zero + * refcnt and trigger BUG(). + * + * That's why we hold a reference before dput() and drop it right after. + */ +static void cgroup_dput(struct cgroup *cgrp) +{ + struct super_block *sb = cgrp->root->sb; + + atomic_inc(&sb->s_active); + dput(cgrp->dentry); + deactivate_super(sb); +} + +/* * Unregister event and free resources. * * Gets called from workqueue. @@ -3841,7 +3858,7 @@ static void cgroup_event_remove(struct work_struct *work) eventfd_ctx_put(event->eventfd); kfree(event); - dput(cgrp->dentry); + cgroup_dput(cgrp); } /* @@ -4129,12 +4146,8 @@ static void css_dput_fn(struct work_struct *work) { struct cgroup_subsys_state *css = container_of(work, struct cgroup_subsys_state, dput_work); - struct dentry *dentry = css->cgroup->dentry; - struct super_block *sb = dentry->d_sb; - atomic_inc(&sb->s_active); - dput(dentry); - deactivate_super(sb); + cgroup_dput(css->cgroup); } static void css_release(struct percpu_ref *ref) |