Commit 791c9e02 authored by George McCollister's avatar George McCollister Committed by Ingo Molnar

sched: Fix double normalization of vruntime

dequeue_entity() is called when p->on_rq and sets se->on_rq = 0
which appears to guarentee that the !se->on_rq condition is met.
If the task has done set_current_state(TASK_INTERRUPTIBLE) without
schedule() the second condition will be met and vruntime will be
incorrectly adjusted twice.

In certain cases this can result in the task's vruntime never increasing
past the vruntime of other tasks on the CFS' run queue, starving them of
CPU time.

This patch changes switched_from_fair() to use !p->on_rq instead of
!se->on_rq.

I'm able to cause a task with a priority of 120 to starve all other
tasks with the same priority on an ARM platform running 3.2.51-rt72
PREEMPT RT by writing one character at time to a serial tty (16550 UART)
in a tight loop. I'm also able to verify making this change corrects the
problem on that platform and kernel version.
Signed-off-by: default avatarGeorge McCollister <george.mccollister@gmail.com>
Signed-off-by: default avatarPeter Zijlstra <peterz@infradead.org>
Cc: stable@vger.kernel.org
Link: http://lkml.kernel.org/r/1392767811-28916-1-git-send-email-george.mccollister@gmail.comSigned-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent d2a04763
...@@ -7001,15 +7001,15 @@ static void switched_from_fair(struct rq *rq, struct task_struct *p) ...@@ -7001,15 +7001,15 @@ static void switched_from_fair(struct rq *rq, struct task_struct *p)
struct cfs_rq *cfs_rq = cfs_rq_of(se); struct cfs_rq *cfs_rq = cfs_rq_of(se);
/* /*
* Ensure the task's vruntime is normalized, so that when its * Ensure the task's vruntime is normalized, so that when it's
* switched back to the fair class the enqueue_entity(.flags=0) will * switched back to the fair class the enqueue_entity(.flags=0) will
* do the right thing. * do the right thing.
* *
* If it was on_rq, then the dequeue_entity(.flags=0) will already * If it's on_rq, then the dequeue_entity(.flags=0) will already
* have normalized the vruntime, if it was !on_rq, then only when * have normalized the vruntime, if it's !on_rq, then only when
* the task is sleeping will it still have non-normalized vruntime. * the task is sleeping will it still have non-normalized vruntime.
*/ */
if (!se->on_rq && p->state != TASK_RUNNING) { if (!p->on_rq && p->state != TASK_RUNNING) {
/* /*
* Fix up our vruntime so that the current sleep doesn't * Fix up our vruntime so that the current sleep doesn't
* cause 'unlimited' sleep bonus. * cause 'unlimited' sleep bonus.
......
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