• Wanpeng Li's avatar
    KVM: X86: Fix preempt the preemption timer cancel · 5acc1ca4
    Wanpeng Li authored
    Preemption can occur during cancel preemption timer, and there will be
    inconsistent status in lapic, vmx and vmcs field.
    
              CPU0                    CPU1
    
      preemption timer vmexit
      handle_preemption_timer(vCPU0)
        kvm_lapic_expired_hv_timer
          vmx_cancel_hv_timer
            vmx->hv_deadline_tsc = -1
            vmcs_clear_bits
            /* hv_timer_in_use still true */
      sched_out
                               sched_in
                               kvm_arch_vcpu_load
                                 vmx_set_hv_timer
                                   write vmx->hv_deadline_tsc
                                   vmcs_set_bits
                               /* back in kvm_lapic_expired_hv_timer */
                               hv_timer_in_use = false
                               ...
                               vmx_vcpu_run
                                 vmx_arm_hv_run
                                   write preemption timer deadline
                                 spurious preemption timer vmexit
                                   handle_preemption_timer(vCPU0)
                                     kvm_lapic_expired_hv_timer
                                       WARN_ON(!apic->lapic_timer.hv_timer_in_use);
    
    This can be reproduced sporadically during boot of L2 on a
    preemptible L1, causing a splat on L1.
    
     WARNING: CPU: 3 PID: 1952 at arch/x86/kvm/lapic.c:1529 kvm_lapic_expired_hv_timer+0xb5/0xd0 [kvm]
     CPU: 3 PID: 1952 Comm: qemu-system-x86 Not tainted 4.12.0-rc1+ #24 RIP: 0010:kvm_lapic_expired_hv_timer+0xb5/0xd0 [kvm]
      Call Trace:
      handle_preemption_timer+0xe/0x20 [kvm_intel]
      vmx_handle_exit+0xc9/0x15f0 [kvm_intel]
      ? lock_acquire+0xdb/0x250
      ? lock_acquire+0xdb/0x250
      ? kvm_arch_vcpu_ioctl_run+0xdf3/0x1ce0 [kvm]
      kvm_arch_vcpu_ioctl_run+0xe55/0x1ce0 [kvm]
      kvm_vcpu_ioctl+0x384/0x7b0 [kvm]
      ? kvm_vcpu_ioctl+0x384/0x7b0 [kvm]
      ? __fget+0xf3/0x210
      do_vfs_ioctl+0xa4/0x700
      ? __fget+0x114/0x210
      SyS_ioctl+0x79/0x90
      do_syscall_64+0x8f/0x750
      ? trace_hardirqs_on_thunk+0x1a/0x1c
      entry_SYSCALL64_slow_path+0x25/0x25
    
    This patch fixes it by disabling preemption while cancelling
    preemption timer.  This way cancel_hv_timer is atomic with
    respect to kvm_arch_vcpu_load.
    
    Cc: Paolo Bonzini <pbonzini@redhat.com>
    Cc: Radim Krčmář <rkrcmar@redhat.com>
    Signed-off-by: default avatarWanpeng Li <wanpeng.li@hotmail.com>
    Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
    5acc1ca4
lapic.c 62.4 KB