aboutsummaryrefslogtreecommitdiffstats
path: root/virt/kvm/ioapic.c
diff options
context:
space:
mode:
authorMichael S. Tsirkin <mst@redhat.com>2012-07-19 06:45:20 -0400
committerMarcelo Tosatti <mtosatti@redhat.com>2012-07-20 15:12:00 -0400
commit1a577b72475d161b6677c05abe57301362023bb2 (patch)
treed8a9910f0016ada479c5a88c1a330b5e1cbc7ef1 /virt/kvm/ioapic.c
parentd63d3e6217c49b81d74141b7920bbe5950532432 (diff)
KVM: fix race with level interrupts
When more than 1 source id is in use for the same GSI, we have the following race related to handling irq_states race: CPU 0 clears bit 0. CPU 0 read irq_state as 0. CPU 1 sets level to 1. CPU 1 calls kvm_ioapic_set_irq(1). CPU 0 calls kvm_ioapic_set_irq(0). Now ioapic thinks the level is 0 but irq_state is not 0. Fix by performing all irq_states bitmap handling under pic/ioapic lock. This also removes the need for atomics with irq_states handling. Reported-by: Gleb Natapov <gleb@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Diffstat (limited to 'virt/kvm/ioapic.c')
-rw-r--r--virt/kvm/ioapic.c19
1 files changed, 16 insertions, 3 deletions
diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c
index 26fd54dc459e..ef61d529a6c4 100644
--- a/virt/kvm/ioapic.c
+++ b/virt/kvm/ioapic.c
@@ -191,7 +191,8 @@ static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq)
191 return kvm_irq_delivery_to_apic(ioapic->kvm, NULL, &irqe); 191 return kvm_irq_delivery_to_apic(ioapic->kvm, NULL, &irqe);
192} 192}
193 193
194int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level) 194int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int irq_source_id,
195 int level)
195{ 196{
196 u32 old_irr; 197 u32 old_irr;
197 u32 mask = 1 << irq; 198 u32 mask = 1 << irq;
@@ -201,9 +202,11 @@ int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level)
201 spin_lock(&ioapic->lock); 202 spin_lock(&ioapic->lock);
202 old_irr = ioapic->irr; 203 old_irr = ioapic->irr;
203 if (irq >= 0 && irq < IOAPIC_NUM_PINS) { 204 if (irq >= 0 && irq < IOAPIC_NUM_PINS) {
205 int irq_level = __kvm_irq_line_state(&ioapic->irq_states[irq],
206 irq_source_id, level);
204 entry = ioapic->redirtbl[irq]; 207 entry = ioapic->redirtbl[irq];
205 level ^= entry.fields.polarity; 208 irq_level ^= entry.fields.polarity;
206 if (!level) 209 if (!irq_level)
207 ioapic->irr &= ~mask; 210 ioapic->irr &= ~mask;
208 else { 211 else {
209 int edge = (entry.fields.trig_mode == IOAPIC_EDGE_TRIG); 212 int edge = (entry.fields.trig_mode == IOAPIC_EDGE_TRIG);
@@ -221,6 +224,16 @@ int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level)
221 return ret; 224 return ret;
222} 225}
223 226
227void kvm_ioapic_clear_all(struct kvm_ioapic *ioapic, int irq_source_id)
228{
229 int i;
230
231 spin_lock(&ioapic->lock);
232 for (i = 0; i < KVM_IOAPIC_NUM_PINS; i++)
233 __clear_bit(irq_source_id, &ioapic->irq_states[i]);
234 spin_unlock(&ioapic->lock);
235}
236
224static void __kvm_ioapic_update_eoi(struct kvm_ioapic *ioapic, int vector, 237static void __kvm_ioapic_update_eoi(struct kvm_ioapic *ioapic, int vector,
225 int trigger_mode) 238 int trigger_mode)
226{ 239{