diff options
| author | Oleg Nesterov <oleg@redhat.com> | 2016-11-14 13:46:12 -0500 |
|---|---|---|
| committer | Ingo Molnar <mingo@kernel.org> | 2016-11-22 06:33:43 -0500 |
| commit | 8e5bfa8c1f8471aa4a2d30be631ef2b50e10abaf (patch) | |
| tree | ad3d1c2dc3f1770ac865c8f1df91a53c1e276728 /kernel | |
| parent | 18f649ef344127ef6de23a5a4272dbe2fdb73dde (diff) | |
sched/autogroup: Do not use autogroup->tg in zombie threads
Exactly because for_each_thread() in autogroup_move_group() can't see it
and update its ->sched_task_group before _put() and possibly free().
So the exiting task needs another sched_move_task() before exit_notify()
and we need to re-introduce the PF_EXITING (or similar) check removed by
the previous change for another reason.
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: hartsjc@redhat.com
Cc: vbendel@redhat.com
Cc: vlovejoy@redhat.com
Link: http://lkml.kernel.org/r/20161114184612.GA15968@redhat.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/exit.c | 1 | ||||
| -rw-r--r-- | kernel/sched/auto_group.c | 19 |
2 files changed, 20 insertions, 0 deletions
diff --git a/kernel/exit.c b/kernel/exit.c index 9d68c45ebbe3..3076f3089919 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
| @@ -836,6 +836,7 @@ void __noreturn do_exit(long code) | |||
| 836 | */ | 836 | */ |
| 837 | perf_event_exit_task(tsk); | 837 | perf_event_exit_task(tsk); |
| 838 | 838 | ||
| 839 | sched_autogroup_exit_task(tsk); | ||
| 839 | cgroup_exit(tsk); | 840 | cgroup_exit(tsk); |
| 840 | 841 | ||
| 841 | /* | 842 | /* |
diff --git a/kernel/sched/auto_group.c b/kernel/sched/auto_group.c index ad2b19ad6ca0..f1c8fd566246 100644 --- a/kernel/sched/auto_group.c +++ b/kernel/sched/auto_group.c | |||
| @@ -115,10 +115,26 @@ bool task_wants_autogroup(struct task_struct *p, struct task_group *tg) | |||
| 115 | * If we race with autogroup_move_group() the caller can use the old | 115 | * If we race with autogroup_move_group() the caller can use the old |
| 116 | * value of signal->autogroup but in this case sched_move_task() will | 116 | * value of signal->autogroup but in this case sched_move_task() will |
| 117 | * be called again before autogroup_kref_put(). | 117 | * be called again before autogroup_kref_put(). |
| 118 | * | ||
| 119 | * However, there is no way sched_autogroup_exit_task() could tell us | ||
| 120 | * to avoid autogroup->tg, so we abuse PF_EXITING flag for this case. | ||
| 118 | */ | 121 | */ |
| 122 | if (p->flags & PF_EXITING) | ||
| 123 | return false; | ||
| 124 | |||
| 119 | return true; | 125 | return true; |
| 120 | } | 126 | } |
| 121 | 127 | ||
| 128 | void sched_autogroup_exit_task(struct task_struct *p) | ||
| 129 | { | ||
| 130 | /* | ||
| 131 | * We are going to call exit_notify() and autogroup_move_group() can't | ||
| 132 | * see this thread after that: we can no longer use signal->autogroup. | ||
| 133 | * See the PF_EXITING check in task_wants_autogroup(). | ||
| 134 | */ | ||
| 135 | sched_move_task(p); | ||
| 136 | } | ||
| 137 | |||
| 122 | static void | 138 | static void |
| 123 | autogroup_move_group(struct task_struct *p, struct autogroup *ag) | 139 | autogroup_move_group(struct task_struct *p, struct autogroup *ag) |
| 124 | { | 140 | { |
| @@ -142,6 +158,9 @@ autogroup_move_group(struct task_struct *p, struct autogroup *ag) | |||
| 142 | * In the latter case for_each_thread() can not miss a migrating thread, | 158 | * In the latter case for_each_thread() can not miss a migrating thread, |
| 143 | * cpu_cgroup_attach() must not be possible after cgroup_exit() and it | 159 | * cpu_cgroup_attach() must not be possible after cgroup_exit() and it |
| 144 | * can't be removed from thread list, we hold ->siglock. | 160 | * can't be removed from thread list, we hold ->siglock. |
| 161 | * | ||
| 162 | * If an exiting thread was already removed from thread list we rely on | ||
| 163 | * sched_autogroup_exit_task(). | ||
| 145 | */ | 164 | */ |
| 146 | for_each_thread(p, t) | 165 | for_each_thread(p, t) |
| 147 | sched_move_task(t); | 166 | sched_move_task(t); |
