KVM: x86: fix maintaining of kvm_clock stability on guest CPU hotplug
authorDenis Plotnikov <dplotnikov@virtuozzo.com>
Fri, 7 Apr 2017 09:09:53 +0000 (12:09 +0300)
committerRadim Krčmář <rkrcmar@redhat.com>
Wed, 12 Apr 2017 18:17:15 +0000 (20:17 +0200)
VCPU TSC synchronization is perfromed in kvm_write_tsc() when the TSC
value being set is within 1 second from the expected, as obtained by
extrapolating of the TSC in already synchronized VCPUs.

This is naturally achieved on all VCPUs at VM start and resume;
however on VCPU hotplug it is not: the newly added VCPU is created
with TSC == 0 while others are well ahead.

To compensate for that, consider host-initiated kvm_write_tsc() with
TSC == 0 a special case requiring synchronization regardless of the
current TSC on other VCPUs.

Signed-off-by: Denis Plotnikov <dplotnikov@virtuozzo.com>
Reviewed-by: Roman Kagan <rkagan@virtuozzo.com>
Signed-off-by: Radim Krčmář <rkrcmar@redhat.com>
arch/x86/kvm/x86.c

index 422f803..2e4a472 100644 (file)
@@ -1454,16 +1454,25 @@ void kvm_write_tsc(struct kvm_vcpu *vcpu, struct msr_data *msr)
        elapsed = ns - kvm->arch.last_tsc_nsec;
 
        if (vcpu->arch.virtual_tsc_khz) {
-               u64 tsc_exp = kvm->arch.last_tsc_write +
-                                       nsec_to_cycles(vcpu, elapsed);
-               u64 tsc_hz = vcpu->arch.virtual_tsc_khz * 1000LL;
-               /*
-                * Special case: TSC write with a small delta (1 second)
-                * of virtual cycle time against real time is
-                * interpreted as an attempt to synchronize the CPU.
-                */
-               synchronizing = data < tsc_exp + tsc_hz &&
-                               data + tsc_hz > tsc_exp;
+               if (data == 0 && msr->host_initiated) {
+                       /*
+                        * detection of vcpu initialization -- need to sync
+                        * with other vCPUs. This particularly helps to keep
+                        * kvm_clock stable after CPU hotplug
+                        */
+                       synchronizing = true;
+               } else {
+                       u64 tsc_exp = kvm->arch.last_tsc_write +
+                                               nsec_to_cycles(vcpu, elapsed);
+                       u64 tsc_hz = vcpu->arch.virtual_tsc_khz * 1000LL;
+                       /*
+                        * Special case: TSC write with a small delta (1 second)
+                        * of virtual cycle time against real time is
+                        * interpreted as an attempt to synchronize the CPU.
+                        */
+                       synchronizing = data < tsc_exp + tsc_hz &&
+                                       data + tsc_hz > tsc_exp;
+               }
        }
 
        /*