aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2012-10-18 20:52:07 -0400
committerTejun Heo <tj@kernel.org>2012-10-19 17:08:49 -0400
commit9bb71308b8133d643648776243e4d5599b1c193d (patch)
treef975fb2ffcd3d9b2ae222705836a9a142b97d350 /kernel
parent1f5320d5972aa50d3e8d2b227b636b370e608359 (diff)
Revert "cgroup: Drop task_lock(parent) on cgroup_fork()"
This reverts commit 7e381b0eb1e1a9805c37335562e8dc02e7d7848c. The commit incorrectly assumed that fork path always performed threadgroup_change_begin/end() and depended on that for synchronization against task exit and cgroup migration paths instead of explicitly grabbing task_lock(). threadgroup_change is not locked when forking a new process (as opposed to a new thread in the same process) and even if it were it wouldn't be effective as different processes use different threadgroup locks. Revert the incorrect optimization. Signed-off-by: Tejun Heo <tj@kernel.org> LKML-Reference: <20121008020000.GB2575@localhost> Acked-by: Li Zefan <lizefan@huawei.com> Bitterly-Acked-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: stable@vger.kernel.org
Diffstat (limited to 'kernel')
-rw-r--r--kernel/cgroup.c23
1 files changed, 6 insertions, 17 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index d1739fc7eb94..75aec12c78a0 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -4814,31 +4814,20 @@ static const struct file_operations proc_cgroupstats_operations = {
4814 * 4814 *
4815 * A pointer to the shared css_set was automatically copied in 4815 * A pointer to the shared css_set was automatically copied in
4816 * fork.c by dup_task_struct(). However, we ignore that copy, since 4816 * fork.c by dup_task_struct(). However, we ignore that copy, since
4817 * it was not made under the protection of RCU, cgroup_mutex or 4817 * it was not made under the protection of RCU or cgroup_mutex, so
4818 * threadgroup_change_begin(), so it might no longer be a valid 4818 * might no longer be a valid cgroup pointer. cgroup_attach_task() might
4819 * cgroup pointer. cgroup_attach_task() might have already changed 4819 * have already changed current->cgroups, allowing the previously
4820 * current->cgroups, allowing the previously referenced cgroup 4820 * referenced cgroup group to be removed and freed.
4821 * group to be removed and freed.
4822 *
4823 * Outside the pointer validity we also need to process the css_set
4824 * inheritance between threadgoup_change_begin() and
4825 * threadgoup_change_end(), this way there is no leak in any process
4826 * wide migration performed by cgroup_attach_proc() that could otherwise
4827 * miss a thread because it is too early or too late in the fork stage.
4828 * 4821 *
4829 * At the point that cgroup_fork() is called, 'current' is the parent 4822 * At the point that cgroup_fork() is called, 'current' is the parent
4830 * task, and the passed argument 'child' points to the child task. 4823 * task, and the passed argument 'child' points to the child task.
4831 */ 4824 */
4832void cgroup_fork(struct task_struct *child) 4825void cgroup_fork(struct task_struct *child)
4833{ 4826{
4834 /* 4827 task_lock(current);
4835 * We don't need to task_lock() current because current->cgroups
4836 * can't be changed concurrently here. The parent obviously hasn't
4837 * exited and called cgroup_exit(), and we are synchronized against
4838 * cgroup migration through threadgroup_change_begin().
4839 */
4840 child->cgroups = current->cgroups; 4828 child->cgroups = current->cgroups;
4841 get_css_set(child->cgroups); 4829 get_css_set(child->cgroups);
4830 task_unlock(current);
4842 INIT_LIST_HEAD(&child->cg_list); 4831 INIT_LIST_HEAD(&child->cg_list);
4843} 4832}
4844 4833