diff options
author | Marcelo Tosatti <mtosatti@redhat.com> | 2008-06-06 15:37:36 -0400 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2008-06-24 05:16:59 -0400 |
commit | 06e05645661211b9eaadaf6344c335d2e80f0ba2 (patch) | |
tree | 8846d2a5052aec44141e811c0a76fdb39c2e77ca | |
parent | d4acf7e7abe45457e751525a2a4d5b693dfdd597 (diff) |
KVM: close timer injection race window in __vcpu_run
If a timer fires after kvm_inject_pending_timer_irqs() but before
local_irq_disable() the code will enter guest mode and only inject such
timer interrupt the next time an unrelated event causes an exit.
It would be simpler if the timer->pending irq conversion could be done
with IRQ's disabled, so that the above problem cannot happen.
For now introduce a new vcpu requests bit to cancel guest entry.
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: Avi Kivity <avi@qumranet.com>
-rw-r--r-- | arch/x86/kvm/i8254.c | 9 | ||||
-rw-r--r-- | arch/x86/kvm/lapic.c | 1 | ||||
-rw-r--r-- | arch/x86/kvm/x86.c | 1 | ||||
-rw-r--r-- | include/linux/kvm_host.h | 1 |
4 files changed, 9 insertions, 3 deletions
diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c index f2f5d260874e..3829aa7b663f 100644 --- a/arch/x86/kvm/i8254.c +++ b/arch/x86/kvm/i8254.c | |||
@@ -200,9 +200,12 @@ int __pit_timer_fn(struct kvm_kpit_state *ps) | |||
200 | 200 | ||
201 | atomic_inc(&pt->pending); | 201 | atomic_inc(&pt->pending); |
202 | smp_mb__after_atomic_inc(); | 202 | smp_mb__after_atomic_inc(); |
203 | if (vcpu0 && waitqueue_active(&vcpu0->wq)) { | 203 | if (vcpu0) { |
204 | vcpu0->arch.mp_state = KVM_MP_STATE_RUNNABLE; | 204 | set_bit(KVM_REQ_PENDING_TIMER, &vcpu0->requests); |
205 | wake_up_interruptible(&vcpu0->wq); | 205 | if (waitqueue_active(&vcpu0->wq)) { |
206 | vcpu0->arch.mp_state = KVM_MP_STATE_RUNNABLE; | ||
207 | wake_up_interruptible(&vcpu0->wq); | ||
208 | } | ||
206 | } | 209 | } |
207 | 210 | ||
208 | pt->timer.expires = ktime_add_ns(pt->timer.expires, pt->period); | 211 | pt->timer.expires = ktime_add_ns(pt->timer.expires, pt->period); |
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index c297c50eba63..ebc03f5ae162 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c | |||
@@ -940,6 +940,7 @@ static int __apic_timer_fn(struct kvm_lapic *apic) | |||
940 | wait_queue_head_t *q = &apic->vcpu->wq; | 940 | wait_queue_head_t *q = &apic->vcpu->wq; |
941 | 941 | ||
942 | atomic_inc(&apic->timer.pending); | 942 | atomic_inc(&apic->timer.pending); |
943 | set_bit(KVM_REQ_PENDING_TIMER, &apic->vcpu->requests); | ||
943 | if (waitqueue_active(q)) { | 944 | if (waitqueue_active(q)) { |
944 | apic->vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE; | 945 | apic->vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE; |
945 | wake_up_interruptible(q); | 946 | wake_up_interruptible(q); |
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index b90744a1dc3a..b08812d6b34c 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -2774,6 +2774,7 @@ again: | |||
2774 | } | 2774 | } |
2775 | } | 2775 | } |
2776 | 2776 | ||
2777 | clear_bit(KVM_REQ_PENDING_TIMER, &vcpu->requests); | ||
2777 | kvm_inject_pending_timer_irqs(vcpu); | 2778 | kvm_inject_pending_timer_irqs(vcpu); |
2778 | 2779 | ||
2779 | preempt_disable(); | 2780 | preempt_disable(); |
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 092b1b25291d..de9d1df4bba2 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h | |||
@@ -33,6 +33,7 @@ | |||
33 | #define KVM_REQ_REPORT_TPR_ACCESS 2 | 33 | #define KVM_REQ_REPORT_TPR_ACCESS 2 |
34 | #define KVM_REQ_MMU_RELOAD 3 | 34 | #define KVM_REQ_MMU_RELOAD 3 |
35 | #define KVM_REQ_TRIPLE_FAULT 4 | 35 | #define KVM_REQ_TRIPLE_FAULT 4 |
36 | #define KVM_REQ_PENDING_TIMER 5 | ||
36 | 37 | ||
37 | struct kvm_vcpu; | 38 | struct kvm_vcpu; |
38 | extern struct kmem_cache *kvm_vcpu_cache; | 39 | extern struct kmem_cache *kvm_vcpu_cache; |