diff options
author | Tejun Heo <tj@kernel.org> | 2012-10-18 20:52:07 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2012-10-19 17:08:49 -0400 |
commit | 9bb71308b8133d643648776243e4d5599b1c193d (patch) | |
tree | f975fb2ffcd3d9b2ae222705836a9a142b97d350 /kernel | |
parent | 1f5320d5972aa50d3e8d2b227b636b370e608359 (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.c | 23 |
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 | */ |
4832 | void cgroup_fork(struct task_struct *child) | 4825 | void 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 | ||