浏览代码

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>
Marcelo Tosatti 17 年之前
父节点
当前提交
06e0564566
共有 4 个文件被更改,包括 9 次插入3 次删除
  1. 6 3
      arch/x86/kvm/i8254.c
  2. 1 0
      arch/x86/kvm/lapic.c
  3. 1 0
      arch/x86/kvm/x86.c
  4. 1 0
      include/linux/kvm_host.h

+ 6 - 3
arch/x86/kvm/i8254.c

@@ -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)) {
-		vcpu0->arch.mp_state = KVM_MP_STATE_RUNNABLE;
-		wake_up_interruptible(&vcpu0->wq);
+	if (vcpu0) {
+		set_bit(KVM_REQ_PENDING_TIMER, &vcpu0->requests);
+		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);

+ 1 - 0
arch/x86/kvm/lapic.c

@@ -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);

+ 1 - 0
arch/x86/kvm/x86.c

@@ -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();

+ 1 - 0
include/linux/kvm_host.h

@@ -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;