diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 1a2da0e..84abb1a 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -1273,7 +1273,6 @@ static void apic_timer_expired(struct kvm_lapic *apic)
{
struct kvm_vcpu *vcpu = apic->vcpu;
struct swait_queue_head *q = &vcpu->wq;
- struct kvm_timer *ktimer = &apic->lapic_timer;
if (atomic_read(&apic->lapic_timer.pending))
return;
@@ -1283,9 +1282,6 @@ static void apic_timer_expired(struct kvm_lapic *apic)
if (swait_active(q))
swake_up(q);
-
- if (apic_lvtt_tscdeadline(apic))
- ktimer->expired_tscdeadline = ktimer->tscdeadline;
}
/*
@@ -1922,12 +1918,15 @@ int kvm_apic_accept_pic_intr(struct kvm_vcpu *vcpu)
void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu)
{
struct kvm_lapic *apic = vcpu->arch.apic;
+ struct kvm_timer *ktimer = &apic->lapic_timer;
- if (atomic_read(&apic->lapic_timer.pending) > 0) {
+ if (atomic_read(&ktimer->pending) > 0) {
kvm_apic_local_deliver(apic, APIC_LVTT);
- if (apic_lvtt_tscdeadline(apic))
- apic->lapic_timer.tscdeadline = 0;
- atomic_set(&apic->lapic_timer.pending, 0);
+ if (apic_lvtt_tscdeadline(apic)) {
+ ktimer->expired_tscdeadline = ktimer->tscdeadline;
+ ktimer->tscdeadline = 0;
+ }
+ atomic_set(&ktimer->pending, 0);
}
}
@@ -2007,6 +2006,71 @@ void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu)
}
/*
+ * kvm_apic_tsc_update - called when guest or host changes the TSC
+ *
+ * Update the emulated TSC deadline timer.
+ *
+ * It is also required if host changes TSC frequency scaling. It is not
+ * required when we "catch up" the TSC, because that is maintaining the
+ * relationship between TSC and real time.
+ */
+void kvm_apic_tsc_update(struct kvm_vcpu *vcpu)
+{
+ struct kvm_lapic *apic = vcpu->arch.apic;
+ struct kvm_timer *ktimer = &apic->lapic_timer;
+
+ if (!lapic_in_kernel(vcpu))
+ return;
+
+ if (!apic_lvtt_tscdeadline(apic))
+ return;
+
+ hrtimer_cancel(&ktimer->timer);
+
+ /*
+ * Handle when guest TSC is adjusted backwards, just after
+ * inject_apic_timer_irqs(). When we hit wait_lapic_expire(), we risk
+ * an extended busy-wait. Because ktimer->expired_tscdeadline will
+ * have receded further into the future.
+ *
+ * The guest does not get a chance to run in this window, but the host
+ * could modify the TSC at this point. This race could happen when
+ * restoring a live snapshot of a VM.
+ *
+ * Just clear the busy-wait. In theory this could cause a wakeup
+ * before the deadline, if the user configured the the busy-wait
+ * feature (lapic_advance_timer_ns). We don't expect this to matter: