Commit c3a2ae3d93c0f10d29c071f599764d00b8de00cb
Committed by
Ingo Molnar
1 parent
da19ab5103
Exists in
master
and in
7 other branches
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 | } |