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

[PATCH v13 25/26] 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 | 40 +++++++++++++++++++++++++++++++++++-----
 1 file changed, 35 insertions(+), 5 deletions(-)

diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index b9d3b2715403..921d834b9682 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -5143,19 +5143,49 @@ 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. In the
+                * absurd case that the projection would take a
+                * CLOCK_REALTIME set to within moments of the 1970 epoch
+                * (legal with CAP_SYS_TIME) below zero, clamp it to zero;
+                * the anchor must still move to master_kernel_ns, from
+                * which the master clock consumers compute system_time,
+                * lest a near-zero data.clock wrap it below zero.
+                */
+               if (ka->use_master_clock) {
+                       u64 delta = now_raw_ns - ka->master_kernel_ns;
+
+                       now_real_ns = now_real_ns > delta ? now_real_ns - delta 
: 0;
+                       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);
 
-- 
2.43.0




 


Rackspace

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