cgroup: fix a race between cgroup_mount() and cgroup_kill_sb()
authorLi Zefan <lizefan@huawei.com>
Mon, 30 Jun 2014 03:50:59 +0000 (11:50 +0800)
committerTejun Heo <tj@kernel.org>
Mon, 30 Jun 2014 14:16:26 +0000 (10:16 -0400)
commit3a32bd72d77058d768dbb38183ad517f720dd1bc
treedc67b70a50e1dc649b059113bb8303f420192eca
parent4e26445faad366d67d7723622bf6a60a6f0f5993
cgroup: fix a race between cgroup_mount() and cgroup_kill_sb()

We've converted cgroup to kernfs so cgroup won't be intertwined with
vfs objects and locking, but there are dark areas.

Run two instances of this script concurrently:

    for ((; ;))
    {
     mount -t cgroup -o cpuacct xxx /cgroup
     umount /cgroup
    }

After a while, I saw two mount processes were stuck at retrying, because
they were waiting for a subsystem to become free, but the root associated
with this subsystem never got freed.

This can happen, if thread A is in the process of killing superblock but
hasn't called percpu_ref_kill(), and at this time thread B is mounting
the same cgroup root and finds the root in the root list and performs
percpu_ref_try_get().

To fix this, we try to increase both the refcnt of the superblock and the
percpu refcnt of cgroup root.

v2:
- we should try to get both the superblock refcnt and cgroup_root refcnt,
  because cgroup_root may have no superblock assosiated with it.
- adjust/add comments.

tj: Updated comments.  Renamed @sb to @pinned_sb.

Cc: <stable@vger.kernel.org> # 3.15
Signed-off-by: Li Zefan <lizefan@huawei.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
kernel/cgroup.c