Certain clocks (such as TSC) in older 2.6 guests overaccount for lost ticks, causing severe time drift. Interrupt reinjection magnifies the problem.
Provide an option to disable it. Signed-off-by: Marcelo Tosatti <mtosa...@redhat.com> Index: kvm/arch/x86/kvm/i8254.c =================================================================== --- kvm.orig/arch/x86/kvm/i8254.c +++ kvm/arch/x86/kvm/i8254.c @@ -201,6 +201,9 @@ static int __pit_timer_fn(struct kvm_kpi if (!atomic_inc_and_test(&pt->pending)) set_bit(KVM_REQ_PENDING_TIMER, &vcpu0->requests); + if (!pt->reinject) + atomic_set(&pt->pending, 1); + if (vcpu0 && waitqueue_active(&vcpu0->wq)) wake_up_interruptible(&vcpu0->wq); @@ -580,6 +583,7 @@ struct kvm_pit *kvm_create_pit(struct kv pit_state->irq_ack_notifier.gsi = 0; pit_state->irq_ack_notifier.irq_acked = kvm_pit_ack_irq; kvm_register_irq_ack_notifier(kvm, &pit_state->irq_ack_notifier); + pit_state->pit_timer.reinject = true; mutex_unlock(&pit->pit_state.lock); kvm_pit_reset(pit); Index: kvm/arch/x86/kvm/i8254.h =================================================================== --- kvm.orig/arch/x86/kvm/i8254.h +++ kvm/arch/x86/kvm/i8254.h @@ -9,6 +9,7 @@ struct kvm_kpit_timer { s64 period; /* unit: ns */ s64 scheduled; atomic_t pending; + bool reinject; }; struct kvm_kpit_channel_state { Index: kvm/arch/x86/kvm/x86.c =================================================================== --- kvm.orig/arch/x86/kvm/x86.c +++ kvm/arch/x86/kvm/x86.c @@ -991,6 +991,7 @@ int kvm_dev_ioctl_check_extension(long e case KVM_CAP_NOP_IO_DELAY: case KVM_CAP_MP_STATE: case KVM_CAP_SYNC_MMU: + case KVM_CAP_PIT_REINJECT_CONTROL: r = 1; break; case KVM_CAP_COALESCED_MMIO: @@ -1723,6 +1724,13 @@ static int kvm_vm_ioctl_set_pit(struct k return r; } +static int kvm_vm_ioctl_pit_reinject(struct kvm *kvm, + struct kvm_pit_reinject_control *control) +{ + kvm->arch.vpit->pit_state.pit_timer.reinject = control->reinject; + return 0; +} + /* * Get (and clear) the dirty memory log for a memory slot. */ @@ -1920,6 +1928,20 @@ long kvm_arch_vm_ioctl(struct file *filp r = 0; break; } + case KVM_PIT_REINJECT_CONTROL: { + struct kvm_pit_reinject_control control; + r = -EFAULT; + if (copy_from_user(&control, argp, sizeof(control))) + goto out; + r = -ENXIO; + if (!kvm->arch.vpit) + goto out; + r = kvm_vm_ioctl_pit_reinject(kvm, &control); + if (r) + goto out; + r = 0; + break; + } default: ; } Index: kvm/include/linux/kvm.h =================================================================== --- kvm.orig/include/linux/kvm.h +++ kvm/include/linux/kvm.h @@ -396,6 +396,9 @@ struct kvm_trace_rec { #if defined(CONFIG_X86) #define KVM_CAP_SET_GUEST_DEBUG 23 #endif +#if defined(CONFIG_X86) +#define KVM_CAP_PIT_REINJECT_CONTROL 24 +#endif /* * ioctls for VM fds @@ -429,6 +432,7 @@ struct kvm_trace_rec { struct kvm_assigned_pci_dev) #define KVM_ASSIGN_IRQ _IOR(KVMIO, 0x70, \ struct kvm_assigned_irq) +#define KVM_PIT_REINJECT_CONTROL _IO(KVMIO, 0x71) /* * ioctls for vcpu fds Index: kvm/arch/x86/include/asm/kvm.h =================================================================== --- kvm.orig/arch/x86/include/asm/kvm.h +++ kvm/arch/x86/include/asm/kvm.h @@ -226,4 +226,8 @@ struct kvm_guest_debug_arch { struct kvm_pit_state { struct kvm_pit_channel_state channels[3]; }; + +struct kvm_pit_reinject_control { + __u8 reinject; +}; #endif /* _ASM_X86_KVM_H */ -- -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html