Message ID | 1498209769-5546-1-git-send-email-wanpeng.li@hotmail.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
2017-06-23 17:22 GMT+08:00 Wanpeng Li <kernellwp@gmail.com>: > From: Wanpeng Li <wanpeng.li@hotmail.com> > > Linux as a guest will prevent to program the next event to the clock event > device when the event is in the past. However, it is not guaranteed by all > the guests, the guest like kvm-unit-tests/apic.flat will write current tsc > value visible in guest to MSR_IA32_TSCDEADLINE, lapic timer which is emulated > by vmx preemption timer will program the absolute target tsc value to vmcs > preemption timer field w/ delta == 0, then plays a vmentry and an upcoming > vmx preemption timer fire vmexit dance, the lapic timer injection is delayed > for this duration. Actually the lapic timer which is emulated by hrtimer can > handle this correctly. > > This patch fixes it by firing the lapic timer and injecting a timer interrupt > immediately during the next vmentry if guest programs an expired timer to > the emulated timer device. > > Cc: Paolo Bonzini <pbonzini@redhat.com> > Cc: Radim Krčmář <rkrcmar@redhat.com> > Signed-off-by: Wanpeng Li <wanpeng.li@hotmail.com> > --- > arch/x86/kvm/lapic.c | 6 +++++- > arch/x86/kvm/vmx.c | 3 +++ > 2 files changed, 8 insertions(+), 1 deletion(-) > > diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c > index d24c874..8a1263a 100644 > --- a/arch/x86/kvm/lapic.c > +++ b/arch/x86/kvm/lapic.c > @@ -1504,12 +1504,16 @@ static void cancel_hv_timer(struct kvm_lapic *apic) > static bool start_hv_timer(struct kvm_lapic *apic) > { > u64 tscdeadline = apic->lapic_timer.tscdeadline; > + int ret = 0; > > if ((atomic_read(&apic->lapic_timer.pending) && > !apic_lvtt_period(apic)) || > - kvm_x86_ops->set_hv_timer(apic->vcpu, tscdeadline)) { > + (ret = kvm_x86_ops->set_hv_timer(apic->vcpu, tscdeadline))) { > if (apic->lapic_timer.hv_timer_in_use) > cancel_hv_timer(apic); > + if (ret == 1) > + apic_timer_expired(apic); > + return true; Ouch! I just sent a wrong version. Regards, Wanpeng Li > } else { > apic->lapic_timer.hv_timer_in_use = true; > hrtimer_cancel(&apic->lapic_timer.timer); > diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c > index 2e906cf..2008e9b 100644 > --- a/arch/x86/kvm/vmx.c > +++ b/arch/x86/kvm/vmx.c > @@ -11149,6 +11149,9 @@ static int vmx_set_hv_timer(struct kvm_vcpu *vcpu, u64 guest_deadline_tsc) > u64 guest_tscl = kvm_read_l1_tsc(vcpu, tscl); > u64 delta_tsc = max(guest_deadline_tsc, guest_tscl) - guest_tscl; > > + if (delta_tsc == 0) > + return 1; > + > /* Convert to host delta tsc if tsc scaling is enabled */ > if (vcpu->arch.tsc_scaling_ratio != kvm_default_tsc_scaling_ratio && > u64_shl_div_u64(delta_tsc, > -- > 2.7.4 >
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index d24c874..8a1263a 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -1504,12 +1504,16 @@ static void cancel_hv_timer(struct kvm_lapic *apic) static bool start_hv_timer(struct kvm_lapic *apic) { u64 tscdeadline = apic->lapic_timer.tscdeadline; + int ret = 0; if ((atomic_read(&apic->lapic_timer.pending) && !apic_lvtt_period(apic)) || - kvm_x86_ops->set_hv_timer(apic->vcpu, tscdeadline)) { + (ret = kvm_x86_ops->set_hv_timer(apic->vcpu, tscdeadline))) { if (apic->lapic_timer.hv_timer_in_use) cancel_hv_timer(apic); + if (ret == 1) + apic_timer_expired(apic); + return true; } else { apic->lapic_timer.hv_timer_in_use = true; hrtimer_cancel(&apic->lapic_timer.timer); diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 2e906cf..2008e9b 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -11149,6 +11149,9 @@ static int vmx_set_hv_timer(struct kvm_vcpu *vcpu, u64 guest_deadline_tsc) u64 guest_tscl = kvm_read_l1_tsc(vcpu, tscl); u64 delta_tsc = max(guest_deadline_tsc, guest_tscl) - guest_tscl; + if (delta_tsc == 0) + return 1; + /* Convert to host delta tsc if tsc scaling is enabled */ if (vcpu->arch.tsc_scaling_ratio != kvm_default_tsc_scaling_ratio && u64_shl_div_u64(delta_tsc,