Commit 9c40cef2 authored by Thomas Gleixner's avatar Thomas Gleixner Committed by Ingo Molnar

sched: Move blk_schedule_flush_plug() out of __schedule()

There is no real reason to run blk_schedule_flush_plug() with
interrupts and preemption disabled.

Move it into schedule() and call it when the task is going voluntarily
to sleep. There might be false positives when the task is woken
between that call and actually scheduling, but that's not really
different from being woken immediately after switching away.

This fixes a deadlock in the scheduler where the
blk_schedule_flush_plug() callchain enables interrupts and thereby
allows a wakeup to happen of the task that's going to sleep.
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Signed-off-by: default avatarPeter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Tejun Heo <tj@kernel.org>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: stable@kernel.org # 2.6.39+
Link: http://lkml.kernel.org/n/tip-dwfxtra7yg1b5r65m32ywtct@git.kernel.orgSigned-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent c259e01a
...@@ -4322,16 +4322,6 @@ static void __sched __schedule(void) ...@@ -4322,16 +4322,6 @@ static void __sched __schedule(void)
if (to_wakeup) if (to_wakeup)
try_to_wake_up_local(to_wakeup); try_to_wake_up_local(to_wakeup);
} }
/*
* If we are going to sleep and we have plugged IO
* queued, make sure to submit it to avoid deadlocks.
*/
if (blk_needs_flush_plug(prev)) {
raw_spin_unlock(&rq->lock);
blk_schedule_flush_plug(prev);
raw_spin_lock(&rq->lock);
}
} }
switch_count = &prev->nvcsw; switch_count = &prev->nvcsw;
} }
...@@ -4370,8 +4360,23 @@ static void __sched __schedule(void) ...@@ -4370,8 +4360,23 @@ static void __sched __schedule(void)
goto need_resched; goto need_resched;
} }
static inline void sched_submit_work(struct task_struct *tsk)
{
if (!tsk->state)
return;
/*
* If we are going to sleep and we have plugged IO queued,
* make sure to submit it to avoid deadlocks.
*/
if (blk_needs_flush_plug(tsk))
blk_schedule_flush_plug(tsk);
}
asmlinkage void schedule(void) asmlinkage void schedule(void)
{ {
struct task_struct *tsk = current;
sched_submit_work(tsk);
__schedule(); __schedule();
} }
EXPORT_SYMBOL(schedule); EXPORT_SYMBOL(schedule);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment