summaryrefslogtreecommitdiff
path: root/kernel/fail_function.c
diff options
context:
space:
mode:
authorPeter Zijlstra <peterz@infradead.org>2020-07-20 17:20:21 +0200
committerPeter Zijlstra <peterz@infradead.org>2020-07-22 10:22:00 +0200
commitd136122f58458479fd8926020ba2937de61d7f65 (patch)
treeab3373ed22a5a5801e4570aca5941bab4dc59921 /kernel/fail_function.c
parentba47d845d715a010f7b51f6f89bae32845e6acb7 (diff)
sched: Fix race against ptrace_freeze_trace()
There is apparently one site that violates the rule that only current and ttwu() will modify task->state, namely ptrace_{,un}freeze_traced() will change task->state for a remote task. Oleg explains: "TASK_TRACED/TASK_STOPPED was always protected by siglock. In particular, ttwu(__TASK_TRACED) must be always called with siglock held. That is why ptrace_freeze_traced() assumes it can safely do s/TASK_TRACED/__TASK_TRACED/ under spin_lock(siglock)." This breaks the ordering scheme introduced by commit: dbfb089d360b ("sched: Fix loadavg accounting race") Specifically, the reload not matching no longer implies we don't have to block. Simply things by noting that what we need is a LOAD->STORE ordering and this can be provided by a control dependency. So replace: prev_state = prev->state; raw_spin_lock(&rq->lock); smp_mb__after_spinlock(); /* SMP-MB */ if (... && prev_state && prev_state == prev->state) deactivate_task(); with: prev_state = prev->state; if (... && prev_state) /* CTRL-DEP */ deactivate_task(); Since that already implies the 'prev->state' load must be complete before allowing the 'prev->on_rq = 0' store to become visible. Fixes: dbfb089d360b ("sched: Fix loadavg accounting race") Reported-by: Jiri Slaby <jirislaby@kernel.org> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Acked-by: Oleg Nesterov <oleg@redhat.com> Tested-by: Paul Gortmaker <paul.gortmaker@windriver.com> Tested-by: Christian Brauner <christian.brauner@ubuntu.com>
Diffstat (limited to 'kernel/fail_function.c')
0 files changed, 0 insertions, 0 deletions