From: David Woodhouse <[email protected]>

KVM_SET_TSC_KHZ changes the vCPU's TSC scaling ratio but does not
update the VM-wide cur_tsc_scaling_ratio used by get_kvmclock().
This causes get_kvmclock() to use a stale (default 1:1) ratio when
computing the KVM clock, leading to drift between the host-side
kvmclock and what the guest observes.

Fix this by calling kvm_synchronize_tsc() after changing the TSC
frequency. This:
 - Updates cur_tsc_scaling_ratio (consumed by pvclock_update_vm_gtod_copy)
 - Ensures the TSC value is continuous across the frequency change
 - Triggers kvm_track_tsc_matching() for proper masterclock handling
 - Allows subsequent vCPUs to synchronize via the 1-second slop hack

Signed-off-by: David Woodhouse <[email protected]>
---
 arch/x86/kvm/x86.c | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 80fe69974ded..37a768b2fe16 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -206,6 +206,7 @@ module_param(mitigate_smt_rsb, bool, 0444);
 #ifdef CONFIG_X86_64
 static bool kvm_get_time_and_clockread(s64 *kernel_ns, u64 *tsc_timestamp);
 #endif
+static void kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 *user_value);
 #define KVM_MAX_NR_USER_RETURN_MSRS 16
 
 struct kvm_user_return_msrs {
@@ -2584,6 +2585,7 @@ static int kvm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 
user_tsc_khz)
 {
        u32 thresh_lo, thresh_hi;
        int use_scaling = 0;
+       u64 tsc;
 
        /* tsc_khz can be zero if TSC calibration fails */
        if (user_tsc_khz == 0) {
@@ -2611,7 +2613,17 @@ static int kvm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 
user_tsc_khz)
                         user_tsc_khz, thresh_lo, thresh_hi);
                use_scaling = 1;
        }
-       return set_tsc_khz(vcpu, user_tsc_khz, use_scaling);
+       /*
+        * Read the guest TSC before changing the ratio, so we can
+        * re-synchronize to preserve continuity across the change.
+        */
+       tsc = kvm_read_l1_tsc(vcpu, rdtsc());
+
+       if (set_tsc_khz(vcpu, user_tsc_khz, use_scaling))
+               return -1;
+
+       kvm_synchronize_tsc(vcpu, &tsc);
+       return 0;
 }
 
 static u64 compute_guest_tsc(struct kvm_vcpu *vcpu, s64 kernel_ns)
-- 
2.54.0


Reply via email to