cgroup: fix mount failure in a corner case
# cat test.sh #! /bin/bash mount -t cgroup -o cpu xxx /cgroup umount /cgroup mount -t cgroup -o cpu,cpuacct xxx /cgroup umount /cgroup # ./test.sh mount: xxx already mounted or /cgroup busy mount: according to mtab, xxx is already mounted on /cgroup It's because the cgroupfs_root of the first mount was under destruction asynchronously. Fix this by delaying and then retrying mount for this case. v3: - put the refcnt immediately after getting it. (Tejun) v2: - use percpu_ref_tryget_live() rather that introducing percpu_ref_alive(). (Tejun) - adjust comment. tj: Updated the comment a bit. Cc: <stable@vger.kernel.org> # 3.15 Signed-off-by: Li Zefan <lizefan@huawei.com> Signed-off-by: Tejun Heo <tj@kernel.org>
This commit is contained in:
parent
391acf970d
commit
970317aa48
|
@ -1648,10 +1648,12 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
|
|||
int flags, const char *unused_dev_name,
|
||||
void *data)
|
||||
{
|
||||
struct cgroup_subsys *ss;
|
||||
struct cgroup_root *root;
|
||||
struct cgroup_sb_opts opts;
|
||||
struct dentry *dentry;
|
||||
int ret;
|
||||
int i;
|
||||
bool new_sb;
|
||||
|
||||
/*
|
||||
|
@ -1677,6 +1679,27 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
|
|||
goto out_unlock;
|
||||
}
|
||||
|
||||
/*
|
||||
* Destruction of cgroup root is asynchronous, so subsystems may
|
||||
* still be dying after the previous unmount. Let's drain the
|
||||
* dying subsystems. We just need to ensure that the ones
|
||||
* unmounted previously finish dying and don't care about new ones
|
||||
* starting. Testing ref liveliness is good enough.
|
||||
*/
|
||||
for_each_subsys(ss, i) {
|
||||
if (!(opts.subsys_mask & (1 << i)) ||
|
||||
ss->root == &cgrp_dfl_root)
|
||||
continue;
|
||||
|
||||
if (!percpu_ref_tryget_live(&ss->root->cgrp.self.refcnt)) {
|
||||
mutex_unlock(&cgroup_mutex);
|
||||
msleep(10);
|
||||
ret = restart_syscall();
|
||||
goto out_free;
|
||||
}
|
||||
cgroup_put(&ss->root->cgrp);
|
||||
}
|
||||
|
||||
for_each_root(root) {
|
||||
bool name_match = false;
|
||||
|
||||
|
|
Loading…
Reference in New Issue