Commit c3a2ae3d93c0f10d29c071f599764d00b8de00cb

Authored by Steven Rostedt
Committed by Ingo Molnar
1 parent da19ab5103

sched: Add new prio to cpupri before removing old prio

We need to add the new prio to the cpupri accounting before
removing the old prio. This is because removing the old prio
first will open a race window where the cpu will be removed
from pri_active. In this case the cpu will not be visible for
RT push and pulls. This could cause a RT task to not migrate
appropriately, and create a very large latency.

This bug was found with the use of ftrace sched events and
trace_printk.

Signed-off-by: Steven Rostedt <srostedt@redhat.com>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
LKML-Reference: <20090729042526.438281019@goodmis.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>

Showing 1 changed file with 16 additions and 14 deletions Side-by-side Diff

kernel/sched_cpupri.c
... ... @@ -127,21 +127,11 @@
127 127  
128 128 /*
129 129 * If the cpu was currently mapped to a different value, we
130   - * first need to unmap the old value
  130 + * need to map it to the new value then remove the old value.
  131 + * Note, we must add the new value first, otherwise we risk the
  132 + * cpu being cleared from pri_active, and this cpu could be
  133 + * missed for a push or pull.
131 134 */
132   - if (likely(oldpri != CPUPRI_INVALID)) {
133   - struct cpupri_vec *vec = &cp->pri_to_cpu[oldpri];
134   -
135   - spin_lock_irqsave(&vec->lock, flags);
136   -
137   - vec->count--;
138   - if (!vec->count)
139   - clear_bit(oldpri, cp->pri_active);
140   - cpumask_clear_cpu(cpu, vec->mask);
141   -
142   - spin_unlock_irqrestore(&vec->lock, flags);
143   - }
144   -
145 135 if (likely(newpri != CPUPRI_INVALID)) {
146 136 struct cpupri_vec *vec = &cp->pri_to_cpu[newpri];
147 137  
... ... @@ -151,6 +141,18 @@
151 141 vec->count++;
152 142 if (vec->count == 1)
153 143 set_bit(newpri, cp->pri_active);
  144 +
  145 + spin_unlock_irqrestore(&vec->lock, flags);
  146 + }
  147 + if (likely(oldpri != CPUPRI_INVALID)) {
  148 + struct cpupri_vec *vec = &cp->pri_to_cpu[oldpri];
  149 +
  150 + spin_lock_irqsave(&vec->lock, flags);
  151 +
  152 + vec->count--;
  153 + if (!vec->count)
  154 + clear_bit(oldpri, cp->pri_active);
  155 + cpumask_clear_cpu(cpu, vec->mask);
154 156  
155 157 spin_unlock_irqrestore(&vec->lock, flags);
156 158 }