Skip to content
  • Joao Martins's avatar
    KVM: VMX: Do not change PID.NDST when loading a blocked vCPU · 132194ff
    Joao Martins authored
    When vCPU enters block phase, pi_pre_block() inserts vCPU to a per pCPU
    linked list of all vCPUs that are blocked on this pCPU. Afterwards, it
    changes PID.NV to POSTED_INTR_WAKEUP_VECTOR which its handler
    (wakeup_handler()) is responsible to kick (unblock) any vCPU on that
    linked list that now has pending posted interrupts.
    
    While vCPU is blocked (in kvm_vcpu_block()), it may be preempted which
    will cause vmx_vcpu_pi_put() to set PID.SN.  If later the vCPU will be
    scheduled to run on a different pCPU, vmx_vcpu_pi_load() will clear
    PID.SN but will also *overwrite PID.NDST to this different pCPU*.
    Instead of keeping it with original pCPU which vCPU had entered block
    phase on.
    
    This results in an issue because when a posted interrupt is delivered, as
    the wakeup_handler() will be executed and fail to find blocked vCPU on
    its per pCPU linked list of all vCPUs that are blocked on this pCPU.
    Which is due to the vCPU being placed on a *different* per pCPU
    linked list i.e. the original pCPU in which it entered block phase.
    
    The regression is introduced by commit c112b5f5 ("KVM: x86:
    Recompute PID.ON when clearing PID.SN"). Therefore, partially revert
    it and reintroduce the condition in vmx_vcpu_pi_load() responsible for
    avoiding changing PID.NDST when loading a blocked vCPU.
    
    Fixes: c112b5f5
    
     ("KVM: x86: Recompute PID.ON when clearing PID.SN")
    Tested-by: default avatarNathan Ni <nathan.ni@oracle.com>
    Co-developed-by: default avatarLiran Alon <liran.alon@oracle.com>
    Signed-off-by: default avatarLiran Alon <liran.alon@oracle.com>
    Signed-off-by: default avatarJoao Martins <joao.m.martins@oracle.com>
    Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
    132194ff