diff options
author | Marcelo Tosatti <mtosatti@redhat.com> | 2008-04-11 14:01:22 -0400 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2008-04-27 11:21:32 -0400 |
commit | e9571ed54b2a290d61b98ad6f369f963159fe6da (patch) | |
tree | 8767ba834196c08da817e545542ff5a681df96e8 /arch | |
parent | 62d9f0dbc92d7e398fde53fc6021338393522e68 (diff) |
KVM: fix kvm_vcpu_kick vs __vcpu_run race
There is a window open between testing of pending IRQ's
and assignment of guest_mode in __vcpu_run.
Injection of IRQ's can race with __vcpu_run as follows:
CPU0 CPU1
kvm_x86_ops->run()
vcpu->guest_mode = 0 SET_IRQ_LINE ioctl
..
kvm_x86_ops->inject_pending_irq
kvm_cpu_has_interrupt()
apic_test_and_set_irr()
kvm_vcpu_kick
if (vcpu->guest_mode)
send_ipi()
vcpu->guest_mode = 1
So move guest_mode=1 assignment before ->inject_pending_irq, and make
sure that it won't reorder after it.
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/kvm/x86.c | 16 |
1 files changed, 14 insertions, 2 deletions
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 5c3c9d38c780..0ce556372a4d 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -2802,6 +2802,13 @@ again: | |||
2802 | goto out; | 2802 | goto out; |
2803 | } | 2803 | } |
2804 | 2804 | ||
2805 | vcpu->guest_mode = 1; | ||
2806 | /* | ||
2807 | * Make sure that guest_mode assignment won't happen after | ||
2808 | * testing the pending IRQ vector bitmap. | ||
2809 | */ | ||
2810 | smp_wmb(); | ||
2811 | |||
2805 | if (vcpu->arch.exception.pending) | 2812 | if (vcpu->arch.exception.pending) |
2806 | __queue_exception(vcpu); | 2813 | __queue_exception(vcpu); |
2807 | else if (irqchip_in_kernel(vcpu->kvm)) | 2814 | else if (irqchip_in_kernel(vcpu->kvm)) |
@@ -2813,7 +2820,6 @@ again: | |||
2813 | 2820 | ||
2814 | up_read(&vcpu->kvm->slots_lock); | 2821 | up_read(&vcpu->kvm->slots_lock); |
2815 | 2822 | ||
2816 | vcpu->guest_mode = 1; | ||
2817 | kvm_guest_enter(); | 2823 | kvm_guest_enter(); |
2818 | 2824 | ||
2819 | if (vcpu->requests) | 2825 | if (vcpu->requests) |
@@ -3970,11 +3976,17 @@ static void vcpu_kick_intr(void *info) | |||
3970 | void kvm_vcpu_kick(struct kvm_vcpu *vcpu) | 3976 | void kvm_vcpu_kick(struct kvm_vcpu *vcpu) |
3971 | { | 3977 | { |
3972 | int ipi_pcpu = vcpu->cpu; | 3978 | int ipi_pcpu = vcpu->cpu; |
3979 | int cpu = get_cpu(); | ||
3973 | 3980 | ||
3974 | if (waitqueue_active(&vcpu->wq)) { | 3981 | if (waitqueue_active(&vcpu->wq)) { |
3975 | wake_up_interruptible(&vcpu->wq); | 3982 | wake_up_interruptible(&vcpu->wq); |
3976 | ++vcpu->stat.halt_wakeup; | 3983 | ++vcpu->stat.halt_wakeup; |
3977 | } | 3984 | } |
3978 | if (vcpu->guest_mode) | 3985 | /* |
3986 | * We may be called synchronously with irqs disabled in guest mode, | ||
3987 | * So need not to call smp_call_function_single() in that case. | ||
3988 | */ | ||
3989 | if (vcpu->guest_mode && vcpu->cpu != cpu) | ||
3979 | smp_call_function_single(ipi_pcpu, vcpu_kick_intr, vcpu, 0, 0); | 3990 | smp_call_function_single(ipi_pcpu, vcpu_kick_intr, vcpu, 0, 0); |
3991 | put_cpu(); | ||
3980 | } | 3992 | } |