diff options
author | Michael S. Tsirkin <mst@redhat.com> | 2012-07-19 06:45:20 -0400 |
---|---|---|
committer | Marcelo Tosatti <mtosatti@redhat.com> | 2012-07-20 15:12:00 -0400 |
commit | 1a577b72475d161b6677c05abe57301362023bb2 (patch) | |
tree | d8a9910f0016ada479c5a88c1a330b5e1cbc7ef1 /virt/kvm/irq_comm.c | |
parent | d63d3e6217c49b81d74141b7920bbe5950532432 (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.c | 31 |
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 | ||
36 | static 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 | |||
48 | static int kvm_set_pic_irq(struct kvm_kernel_irq_routing_entry *e, | 36 | static 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 | ||
71 | inline static bool kvm_is_dm_lowest_prio(struct kvm_lapic_irq *irq) | 54 | inline static bool kvm_is_dm_lowest_prio(struct kvm_lapic_irq *irq) |
@@ -249,8 +232,6 @@ unlock: | |||
249 | 232 | ||
250 | void kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id) | 233 | void 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 | } | ||
274 | unlock: | 251 | unlock: |
275 | mutex_unlock(&kvm->irq_lock); | 252 | mutex_unlock(&kvm->irq_lock); |
276 | } | 253 | } |