[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v11 23/23] KVM: x86: Use a single time snapshot in kvm_vm_ioctl_set_clock()



From: David Woodhouse <dwmw@xxxxxxxxxxxx>

The KVM_CLOCK_REALTIME handling read CLOCK_REALTIME with
ktime_get_real_ns() and then anchored the result at a different
instant: the master clock reference point captured a few lines
earlier, or a separate get_kvmclock_base_ns() read. The time elapsed
between the two reads is added to the restored clock as error --
bounded by the interrupts-off critical section, but gratuitous now
that the timekeeping core can snapshot CLOCK_REALTIME and
CLOCK_MONOTONIC_RAW at the same instant.

Take one ktime_get_snapshot_id(CLOCK_REALTIME) snapshot and derive
both the realtime correction and the raw reference point from it. In
master clock mode, keep anchoring at master_kernel_ns -- so that
'system_time' cannot go negative for a very small data.clock, as the
existing comment explains -- by projecting the snapshot's realtime
value back to that reference point; CLOCK_REALTIME and
CLOCK_MONOTONIC_RAW tick at the same rate across the few ns in
between, give or take NTP slew.

Signed-off-by: David Woodhouse <dwmw@xxxxxxxxxxxx>
---
 arch/x86/kvm/x86.c | 32 +++++++++++++++++++++++++++-----
 1 file changed, 27 insertions(+), 5 deletions(-)

diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 17544b3cc035..4db0c809d120 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -4693,19 +4693,41 @@ static int kvm_vm_ioctl_set_clock(struct kvm *kvm, void 
__user *argp)
         * 'system_time' when 'data.clock' is very small.
         */
        if (data.flags & KVM_CLOCK_REALTIME) {
-               u64 now_real_ns = ktime_get_real_ns();
+               struct system_time_snapshot snap = {};
+               u64 now_real_ns;
+
+               /*
+                * Snapshot CLOCK_REALTIME and CLOCK_MONOTONIC_RAW at the
+                * same instant, so that the elapsed time applied to
+                * data.clock and the reference point the result is anchored
+                * to are coherent.
+                */
+               ktime_get_snapshot_id(CLOCK_REALTIME, &snap);
+               now_real_ns = ktime_to_ns(snap.systime);
+               now_raw_ns = ktime_to_ns(ktime_mono_to_any(snap.monoraw,
+                                                          TK_OFFS_BOOT));
+
+               /*
+                * When the master clock is in use, anchor at its reference
+                * point instead, projecting the realtime value back to the
+                * same instant. The two clocks tick at the same rate across
+                * the few ns in between, give or take NTP slew.
+                */
+               if (ka->use_master_clock) {
+                       now_real_ns -= now_raw_ns - ka->master_kernel_ns;
+                       now_raw_ns = ka->master_kernel_ns;
+               }
 
                /*
                 * Avoid stepping the kvmclock backwards.
                 */
                if (now_real_ns > data.realtime)
                        data.clock += now_real_ns - data.realtime;
-       }
-
-       if (ka->use_master_clock)
+       } else if (ka->use_master_clock) {
                now_raw_ns = ka->master_kernel_ns;
-       else
+       } else {
                now_raw_ns = get_kvmclock_base_ns();
+       }
        ka->kvmclock_offset = data.clock - now_raw_ns;
        kvm_end_pvclock_update(kvm);
        return 0;
-- 
2.43.0




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.