Skip to content

Commit c3d591c

Browse files
committed
KVM: SVM: Take and hold ir_list_lock across IRTE updates in IOMMU
Now that svm_ir_list_add() isn't overloaded with all manner of weird things, fold it into avic_pi_update_irte(), and more importantly take ir_list_lock across the irq_set_vcpu_affinity() calls to ensure the info that's shoved into the IRTE is fresh. While preemption (and IRQs) is disabled on the task performing the IRTE update, thanks to irqfds.lock, that task doesn't hold the vCPU's mutex, i.e. preemption being disabled is irrelevant. Link: https://lore.kernel.org/r/20250611224604.313496-40-seanjc@google.com Signed-off-by: Sean Christopherson <seanjc@google.com>
1 parent 71d6b3b commit c3d591c

File tree

1 file changed

+22
-33
lines changed

1 file changed

+22
-33
lines changed

arch/x86/kvm/svm/avic.c

Lines changed: 22 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -770,32 +770,6 @@ static void svm_ir_list_del(struct kvm_kernel_irqfd *irqfd)
770770
spin_unlock_irqrestore(&to_svm(vcpu)->ir_list_lock, flags);
771771
}
772772

773-
static void svm_ir_list_add(struct vcpu_svm *svm,
774-
struct kvm_kernel_irqfd *irqfd,
775-
struct amd_iommu_pi_data *pi)
776-
{
777-
unsigned long flags;
778-
u64 entry;
779-
780-
irqfd->irq_bypass_data = pi->ir_data;
781-
782-
spin_lock_irqsave(&svm->ir_list_lock, flags);
783-
784-
/*
785-
* Update the target pCPU for IOMMU doorbells if the vCPU is running.
786-
* If the vCPU is NOT running, i.e. is blocking or scheduled out, KVM
787-
* will update the pCPU info when the vCPU awkened and/or scheduled in.
788-
* See also avic_vcpu_load().
789-
*/
790-
entry = svm->avic_physical_id_entry;
791-
if (entry & AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK)
792-
amd_iommu_update_ga(entry & AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK,
793-
true, pi->ir_data);
794-
795-
list_add(&irqfd->vcpu_list, &svm->ir_list);
796-
spin_unlock_irqrestore(&svm->ir_list_lock, flags);
797-
}
798-
799773
int avic_pi_update_irte(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,
800774
unsigned int host_irq, uint32_t guest_irq,
801775
struct kvm_vcpu *vcpu, u32 vector)
@@ -824,8 +798,18 @@ int avic_pi_update_irte(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,
824798
.vapic_addr = avic_get_backing_page_address(to_svm(vcpu)),
825799
.vector = vector,
826800
};
801+
struct vcpu_svm *svm = to_svm(vcpu);
802+
u64 entry;
827803
int ret;
828804

805+
/*
806+
* Prevent the vCPU from being scheduled out or migrated until
807+
* the IRTE is updated and its metadata has been added to the
808+
* list of IRQs being posted to the vCPU, to ensure the IRTE
809+
* isn't programmed with stale pCPU/IsRunning information.
810+
*/
811+
guard(spinlock_irqsave)(&svm->ir_list_lock);
812+
829813
ret = irq_set_vcpu_affinity(host_irq, &pi_data);
830814
if (ret)
831815
return ret;
@@ -840,14 +824,19 @@ int avic_pi_update_irte(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,
840824
return -EIO;
841825
}
842826

843-
/**
844-
* Here, we successfully setting up vcpu affinity in
845-
* IOMMU guest mode. Now, we need to store the posted
846-
* interrupt information in a per-vcpu ir_list so that
847-
* we can reference to them directly when we update vcpu
848-
* scheduling information in IOMMU irte.
827+
/*
828+
* Update the target pCPU for IOMMU doorbells if the vCPU is
829+
* running. If the vCPU is NOT running, i.e. is blocking or
830+
* scheduled out, KVM will update the pCPU info when the vCPU
831+
* is awakened and/or scheduled in. See also avic_vcpu_load().
849832
*/
850-
svm_ir_list_add(to_svm(vcpu), irqfd, &pi_data);
833+
entry = svm->avic_physical_id_entry;
834+
if (entry & AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK)
835+
amd_iommu_update_ga(entry & AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK,
836+
true, pi_data.ir_data);
837+
838+
irqfd->irq_bypass_data = pi_data.ir_data;
839+
list_add(&irqfd->vcpu_list, &svm->ir_list);
851840
return 0;
852841
}
853842
return irq_set_vcpu_affinity(host_irq, NULL);

0 commit comments

Comments
 (0)