Skip to content

Commit 1a577b7

Browse files
mstsirkinmatosatti
authored andcommitted
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 <[email protected]> Signed-off-by: Michael S. Tsirkin <[email protected]> Signed-off-by: Marcelo Tosatti <[email protected]>
1 parent d63d3e6 commit 1a577b7

File tree

5 files changed

+51
-35
lines changed

5 files changed

+51
-35
lines changed

arch/x86/include/asm/kvm_host.h

+14-1
Original file line numberDiff line numberDiff line change
@@ -816,7 +816,20 @@ int kvm_read_guest_page_mmu(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
816816
void kvm_propagate_fault(struct kvm_vcpu *vcpu, struct x86_exception *fault);
817817
bool kvm_require_cpl(struct kvm_vcpu *vcpu, int required_cpl);
818818

819-
int kvm_pic_set_irq(void *opaque, int irq, int level);
819+
static inline int __kvm_irq_line_state(unsigned long *irq_state,
820+
int irq_source_id, int level)
821+
{
822+
/* Logical OR for level trig interrupt */
823+
if (level)
824+
__set_bit(irq_source_id, irq_state);
825+
else
826+
__clear_bit(irq_source_id, irq_state);
827+
828+
return !!(*irq_state);
829+
}
830+
831+
int kvm_pic_set_irq(struct kvm_pic *pic, int irq, int irq_source_id, int level);
832+
void kvm_pic_clear_all(struct kvm_pic *pic, int irq_source_id);
820833

821834
void kvm_inject_nmi(struct kvm_vcpu *vcpu);
822835

arch/x86/kvm/i8259.c

+14-3
Original file line numberDiff line numberDiff line change
@@ -188,14 +188,15 @@ void kvm_pic_update_irq(struct kvm_pic *s)
188188
pic_unlock(s);
189189
}
190190

191-
int kvm_pic_set_irq(void *opaque, int irq, int level)
191+
int kvm_pic_set_irq(struct kvm_pic *s, int irq, int irq_source_id, int level)
192192
{
193-
struct kvm_pic *s = opaque;
194193
int ret = -1;
195194

196195
pic_lock(s);
197196
if (irq >= 0 && irq < PIC_NUM_PINS) {
198-
ret = pic_set_irq1(&s->pics[irq >> 3], irq & 7, level);
197+
int irq_level = __kvm_irq_line_state(&s->irq_states[irq],
198+
irq_source_id, level);
199+
ret = pic_set_irq1(&s->pics[irq >> 3], irq & 7, irq_level);
199200
pic_update_irq(s);
200201
trace_kvm_pic_set_irq(irq >> 3, irq & 7, s->pics[irq >> 3].elcr,
201202
s->pics[irq >> 3].imr, ret == 0);
@@ -205,6 +206,16 @@ int kvm_pic_set_irq(void *opaque, int irq, int level)
205206
return ret;
206207
}
207208

209+
void kvm_pic_clear_all(struct kvm_pic *s, int irq_source_id)
210+
{
211+
int i;
212+
213+
pic_lock(s);
214+
for (i = 0; i < PIC_NUM_PINS; i++)
215+
__clear_bit(irq_source_id, &s->irq_states[i]);
216+
pic_unlock(s);
217+
}
218+
208219
/*
209220
* acknowledge interrupt 'irq'
210221
*/

virt/kvm/ioapic.c

+16-3
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,8 @@ static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq)
191191
return kvm_irq_delivery_to_apic(ioapic->kvm, NULL, &irqe);
192192
}
193193

194-
int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level)
194+
int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int irq_source_id,
195+
int level)
195196
{
196197
u32 old_irr;
197198
u32 mask = 1 << irq;
@@ -201,9 +202,11 @@ int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level)
201202
spin_lock(&ioapic->lock);
202203
old_irr = ioapic->irr;
203204
if (irq >= 0 && irq < IOAPIC_NUM_PINS) {
205+
int irq_level = __kvm_irq_line_state(&ioapic->irq_states[irq],
206+
irq_source_id, level);
204207
entry = ioapic->redirtbl[irq];
205-
level ^= entry.fields.polarity;
206-
if (!level)
208+
irq_level ^= entry.fields.polarity;
209+
if (!irq_level)
207210
ioapic->irr &= ~mask;
208211
else {
209212
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)
221224
return ret;
222225
}
223226

227+
void 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+
224237
static void __kvm_ioapic_update_eoi(struct kvm_ioapic *ioapic, int vector,
225238
int trigger_mode)
226239
{

virt/kvm/ioapic.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,9 @@ void kvm_ioapic_update_eoi(struct kvm *kvm, int vector, int trigger_mode);
7474
bool kvm_ioapic_handles_vector(struct kvm *kvm, int vector);
7575
int kvm_ioapic_init(struct kvm *kvm);
7676
void kvm_ioapic_destroy(struct kvm *kvm);
77-
int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level);
77+
int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int irq_source_id,
78+
int level);
79+
void kvm_ioapic_clear_all(struct kvm_ioapic *ioapic, int irq_source_id);
7880
void kvm_ioapic_reset(struct kvm_ioapic *ioapic);
7981
int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src,
8082
struct kvm_lapic_irq *irq);

virt/kvm/irq_comm.c

+4-27
Original file line numberDiff line numberDiff line change
@@ -33,26 +33,12 @@
3333

3434
#include "ioapic.h"
3535

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-
4836
static int kvm_set_pic_irq(struct kvm_kernel_irq_routing_entry *e,
4937
struct kvm *kvm, int irq_source_id, int level)
5038
{
5139
#ifdef CONFIG_X86
5240
struct kvm_pic *pic = pic_irqchip(kvm);
53-
level = kvm_irq_line_state(&pic->irq_states[e->irqchip.pin],
54-
irq_source_id, level);
55-
return kvm_pic_set_irq(pic, e->irqchip.pin, level);
41+
return kvm_pic_set_irq(pic, e->irqchip.pin, irq_source_id, level);
5642
#else
5743
return -1;
5844
#endif
@@ -62,10 +48,7 @@ static int kvm_set_ioapic_irq(struct kvm_kernel_irq_routing_entry *e,
6248
struct kvm *kvm, int irq_source_id, int level)
6349
{
6450
struct kvm_ioapic *ioapic = kvm->arch.vioapic;
65-
level = kvm_irq_line_state(&ioapic->irq_states[e->irqchip.pin],
66-
irq_source_id, level);
67-
68-
return kvm_ioapic_set_irq(ioapic, e->irqchip.pin, level);
51+
return kvm_ioapic_set_irq(ioapic, e->irqchip.pin, irq_source_id, level);
6952
}
7053

7154
inline static bool kvm_is_dm_lowest_prio(struct kvm_lapic_irq *irq)
@@ -249,8 +232,6 @@ int kvm_request_irq_source_id(struct kvm *kvm)
249232

250233
void kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id)
251234
{
252-
int i;
253-
254235
ASSERT(irq_source_id != KVM_USERSPACE_IRQ_SOURCE_ID);
255236

256237
mutex_lock(&kvm->irq_lock);
@@ -263,14 +244,10 @@ void kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id)
263244
if (!irqchip_in_kernel(kvm))
264245
goto unlock;
265246

266-
for (i = 0; i < KVM_IOAPIC_NUM_PINS; i++) {
267-
clear_bit(irq_source_id, &kvm->arch.vioapic->irq_states[i]);
268-
if (i >= 16)
269-
continue;
247+
kvm_ioapic_clear_all(kvm->arch.vioapic, irq_source_id);
270248
#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);
272250
#endif
273-
}
274251
unlock:
275252
mutex_unlock(&kvm->irq_lock);
276253
}

0 commit comments

Comments
 (0)