diff options
author | Peter Zijlstra <peterz@infradead.org> | 2015-10-07 14:14:13 +0200 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2015-12-04 10:26:43 +0100 |
commit | ecf7d01c229d11a44609c0067889372c91fb4f36 (patch) | |
tree | 244e7e8752a7fa9a9dc8cb36cd6ce4ef04042c95 /kernel/Kconfig.freezer | |
parent | sched/core: Better document the try_to_wake_up() barriers (diff) | |
download | linux-ecf7d01c229d11a44609c0067889372c91fb4f36.tar.xz linux-ecf7d01c229d11a44609c0067889372c91fb4f36.zip |
sched/core: Fix an SMP ordering race in try_to_wake_up() vs. schedule()
Oleg noticed that its possible to falsely observe p->on_cpu == 0 such
that we'll prematurely continue with the wakeup and effectively run p on
two CPUs at the same time.
Even though the overlap is very limited; the task is in the middle of
being scheduled out; it could still result in corruption of the
scheduler data structures.
CPU0 CPU1
set_current_state(...)
<preempt_schedule>
context_switch(X, Y)
prepare_lock_switch(Y)
Y->on_cpu = 1;
finish_lock_switch(X)
store_release(X->on_cpu, 0);
try_to_wake_up(X)
LOCK(p->pi_lock);
t = X->on_cpu; // 0
context_switch(Y, X)
prepare_lock_switch(X)
X->on_cpu = 1;
finish_lock_switch(Y)
store_release(Y->on_cpu, 0);
</preempt_schedule>
schedule();
deactivate_task(X);
X->on_rq = 0;
if (X->on_rq) // false
if (t) while (X->on_cpu)
cpu_relax();
context_switch(X, ..)
finish_lock_switch(X)
store_release(X->on_cpu, 0);
Avoid the load of X->on_cpu being hoisted over the X->on_rq load.
Reported-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>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'kernel/Kconfig.freezer')
0 files changed, 0 insertions, 0 deletions