summaryrefslogtreecommitdiffstats
path: root/kernel/sched/core.c
diff options
context:
space:
mode:
authorLinus Torvalds2015-10-11 19:24:32 +0200
committerLinus Torvalds2015-10-11 19:24:32 +0200
commit9a78f9c3c68c4d57f602b4100e766945d3362f4d (patch)
treed17f8e55f98819b58bd0a594afee211867d3a016 /kernel/sched/core.c
parentMerge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/ke... (diff)
parentsched/core: Fix TASK_DEAD race in finish_task_switch() (diff)
downloadkernel-qcow2-linux-9a78f9c3c68c4d57f602b4100e766945d3362f4d.tar.gz
kernel-qcow2-linux-9a78f9c3c68c4d57f602b4100e766945d3362f4d.tar.xz
kernel-qcow2-linux-9a78f9c3c68c4d57f602b4100e766945d3362f4d.zip
Merge branch 'sched-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull scheduler fix from Thomas Gleixner: "Fix a long standing state race in finish_task_switch()" * 'sched-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: sched/core: Fix TASK_DEAD race in finish_task_switch()
Diffstat (limited to 'kernel/sched/core.c')
-rw-r--r--kernel/sched/core.c10
1 files changed, 5 insertions, 5 deletions
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 615953141951..10a8faa1b0d4 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -2517,11 +2517,11 @@ static struct rq *finish_task_switch(struct task_struct *prev)
* If a task dies, then it sets TASK_DEAD in tsk->state and calls
* schedule one last time. The schedule call will never return, and
* the scheduled task must drop that reference.
- * The test for TASK_DEAD must occur while the runqueue locks are
- * still held, otherwise prev could be scheduled on another cpu, die
- * there before we look at prev->state, and then the reference would
- * be dropped twice.
- * Manfred Spraul <manfred@colorfullife.com>
+ *
+ * We must observe prev->state before clearing prev->on_cpu (in
+ * finish_lock_switch), otherwise a concurrent wakeup can get prev
+ * running on another CPU and we could rave with its RUNNING -> DEAD
+ * transition, resulting in a double drop.
*/
prev_state = prev->state;
vtime_task_switch(prev);