diff options
author | Peter Zijlstra <peterz@infradead.org> | 2012-06-22 07:36:05 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2012-07-24 07:58:20 -0400 |
commit | 8323f26ce3425460769605a6aece7a174edaa7d1 (patch) | |
tree | 44daa0dafa49cedc9301efd1417c6c2ac338c1c7 /include/linux/init_task.h | |
parent | 88b8dac0a14c511ff41486b83a8c3d688936eec0 (diff) |
sched: Fix race in task_group()
Stefan reported a crash on a kernel before a3e5d1091c1 ("sched:
Don't call task_group() too many times in set_task_rq()"), he
found the reason to be that the multiple task_group()
invocations in set_task_rq() returned different values.
Looking at all that I found a lack of serialization and plain
wrong comments.
The below tries to fix it using an extra pointer which is
updated under the appropriate scheduler locks. Its not pretty,
but I can't really see another way given how all the cgroup
stuff works.
Reported-and-tested-by: Stefan Bader <stefan.bader@canonical.com>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/1340364965.18025.71.camel@twins
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'include/linux/init_task.h')
-rw-r--r-- | include/linux/init_task.h | 12 |
1 files changed, 11 insertions, 1 deletions
diff --git a/include/linux/init_task.h b/include/linux/init_task.h index 9e65eff6af3b..b806b821e735 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h | |||
@@ -123,8 +123,17 @@ extern struct group_info init_groups; | |||
123 | 123 | ||
124 | extern struct cred init_cred; | 124 | extern struct cred init_cred; |
125 | 125 | ||
126 | extern struct task_group root_task_group; | ||
127 | |||
128 | #ifdef CONFIG_CGROUP_SCHED | ||
129 | # define INIT_CGROUP_SCHED(tsk) \ | ||
130 | .sched_task_group = &root_task_group, | ||
131 | #else | ||
132 | # define INIT_CGROUP_SCHED(tsk) | ||
133 | #endif | ||
134 | |||
126 | #ifdef CONFIG_PERF_EVENTS | 135 | #ifdef CONFIG_PERF_EVENTS |
127 | # define INIT_PERF_EVENTS(tsk) \ | 136 | # define INIT_PERF_EVENTS(tsk) \ |
128 | .perf_event_mutex = \ | 137 | .perf_event_mutex = \ |
129 | __MUTEX_INITIALIZER(tsk.perf_event_mutex), \ | 138 | __MUTEX_INITIALIZER(tsk.perf_event_mutex), \ |
130 | .perf_event_list = LIST_HEAD_INIT(tsk.perf_event_list), | 139 | .perf_event_list = LIST_HEAD_INIT(tsk.perf_event_list), |
@@ -161,6 +170,7 @@ extern struct cred init_cred; | |||
161 | }, \ | 170 | }, \ |
162 | .tasks = LIST_HEAD_INIT(tsk.tasks), \ | 171 | .tasks = LIST_HEAD_INIT(tsk.tasks), \ |
163 | INIT_PUSHABLE_TASKS(tsk) \ | 172 | INIT_PUSHABLE_TASKS(tsk) \ |
173 | INIT_CGROUP_SCHED(tsk) \ | ||
164 | .ptraced = LIST_HEAD_INIT(tsk.ptraced), \ | 174 | .ptraced = LIST_HEAD_INIT(tsk.ptraced), \ |
165 | .ptrace_entry = LIST_HEAD_INIT(tsk.ptrace_entry), \ | 175 | .ptrace_entry = LIST_HEAD_INIT(tsk.ptrace_entry), \ |
166 | .real_parent = &tsk, \ | 176 | .real_parent = &tsk, \ |