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()
This commit is contained in:
commit
9a78f9c3c6
|
@ -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
|
* 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
|
* schedule one last time. The schedule call will never return, and
|
||||||
* the scheduled task must drop that reference.
|
* 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
|
* We must observe prev->state before clearing prev->on_cpu (in
|
||||||
* there before we look at prev->state, and then the reference would
|
* finish_lock_switch), otherwise a concurrent wakeup can get prev
|
||||||
* be dropped twice.
|
* running on another CPU and we could rave with its RUNNING -> DEAD
|
||||||
* Manfred Spraul <manfred@colorfullife.com>
|
* transition, resulting in a double drop.
|
||||||
*/
|
*/
|
||||||
prev_state = prev->state;
|
prev_state = prev->state;
|
||||||
vtime_task_switch(prev);
|
vtime_task_switch(prev);
|
||||||
|
|
|
@ -1078,9 +1078,10 @@ static inline void finish_lock_switch(struct rq *rq, struct task_struct *prev)
|
||||||
* After ->on_cpu is cleared, the task can be moved to a different CPU.
|
* After ->on_cpu is cleared, the task can be moved to a different CPU.
|
||||||
* We must ensure this doesn't happen until the switch is completely
|
* We must ensure this doesn't happen until the switch is completely
|
||||||
* finished.
|
* finished.
|
||||||
|
*
|
||||||
|
* Pairs with the control dependency and rmb in try_to_wake_up().
|
||||||
*/
|
*/
|
||||||
smp_wmb();
|
smp_store_release(&prev->on_cpu, 0);
|
||||||
prev->on_cpu = 0;
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_DEBUG_SPINLOCK
|
#ifdef CONFIG_DEBUG_SPINLOCK
|
||||||
/* this is a valid case when another task releases the spinlock */
|
/* this is a valid case when another task releases the spinlock */
|
||||||
|
|
Loading…
Reference in New Issue