Commit 1404f065 authored by Li Zefan's avatar Li Zefan Committed by Linus Torvalds
Browse files

cgroups: fix lock inconsistency in cgroup_clone()



I fixed a bug in cgroup_clone() in Linus' tree in commit 7b574b7b
("cgroups: fix a race between cgroup_clone and umount") without noticing
there was a cleanup patch in -mm tree that should be rebased (now commit
104cbd55, "cgroups: use task_lock() for access tsk->cgroups safe in
cgroup_clone()"), thus resulted in lock inconsistency.

Signed-off-by: default avatarLi Zefan <lizf@cn.fujitsu.com>
Acked-by: default avatarPaul Menage <menage@google.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 945048ca
Loading
Loading
Loading
Loading
+7 −6
Original line number Diff line number Diff line
@@ -2993,20 +2993,21 @@ int cgroup_clone(struct task_struct *tsk, struct cgroup_subsys *subsys,
		mutex_unlock(&cgroup_mutex);
		return 0;
	}
	task_lock(tsk);
	cg = tsk->cgroups;
	parent = task_cgroup(tsk, subsys->subsys_id);

	/* Pin the hierarchy */
	if (!atomic_inc_not_zero(&parent->root->sb->s_active)) {
	if (!atomic_inc_not_zero(&root->sb->s_active)) {
		/* We race with the final deactivate_super() */
		mutex_unlock(&cgroup_mutex);
		return 0;
	}

	/* Keep the cgroup alive */
	task_lock(tsk);
	parent = task_cgroup(tsk, subsys->subsys_id);
	cg = tsk->cgroups;
	get_css_set(cg);
	task_unlock(tsk);

	mutex_unlock(&cgroup_mutex);

	/* Now do the VFS work to create a cgroup */
@@ -3045,7 +3046,7 @@ int cgroup_clone(struct task_struct *tsk, struct cgroup_subsys *subsys,
		mutex_unlock(&inode->i_mutex);
		put_css_set(cg);

		deactivate_super(parent->root->sb);
		deactivate_super(root->sb);
		/* The cgroup is still accessible in the VFS, but
		 * we're not going to try to rmdir() it at this
		 * point. */
@@ -3071,7 +3072,7 @@ int cgroup_clone(struct task_struct *tsk, struct cgroup_subsys *subsys,
	mutex_lock(&cgroup_mutex);
	put_css_set(cg);
	mutex_unlock(&cgroup_mutex);
	deactivate_super(parent->root->sb);
	deactivate_super(root->sb);
	return ret;
}