aboutsummaryrefslogtreecommitdiffstats
path: root/virt/kvm/irq_comm.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/irq_comm.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/irq_comm.c')
-rw-r--r--virt/kvm/irq_comm.c31
1 files changed, 4 insertions, 27 deletions
diff --git a/virt/kvm/irq_comm.c b/virt/kvm/irq_comm.c
index a6a0365475ed..cc59c68da032 100644
--- a/virt/kvm/irq_comm.c
+++ b/virt/kvm/irq_comm.c
@@ -33,26 +33,12 @@
33 33
34#include "ioapic.h" 34#include "ioapic.h"
35 35
36static inline int kvm_irq_line_state(unsigned long *irq_state,
37 int irq_source_id, int level)
38{
39 /* Logical OR for level trig interrupt */
40 if (level)
41 set_bit(irq_source_id, irq_state);
42 else
43 clear_bit(irq_source_id, irq_state);
44
45 return !!(*irq_state);
46}
47
48static int kvm_set_pic_irq(struct kvm_kernel_irq_routing_entry *e, 36static int kvm_set_pic_irq(struct kvm_kernel_irq_routing_entry *e,
49 struct kvm *kvm, int irq_source_id, int level) 37 struct kvm *kvm, int irq_source_id, int level)
50{ 38{
51#ifdef CONFIG_X86 39#ifdef CONFIG_X86
52 struct kvm_pic *pic = pic_irqchip(kvm); 40 struct kvm_pic *pic = pic_irqchip(kvm);
53 level = kvm_irq_line_state(&pic->irq_states[e->irqchip.pin], 41 return kvm_pic_set_irq(pic, e->irqchip.pin, irq_source_id, level);
54 irq_source_id, level);
55 return kvm_pic_set_irq(pic, e->irqchip.pin, level);
56#else 42#else
57 return -1; 43 return -1;
58#endif 44#endif
@@ -62,10 +48,7 @@ static int kvm_set_ioapic_irq(struct kvm_kernel_irq_routing_entry *e,
62 struct kvm *kvm, int irq_source_id, int level) 48 struct kvm *kvm, int irq_source_id, int level)
63{ 49{
64 struct kvm_ioapic *ioapic = kvm->arch.vioapic; 50 struct kvm_ioapic *ioapic = kvm->arch.vioapic;
65 level = kvm_irq_line_state(&ioapic->irq_states[e->irqchip.pin], 51 return kvm_ioapic_set_irq(ioapic, e->irqchip.pin, irq_source_id, level);
66 irq_source_id, level);
67
68 return kvm_ioapic_set_irq(ioapic, e->irqchip.pin, level);
69} 52}
70 53
71inline static bool kvm_is_dm_lowest_prio(struct kvm_lapic_irq *irq) 54inline static bool kvm_is_dm_lowest_prio(struct kvm_lapic_irq *irq)
@@ -249,8 +232,6 @@ unlock:
249 232
250void kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id) 233void kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id)
251{ 234{
252 int i;
253
254 ASSERT(irq_source_id != KVM_USERSPACE_IRQ_SOURCE_ID); 235 ASSERT(irq_source_id != KVM_USERSPACE_IRQ_SOURCE_ID);
255 236
256 mutex_lock(&kvm->irq_lock); 237 mutex_lock(&kvm->irq_lock);
@@ -263,14 +244,10 @@ void kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id)
263 if (!irqchip_in_kernel(kvm)) 244 if (!irqchip_in_kernel(kvm))
264 goto unlock; 245 goto unlock;
265 246
266 for (i = 0; i < KVM_IOAPIC_NUM_PINS; i++) { 247 kvm_ioapic_clear_all(kvm->arch.vioapic, irq_source_id);
267 clear_bit(irq_source_id, &kvm->arch.vioapic->irq_states[i]);
268 if (i >= 16)
269 continue;
270#ifdef CONFIG_X86 248#ifdef CONFIG_X86
271 clear_bit(irq_source_id, &pic_irqchip(kvm)->irq_states[i]); 249 kvm_pic_clear_all(pic_irqchip(kvm), irq_source_id);
272#endif 250#endif
273 }
274unlock: 251unlock:
275 mutex_unlock(&kvm->irq_lock); 252 mutex_unlock(&kvm->irq_lock);
276} 253}