KVM: x86: workaround SuSE's 2.6.16 pvclock vs masterclock issue
authorMarcelo Tosatti <mtosatti@redhat.com>
Tue, 20 Jan 2015 17:54:52 +0000 (15:54 -0200)
committerPaolo Bonzini <pbonzini@redhat.com>
Tue, 20 Jan 2015 19:38:39 +0000 (20:38 +0100)
SuSE's 2.6.16 kernel fails to boot if the delta between tsc_timestamp
and rdtsc is larger than a given threshold:

 * If we get more than the below threshold into the future, we rerequest
 * the real time from the host again which has only little offset then
 * that we need to adjust using the TSC.
 *
 * For now that threshold is 1/5th of a jiffie. That should be good
 * enough accuracy for completely broken systems, but also give us swing
 * to not call out to the host all the time.
 */
#define PVCLOCK_DELTA_MAX ((1000000000ULL / HZ) / 5)

Disable masterclock support (which increases said delta) in case the
boot vcpu does not use MSR_KVM_SYSTEM_TIME_NEW.

Upstreams kernels which support pvclock vsyscalls (and therefore make
use of PVCLOCK_STABLE_BIT) use MSR_KVM_SYSTEM_TIME_NEW.

Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/include/asm/kvm_host.h
arch/x86/kvm/x86.c

index 97a5dd0222c850c04629b7a4a79a8240fa80c0e1..177b2f2ff9fbb3a23c6a50a23353ef92ff872566 100644 (file)
@@ -627,6 +627,8 @@ struct kvm_arch {
        #ifdef CONFIG_KVM_MMU_AUDIT
        int audit_point;
        #endif
+
+       bool boot_vcpu_runs_old_kvmclock;
 };
 
 struct kvm_vm_stat {
index dcb996bfafa4dec0e40e550ec473fd2a261a9b7c..917672f8034ac948b0ff7436b041b803e79f9eeb 100644 (file)
@@ -1542,7 +1542,8 @@ static void pvclock_update_vm_gtod_copy(struct kvm *kvm)
                                        &ka->master_cycle_now);
 
        ka->use_master_clock = host_tsc_clocksource && vcpus_matched
-                               && !backwards_tsc_observed;
+                               && !backwards_tsc_observed
+                               && !ka->boot_vcpu_runs_old_kvmclock;
 
        if (ka->use_master_clock)
                atomic_set(&kvm_guest_has_master_clock, 1);
@@ -2174,8 +2175,20 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
        case MSR_KVM_SYSTEM_TIME_NEW:
        case MSR_KVM_SYSTEM_TIME: {
                u64 gpa_offset;
+               struct kvm_arch *ka = &vcpu->kvm->arch;
+
                kvmclock_reset(vcpu);
 
+               if (vcpu->vcpu_id == 0 && !msr_info->host_initiated) {
+                       bool tmp = (msr == MSR_KVM_SYSTEM_TIME);
+
+                       if (ka->boot_vcpu_runs_old_kvmclock != tmp)
+                               set_bit(KVM_REQ_MASTERCLOCK_UPDATE,
+                                       &vcpu->requests);
+
+                       ka->boot_vcpu_runs_old_kvmclock = tmp;
+               }
+
                vcpu->arch.time = data;
                kvm_make_request(KVM_REQ_GLOBAL_CLOCK_UPDATE, vcpu);