aboutsummaryrefslogtreecommitdiffstats
path: root/virt
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
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')
-rw-r--r--virt/kvm/ioapic.c19
-rw-r--r--virt/kvm/ioapic.h4
-rw-r--r--virt/kvm/irq_comm.c31
3 files changed, 23 insertions, 31 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{
diff --git a/virt/kvm/ioapic.h b/virt/kvm/ioapic.h
index 32872a09b63f..a30abfe6ed16 100644
--- a/virt/kvm/ioapic.h
+++ b/virt/kvm/ioapic.h
@@ -74,7 +74,9 @@ void kvm_ioapic_update_eoi(struct kvm *kvm, int vector, int trigger_mode);
74bool kvm_ioapic_handles_vector(struct kvm *kvm, int vector); 74bool kvm_ioapic_handles_vector(struct kvm *kvm, int vector);
75int kvm_ioapic_init(struct kvm *kvm); 75int kvm_ioapic_init(struct kvm *kvm);
76void kvm_ioapic_destroy(struct kvm *kvm); 76void kvm_ioapic_destroy(struct kvm *kvm);
77int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level); 77int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int irq_source_id,
78 int level);
79void kvm_ioapic_clear_all(struct kvm_ioapic *ioapic, int irq_source_id);
78void kvm_ioapic_reset(struct kvm_ioapic *ioapic); 80void kvm_ioapic_reset(struct kvm_ioapic *ioapic);
79int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src, 81int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src,
80 struct kvm_lapic_irq *irq); 82 struct kvm_lapic_irq *irq);
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}