Skip to content

Commit f3cebc7

Browse files
committed
KVM: SVM: Set target pCPU during IRTE update if target vCPU is running
Update the target pCPU for IOMMU doorbells when updating IRTE routing if KVM is actively running the associated vCPU. KVM currently only updates the pCPU when loading the vCPU (via avic_vcpu_load()), and so doorbell events will be delayed until the vCPU goes through a put+load cycle (which might very well "never" happen for the lifetime of the VM). To avoid inserting a stale pCPU, e.g. due to racing between updating IRTE routing and vCPU load/put, get the pCPU information from the vCPU's Physical APIC ID table entry (a.k.a. avic_physical_id_cache in KVM) and update the IRTE while holding ir_list_lock. Add comments with --verbose enabled to explain exactly what is and isn't protected by ir_list_lock. Fixes: 411b44b ("svm: Implements update_pi_irte hook to setup posted interrupt") Reported-by: dengqiao.joey <dengqiao.joey@bytedance.com> Cc: stable@vger.kernel.org Cc: Alejandro Jimenez <alejandro.j.jimenez@oracle.com> Cc: Joao Martins <joao.m.martins@oracle.com> Cc: Maxim Levitsky <mlevitsk@redhat.com> Cc: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com> Tested-by: Alejandro Jimenez <alejandro.j.jimenez@oracle.com> Reviewed-by: Joao Martins <joao.m.martins@oracle.com> Link: https://lore.kernel.org/r/20230808233132.2499764-3-seanjc@google.com Signed-off-by: Sean Christopherson <seanjc@google.com>
1 parent 4c08e73 commit f3cebc7

File tree

1 file changed

+28
-0
lines changed

1 file changed

+28
-0
lines changed

arch/x86/kvm/svm/avic.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -791,6 +791,7 @@ static int svm_ir_list_add(struct vcpu_svm *svm, struct amd_iommu_pi_data *pi)
791791
int ret = 0;
792792
unsigned long flags;
793793
struct amd_svm_iommu_ir *ir;
794+
u64 entry;
794795

795796
/**
796797
* In some cases, the existing irte is updated and re-set,
@@ -824,6 +825,18 @@ static int svm_ir_list_add(struct vcpu_svm *svm, struct amd_iommu_pi_data *pi)
824825
ir->data = pi->ir_data;
825826

826827
spin_lock_irqsave(&svm->ir_list_lock, flags);
828+
829+
/*
830+
* Update the target pCPU for IOMMU doorbells if the vCPU is running.
831+
* If the vCPU is NOT running, i.e. is blocking or scheduled out, KVM
832+
* will update the pCPU info when the vCPU awkened and/or scheduled in.
833+
* See also avic_vcpu_load().
834+
*/
835+
entry = READ_ONCE(*(svm->avic_physical_id_cache));
836+
if (entry & AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK)
837+
amd_iommu_update_ga(entry & AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK,
838+
true, pi->ir_data);
839+
827840
list_add(&ir->node, &svm->ir_list);
828841
spin_unlock_irqrestore(&svm->ir_list_lock, flags);
829842
out:
@@ -1031,6 +1044,13 @@ void avic_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
10311044
if (kvm_vcpu_is_blocking(vcpu))
10321045
return;
10331046

1047+
/*
1048+
* Grab the per-vCPU interrupt remapping lock even if the VM doesn't
1049+
* _currently_ have assigned devices, as that can change. Holding
1050+
* ir_list_lock ensures that either svm_ir_list_add() will consume
1051+
* up-to-date entry information, or that this task will wait until
1052+
* svm_ir_list_add() completes to set the new target pCPU.
1053+
*/
10341054
spin_lock_irqsave(&svm->ir_list_lock, flags);
10351055

10361056
entry = READ_ONCE(*(svm->avic_physical_id_cache));
@@ -1067,6 +1087,14 @@ void avic_vcpu_put(struct kvm_vcpu *vcpu)
10671087
if (!(entry & AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK))
10681088
return;
10691089

1090+
/*
1091+
* Take and hold the per-vCPU interrupt remapping lock while updating
1092+
* the Physical ID entry even though the lock doesn't protect against
1093+
* multiple writers (see above). Holding ir_list_lock ensures that
1094+
* either svm_ir_list_add() will consume up-to-date entry information,
1095+
* or that this task will wait until svm_ir_list_add() completes to
1096+
* mark the vCPU as not running.
1097+
*/
10701098
spin_lock_irqsave(&svm->ir_list_lock, flags);
10711099

10721100
avic_update_iommu_vcpu_affinity(vcpu, -1, 0);

0 commit comments

Comments
 (0)