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>
This commit is contained in:
parent
d4acf7e7ab
commit
06e0564566
@ -200,9 +200,12 @@ int __pit_timer_fn(struct kvm_kpit_state *ps)
|
|||||||
|
|
||||||
atomic_inc(&pt->pending);
|
atomic_inc(&pt->pending);
|
||||||
smp_mb__after_atomic_inc();
|
smp_mb__after_atomic_inc();
|
||||||
if (vcpu0 && waitqueue_active(&vcpu0->wq)) {
|
if (vcpu0) {
|
||||||
vcpu0->arch.mp_state = KVM_MP_STATE_RUNNABLE;
|
set_bit(KVM_REQ_PENDING_TIMER, &vcpu0->requests);
|
||||||
wake_up_interruptible(&vcpu0->wq);
|
if (waitqueue_active(&vcpu0->wq)) {
|
||||||
|
vcpu0->arch.mp_state = KVM_MP_STATE_RUNNABLE;
|
||||||
|
wake_up_interruptible(&vcpu0->wq);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pt->timer.expires = ktime_add_ns(pt->timer.expires, pt->period);
|
pt->timer.expires = ktime_add_ns(pt->timer.expires, pt->period);
|
||||||
|
@ -940,6 +940,7 @@ static int __apic_timer_fn(struct kvm_lapic *apic)
|
|||||||
wait_queue_head_t *q = &apic->vcpu->wq;
|
wait_queue_head_t *q = &apic->vcpu->wq;
|
||||||
|
|
||||||
atomic_inc(&apic->timer.pending);
|
atomic_inc(&apic->timer.pending);
|
||||||
|
set_bit(KVM_REQ_PENDING_TIMER, &apic->vcpu->requests);
|
||||||
if (waitqueue_active(q)) {
|
if (waitqueue_active(q)) {
|
||||||
apic->vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
|
apic->vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
|
||||||
wake_up_interruptible(q);
|
wake_up_interruptible(q);
|
||||||
|
@ -2774,6 +2774,7 @@ again:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clear_bit(KVM_REQ_PENDING_TIMER, &vcpu->requests);
|
||||||
kvm_inject_pending_timer_irqs(vcpu);
|
kvm_inject_pending_timer_irqs(vcpu);
|
||||||
|
|
||||||
preempt_disable();
|
preempt_disable();
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
#define KVM_REQ_REPORT_TPR_ACCESS 2
|
#define KVM_REQ_REPORT_TPR_ACCESS 2
|
||||||
#define KVM_REQ_MMU_RELOAD 3
|
#define KVM_REQ_MMU_RELOAD 3
|
||||||
#define KVM_REQ_TRIPLE_FAULT 4
|
#define KVM_REQ_TRIPLE_FAULT 4
|
||||||
|
#define KVM_REQ_PENDING_TIMER 5
|
||||||
|
|
||||||
struct kvm_vcpu;
|
struct kvm_vcpu;
|
||||||
extern struct kmem_cache *kvm_vcpu_cache;
|
extern struct kmem_cache *kvm_vcpu_cache;
|
||||||
|
Loading…
Reference in New Issue
Block a user