Skip to content

Commit a248602

Browse files
matosattibonzini
authored andcommitted
KVM: VMX: update vcpu posted-interrupt descriptor when assigning device
For VMX, when a vcpu enters HLT emulation, pi_post_block will: 1) Add vcpu to per-cpu list of blocked vcpus. 2) Program the posted-interrupt descriptor "notification vector" to POSTED_INTR_WAKEUP_VECTOR With interrupt remapping, an interrupt will set the PIR bit for the vector programmed for the device on the CPU, test-and-set the ON bit on the posted interrupt descriptor, and if the ON bit is clear generate an interrupt for the notification vector. This way, the target CPU wakes upon a device interrupt and wakes up the target vcpu. Problem is that pi_post_block only programs the notification vector if kvm_arch_has_assigned_device() is true. Its possible for the following to happen: 1) vcpu V HLTs on pcpu P, kvm_arch_has_assigned_device is false, notification vector is not programmed 2) device is assigned to VM 3) device interrupts vcpu V, sets ON bit (notification vector not programmed, so pcpu P remains in idle) 4) vcpu 0 IPIs vcpu V (in guest), but since pi descriptor ON bit is set, kvm_vcpu_kick is skipped 5) vcpu 0 busy spins on vcpu V's response for several seconds, until RCU watchdog NMIs all vCPUs. To fix this, use the start_assignment kvm_x86_ops callback to kick vcpus out of the halt loop, so the notification vector is properly reprogrammed to the wakeup vector. Reported-by: Pei Zhang <[email protected]> Signed-off-by: Marcelo Tosatti <[email protected]> Message-Id: <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent 084071d commit a248602

File tree

4 files changed

+17
-0
lines changed

4 files changed

+17
-0
lines changed

arch/x86/kvm/vmx/posted_intr.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,20 @@ bool pi_has_pending_interrupt(struct kvm_vcpu *vcpu)
237237
}
238238

239239

240+
/*
241+
* Bail out of the block loop if the VM has an assigned
242+
* device, but the blocking vCPU didn't reconfigure the
243+
* PI.NV to the wakeup vector, i.e. the assigned device
244+
* came along after the initial check in pi_pre_block().
245+
*/
246+
void vmx_pi_start_assignment(struct kvm *kvm)
247+
{
248+
if (!irq_remapping_cap(IRQ_POSTING_CAP))
249+
return;
250+
251+
kvm_make_all_cpus_request(kvm, KVM_REQ_UNBLOCK);
252+
}
253+
240254
/*
241255
* pi_update_irte - set IRTE for Posted-Interrupts
242256
*

arch/x86/kvm/vmx/posted_intr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,5 +95,6 @@ void __init pi_init_cpu(int cpu);
9595
bool pi_has_pending_interrupt(struct kvm_vcpu *vcpu);
9696
int pi_update_irte(struct kvm *kvm, unsigned int host_irq, uint32_t guest_irq,
9797
bool set);
98+
void vmx_pi_start_assignment(struct kvm *kvm);
9899

99100
#endif /* __KVM_X86_VMX_POSTED_INTR_H */

arch/x86/kvm/vmx/vmx.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7721,6 +7721,7 @@ static struct kvm_x86_ops vmx_x86_ops __initdata = {
77217721
.nested_ops = &vmx_nested_ops,
77227722

77237723
.update_pi_irte = pi_update_irte,
7724+
.start_assignment = vmx_pi_start_assignment,
77247725

77257726
#ifdef CONFIG_X86_64
77267727
.set_hv_timer = vmx_set_hv_timer,

virt/kvm/kvm_main.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,7 @@ bool kvm_make_all_cpus_request(struct kvm *kvm, unsigned int req)
307307
{
308308
return kvm_make_all_cpus_request_except(kvm, req, NULL);
309309
}
310+
EXPORT_SYMBOL_GPL(kvm_make_all_cpus_request);
310311

311312
#ifndef CONFIG_HAVE_KVM_ARCH_TLB_FLUSH_ALL
312313
void kvm_flush_remote_tlbs(struct kvm *kvm)

0 commit comments

Comments
 (0)