|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v11 22/23] KVM: x86/xen: Drop open-coded fallback clock read in kvm_xen_start_timer()
From: David Woodhouse <dwmw@xxxxxxxxxxxx>
When no coherent (CLOCK_MONOTONIC, TSC) pair was available,
kvm_xen_start_timer() computed one from separate ktime_get() and
rdtsc() calls rather than using get_kvmclock_ns(), with a comment
explaining that the latter had a systemic error from scaling host TSC
directly to nanoseconds instead of scaling to the guest TSC first.
Commit abdef42276d8 ("KVM: x86: Fix KVM clock precision in
get_kvmclock() with TSC scaling") removed that systemic error: in
master clock mode, get_kvmclock_ns() now scales the host TSC delta to
the guest TSC and converts it with the guest's own mul/shift,
computing precisely what the guest would.
The fallback is also nearly unreachable. It sits behind the
use_master_clock check, so on 32-bit (where the master clock is never
active) it is dead code, and on 64-bit kvm_get_monotonic_and_clockread()
can only fail there if the host clocksource changed after the last
master clock update, in the window before the resulting masterclock
update is processed. In exactly that window get_kvmclock_ns() takes
its raw-clock fallback path rather than the guest TSC computation,
which is continuous with the last valid snapshot and tolerable for
the one timer that can be started before the pending masterclock
update lands.
Drop it and fall back to the existing get_kvmclock_ns() path.
Signed-off-by: David Woodhouse <dwmw@xxxxxxxxxxxx>
---
arch/x86/kvm/xen.c | 40 +++++++++++++++++++---------------------
1 file changed, 19 insertions(+), 21 deletions(-)
diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c
index 6aa00f746cba..dbac3d2c04d7 100644
--- a/arch/x86/kvm/xen.c
+++ b/arch/x86/kvm/xen.c
@@ -230,22 +230,19 @@ static void kvm_xen_start_timer(struct kvm_vcpu *vcpu,
u64 guest_abs,
if (r)
break;
+ /*
+ * With use_master_clock set, the clocksource was TSC-based
+ * when the master clock was last updated. The clockread can
+ * only fail here if the clocksource has changed since, in
+ * which case a masterclock update is already pending and
+ * get_kvmclock_ns() returns the raw-clock fallback value —
+ * continuous with the last valid snapshot, which is as good
+ * as it gets in that transient window.
+ */
if (!IS_ENABLED(CONFIG_64BIT) ||
!kvm_get_monotonic_and_clockread(&kernel_now, &host_tsc)) {
- /*
- * Don't fall back to get_kvmclock_ns() because it's
- * broken; it has a systemic error in its results
- * because it scales directly from host TSC to
- * nanoseconds, and doesn't scale first to guest TSC
- * and *then* to nanoseconds as the guest does.
- *
- * There is a small error introduced here because time
- * continues to elapse between the ktime_get() and the
- * subsequent rdtsc(). But not the systemic drift due
- * to get_kvmclock_ns().
- */
- kernel_now = ktime_get(); /* This is CLOCK_MONOTONIC */
- host_tsc = rdtsc();
+ r = -EOPNOTSUPP;
+ break;
}
/* Calculate the guest kvmclock as the guest would do it. */
@@ -255,18 +252,19 @@ static void kvm_xen_start_timer(struct kvm_vcpu *vcpu,
u64 guest_abs,
if (r) {
/*
- * Without CONSTANT_TSC, get_kvmclock_ns() is the only option.
+ * Without CONSTANT_TSC and the master clock,
+ * get_kvmclock_ns() is the only option.
*
* Also if the guest PV clock hasn't been set up yet, as is
* likely to be the case during migration when the vCPU has
* not been run yet. It would be possible to calculate the
* scaling factors properly in that case but there's not much
- * point in doing so. The get_kvmclock_ns() drift accumulates
- * over time, so it's OK to use it at startup. Besides, on
- * migration there's going to be a little bit of skew in the
- * precise moment at which timers fire anyway. Often they'll
- * be in the "past" by the time the VM is running again after
- * migration.
+ * point in doing so. Without the master clock, the
+ * get_kvmclock_ns() drift accumulates over time, so it's OK
+ * to use it at startup. Besides, on migration there's going
+ * to be a little bit of skew in the precise moment at which
+ * timers fire anyway. Often they'll be in the "past" by the
+ * time the VM is running again after migration.
*/
guest_now = get_kvmclock_ns(vcpu->kvm);
kernel_now = ktime_get();
--
2.43.0
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |