possible deadlock due to irq_set_thread_affinity() calling into the scheduler (was Re: [PATCH v3 38/62] KVM: SVM: Take and hold ir_list_lock across IRTE updates in IOMMU)

Paolo Bonzini posted 1 patch 1 month, 2 weeks ago
possible deadlock due to irq_set_thread_affinity() calling into the scheduler (was Re: [PATCH v3 38/62] KVM: SVM: Take and hold ir_list_lock across IRTE updates in IOMMU)
Posted by Paolo Bonzini 1 month, 2 weeks ago
On 12/22/25 10:16, Ankit Soni wrote:
>    ======================================================
>    WARNING: possible circular locking dependency detected
>    6.19.0-rc2 #20 Tainted: G            E
>    ------------------------------------------------------
>    CPU 58/KVM/28597 is trying to acquire lock:
>      ff12c47d4b1f34c0 (&irq_desc_lock_class){-.-.}-{2:2}, at: __irq_get_desc_lock+0x58/0xa0
> 
>      but task is already holding lock:
>      ff12c49b28552110 (&svm->ir_list_lock){....}-{2:2}, at: avic_pi_update_irte+0x147/0x270 [kvm_amd]
> 
>      which lock already depends on the new lock.
> 
>    Chain exists of:
>      &irq_desc_lock_class --> &rq->__lock --> &svm->ir_list_lock
> 
>    Possible unsafe locking scenario:
> 
>          CPU0                            CPU1
>          ----                            ----
>     lock(&svm->ir_list_lock);
>                                        lock(&rq->__lock);
>                                        lock(&svm->ir_list_lock);
>     lock(&irq_desc_lock_class);
> 
>          *** DEADLOCK ***
> 
> So lockdep sees:
> 
>    &irq_desc_lock_class -> &rq->__lock -> &svm->ir_list_lock
> 
> while avic_pi_update_irte() currently holds svm->ir_list_lock and then
> takes irq_desc_lock via irq_set_vcpu_affinity(), which creates the
> potential inversion.
> 
>    - Is this lockdep warning expected/benign in this code path, or does it
>      indicate a real potential deadlock between svm->ir_list_lock and
>      irq_desc_lock with AVIC + irq_bypass + VFIO?

I'd treat it as a potential (if unlikely) deadlock:

(a) irq_set_thread_affinity triggers the scheduler via wake_up_process,
while irq_desc->lock is taken

(b) the scheduler calls into KVM with rq_lock taken, and KVM uses
ir_list_lock within __avic_vcpu_load/__avic_vcpu_put

(c) KVM wants to block scheduling for a while and uses ir_list_lock for
that purpose, but then takes irq_set_vcpu_affinity takes irq_desc->lock.

I don't think there's an alternative choice of lock for (c); and there's
no easy way to pull the irq_desc->lock out of the IRQ subsystem--in fact
the stickiness of the situation comes from rq->rq_lock and
irq_desc->lock being both internal and not leaf.

Of the three, the most sketchy is (a); notably, __setup_irq() calls
wake_up_process outside desc->lock.  Therefore I'd like so much to treat
it as a kernel/irq/ bug; and the simplest (perhaps too simple...) fix is
to drop the wake_up_process().  The only cost is extra latency on the
next interrupt after an affinity change.

diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 8b1b4c8a4f54..fc135bd079a4 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -189,14 +189,10 @@ static void irq_set_thread_affinity(struct irq_desc *desc)
  	struct irqaction *action;
  
  	for_each_action_of_desc(desc, action) {
-		if (action->thread) {
+		if (action->thread)
  			set_bit(IRQTF_AFFINITY, &action->thread_flags);
-			wake_up_process(action->thread);
-		}
-		if (action->secondary && action->secondary->thread) {
+		if (action->secondary && action->secondary->thread)
  			set_bit(IRQTF_AFFINITY, &action->secondary->thread_flags);
-			wake_up_process(action->secondary->thread);
-		}
  	}
  }
  
Marc, what do you think?

Paolo
Re: possible deadlock due to irq_set_thread_affinity() calling into the scheduler (was Re: [PATCH v3 38/62] KVM: SVM: Take and hold ir_list_lock across IRTE updates in IOMMU)
Posted by Thomas Gleixner 4 weeks, 1 day ago
On Mon, Dec 22 2025 at 15:09, Paolo Bonzini wrote:
> On 12/22/25 10:16, Ankit Soni wrote:
>>    ======================================================
>>    WARNING: possible circular locking dependency detected
>>    6.19.0-rc2 #20 Tainted: G            E
>>    ------------------------------------------------------
>>    CPU 58/KVM/28597 is trying to acquire lock:
>>      ff12c47d4b1f34c0 (&irq_desc_lock_class){-.-.}-{2:2}, at: __irq_get_desc_lock+0x58/0xa0
>> 
>>      but task is already holding lock:
>>      ff12c49b28552110 (&svm->ir_list_lock){....}-{2:2}, at: avic_pi_update_irte+0x147/0x270 [kvm_amd]
>> 
>>      which lock already depends on the new lock.
>> 
>>    Chain exists of:
>>      &irq_desc_lock_class --> &rq->__lock --> &svm->ir_list_lock
>> 
>>    Possible unsafe locking scenario:
>> 
>>          CPU0                            CPU1
>>          ----                            ----
>>     lock(&svm->ir_list_lock);
>>                                        lock(&rq->__lock);
>>                                        lock(&svm->ir_list_lock);
>>     lock(&irq_desc_lock_class);
>> 
>>          *** DEADLOCK ***
>> 
>> So lockdep sees:
>> 
>>    &irq_desc_lock_class -> &rq->__lock -> &svm->ir_list_lock
>> 
>> while avic_pi_update_irte() currently holds svm->ir_list_lock and then
>> takes irq_desc_lock via irq_set_vcpu_affinity(), which creates the
>> potential inversion.
>> 
>>    - Is this lockdep warning expected/benign in this code path, or does it
>>      indicate a real potential deadlock between svm->ir_list_lock and
>>      irq_desc_lock with AVIC + irq_bypass + VFIO?
>
> I'd treat it as a potential (if unlikely) deadlock:
>
> (a) irq_set_thread_affinity triggers the scheduler via wake_up_process,
> while irq_desc->lock is taken
>
> (b) the scheduler calls into KVM with rq_lock taken, and KVM uses
> ir_list_lock within __avic_vcpu_load/__avic_vcpu_put
>
> (c) KVM wants to block scheduling for a while and uses ir_list_lock for
> that purpose, but then takes irq_set_vcpu_affinity takes irq_desc->lock.
>
> I don't think there's an alternative choice of lock for (c); and there's
> no easy way to pull the irq_desc->lock out of the IRQ subsystem--in fact

Don't even think about that.

> the stickiness of the situation comes from rq->rq_lock and
> irq_desc->lock being both internal and not leaf.
>
> Of the three, the most sketchy is (a); notably, __setup_irq() calls
> wake_up_process outside desc->lock.  Therefore I'd like so much to treat
> it as a kernel/irq/ bug; and the simplest (perhaps too simple...) fix is

It's not more sketchy than VIRT assuming that it can do what it wants
under rq->lock. :)

> to drop the wake_up_process().  The only cost is extra latency on the
> next interrupt after an affinity change.

The real problematic cost is that in an isolation scenario the wakeup
happens at the next interrupt which might be far into the isolated
phase. That's why the wakeup is there. See:

  c99303a2d2a2 ("genirq: Wake interrupt threads immediately when changing affinity")

Obviously you did not even bother to look that up otherwise you would
have CC'ed Crystal and asked her to take a look...

Thanks,

        tglx
Re: possible deadlock due to irq_set_thread_affinity() calling into the scheduler (was Re: [PATCH v3 38/62] KVM: SVM: Take and hold ir_list_lock across IRTE updates in IOMMU)
Posted by Thomas Gleixner 4 weeks, 1 day ago
On Thu, Jan 08 2026 at 22:28, Thomas Gleixner wrote:
> On Mon, Dec 22 2025 at 15:09, Paolo Bonzini wrote:
>> Of the three, the most sketchy is (a); notably, __setup_irq() calls
>> wake_up_process outside desc->lock.  Therefore I'd like so much to treat
>> it as a kernel/irq/ bug; and the simplest (perhaps too simple...) fix is
>
> It's not more sketchy than VIRT assuming that it can do what it wants
> under rq->lock. :)

And just for the record, that's not the only place in the irq core which
has that lock chain.

irq_set_affinity_locked()       // invoked with desc::lock held
   if (desc->affinity_notify)
      schedule_work()           // Ends up taking rq::lock

and that's the case since cd7eab44e994 ("genirq: Add IRQ affinity
notifiers"), which was added 15 years ago.

Are you still claiming that this is a kernel/irq bug?

Thanks,

        tglx
Re: possible deadlock due to irq_set_thread_affinity() calling into the scheduler (was Re: [PATCH v3 38/62] KVM: SVM: Take and hold ir_list_lock across IRTE updates in IOMMU)
Posted by Paolo Bonzini 2 weeks, 2 days ago
Sorry, not sure how the previous email ended up encrypted.

On 1/8/26 22:53, Thomas Gleixner wrote:
> On Thu, Jan 08 2026 at 22:28, Thomas Gleixner wrote:
>> On Mon, Dec 22 2025 at 15:09, Paolo Bonzini wrote:
>>> Of the three, the most sketchy is (a); notably, __setup_irq() calls
>>> wake_up_process outside desc->lock.  Therefore I'd like so much to treat
>>> it as a kernel/irq/ bug; and the simplest (perhaps too simple...) fix is
>>
>> It's not more sketchy than VIRT assuming that it can do what it wants
>> under rq->lock. 🙂
>
> And just for the record, that's not the only place in the irq core which
> has that lock chain.
>
> irq_set_affinity_locked()       // invoked with desc::lock held
>     if (desc->affinity_notify)
>        schedule_work()           // Ends up taking rq::lock
>
> and that's the case since cd7eab44e994 ("genirq: Add IRQ affinity
> notifiers"), which was added 15 years ago.
>
> Are you still claiming that this is a kernel/irq bug?

Not really, I did say I'd like to treat it as a kernel/irq bug...
but certainly didn't have hopes high enough to "claim" that.
I do think that it's ugly to have locks that are internal,
non-leaf and held around callbacks; but people smarter than
me have thought about it and you can't call it a bug anyway.

For x86/AMD we have a way to fix it, so that part is not a problem.

For the call(*) to irq_set_affinity() in arch/arm64/kvm/'s
vgic_v4_load() I think it can be solved as well.
kvm_make_request(KVM_REQ_RELOAD_GICv4) will delay vgic_v4_load()
to a safe spot, so just cache the previous smp_processor_id() and,
if it is different, do the kvm_make_request() and return instead
of calling irq_set_affinity().

vgic_v3_load() is the only place that calls it from the preempt
notifier, so this behavior can be tied to a "bool delay_set_affinity"
argument to vgic_v4_load() or placed in a different function.

Marc/Oliver, does that sound doable?

Paolo

(*) kvm_sched_in() preempt notifier -> kvm_arch_vcpu_load() ->
     kvm_vgic_load() -> vgic_v3_load() -> vgic_v4_load()

Re: possible deadlock due to irq_set_thread_affinity() calling into the scheduler (was Re: [PATCH v3 38/62] KVM: SVM: Take and hold ir_list_lock across IRTE updates in IOMMU)
Posted by Thomas Gleixner 2 weeks, 1 day ago
On Wed, Jan 21 2026 at 19:13, Paolo Bonzini wrote:
> On 1/8/26 22:53, Thomas Gleixner wrote:
>> Are you still claiming that this is a kernel/irq bug?
>
> Not really, I did say I'd like to treat it as a kernel/irq bug...
> but certainly didn't have hopes high enough to "claim" that.
> I do think that it's ugly to have locks that are internal,
> non-leaf and held around callbacks; but people smarter than
> me have thought about it and you can't call it a bug anyway.

Deep core code has a tendency to be ugly. But if it makes your life
easier, then these wakeups can be delayed via an irq_work to be outside
of the lock. That needs some life-time issues to be addressed, but
should be doable.

Thanks,

        tglx
Re: possible deadlock due to irq_set_thread_affinity() calling into the scheduler (was Re: [PATCH v3 38/62] KVM: SVM: Take and hold ir_list_lock across IRTE updates in IOMMU)
Posted by Paolo Bonzini 2 weeks ago
On Thu, Jan 22, 2026 at 7:47 PM Thomas Gleixner <tglx@kernel.org> wrote:
>
> On Wed, Jan 21 2026 at 19:13, Paolo Bonzini wrote:
> > On 1/8/26 22:53, Thomas Gleixner wrote:
> >> Are you still claiming that this is a kernel/irq bug?
> >
> > Not really, I did say I'd like to treat it as a kernel/irq bug...
> > but certainly didn't have hopes high enough to "claim" that.
> > I do think that it's ugly to have locks that are internal,
> > non-leaf and held around callbacks; but people smarter than
> > me have thought about it and you can't call it a bug anyway.
>
> Deep core code has a tendency to be ugly. But if it makes your life
> easier, then these wakeups can be delayed via an irq_work to be outside
> of the lock. That needs some life-time issues to be addressed, but
> should be doable.

Thanks for the suggestion---hopefully it's not needed at all and we
can delay taking the lock in KVM.

Paolo
Re: possible deadlock due to irq_set_thread_affinity() calling into the scheduler (was Re: [PATCH v3 38/62] KVM: SVM: Take and hold ir_list_lock across IRTE updates in IOMMU)
Posted by Marc Zyngier 2 weeks, 2 days ago
On Wed, 21 Jan 2026 18:13:43 +0000,
Paolo Bonzini <pbonzini@redhat.com> wrote:
> 
> Sorry, not sure how the previous email ended up encrypted.
> 
> On 1/8/26 22:53, Thomas Gleixner wrote:
> > On Thu, Jan 08 2026 at 22:28, Thomas Gleixner wrote:
> >> On Mon, Dec 22 2025 at 15:09, Paolo Bonzini wrote:
> >>> Of the three, the most sketchy is (a); notably, __setup_irq() calls
> >>> wake_up_process outside desc->lock.  Therefore I'd like so much to treat
> >>> it as a kernel/irq/ bug; and the simplest (perhaps too simple...) fix is
> >> 
> >> It's not more sketchy than VIRT assuming that it can do what it wants
> >> under rq->lock. 🙂
> > 
> > And just for the record, that's not the only place in the irq core which
> > has that lock chain.
> > 
> > irq_set_affinity_locked()       // invoked with desc::lock held
> >     if (desc->affinity_notify)
> >        schedule_work()           // Ends up taking rq::lock
> > 
> > and that's the case since cd7eab44e994 ("genirq: Add IRQ affinity
> > notifiers"), which was added 15 years ago.
> > 
> > Are you still claiming that this is a kernel/irq bug?
> 
> Not really, I did say I'd like to treat it as a kernel/irq bug...
> but certainly didn't have hopes high enough to "claim" that.
> I do think that it's ugly to have locks that are internal,
> non-leaf and held around callbacks; but people smarter than
> me have thought about it and you can't call it a bug anyway.
> 
> For x86/AMD we have a way to fix it, so that part is not a problem.
> 
> For the call(*) to irq_set_affinity() in arch/arm64/kvm/'s
> vgic_v4_load() I think it can be solved as well.
> kvm_make_request(KVM_REQ_RELOAD_GICv4) will delay vgic_v4_load()
> to a safe spot, so just cache the previous smp_processor_id() and,
> if it is different, do the kvm_make_request() and return instead
> of calling irq_set_affinity().
> 
> vgic_v3_load() is the only place that calls it from the preempt
> notifier, so this behavior can be tied to a "bool delay_set_affinity"
> argument to vgic_v4_load() or placed in a different function.
> 
> Marc/Oliver, does that sound doable?

Potentially. But there are a few gotchas that may need surgery beyond
KVM itself, all the way down to the ITS code that abstract the
differences between v4.0 and v4.1.

I'll have a look over the weekend.

Thanks,

	M.

-- 
Without deviation from the norm, progress is not possible.
Re: possible deadlock due to irq_set_thread_affinity() calling into the scheduler (was Re: [PATCH v3 38/62] KVM: SVM: Take and hold ir_list_lock across IRTE updates in IOMMU)
Posted by Paolo Bonzini 2 weeks, 3 days ago
-----BEGIN PGP MESSAGE-----

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
=HPz9
-----END PGP MESSAGE-----
-----BEGIN PGP MESSAGE-----

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
=FdiM
-----END PGP MESSAGE-----
Re: possible deadlock due to irq_set_thread_affinity() calling into the scheduler (was Re: [PATCH v3 38/62] KVM: SVM: Take and hold ir_list_lock across IRTE updates in IOMMU)
Posted by Sean Christopherson 1 month, 2 weeks ago
On Mon, Dec 22, 2025, Paolo Bonzini wrote:
> On 12/22/25 10:16, Ankit Soni wrote:
> >    ======================================================
> >    WARNING: possible circular locking dependency detected
> >    6.19.0-rc2 #20 Tainted: G            E
> >    ------------------------------------------------------
> >    CPU 58/KVM/28597 is trying to acquire lock:
> >      ff12c47d4b1f34c0 (&irq_desc_lock_class){-.-.}-{2:2}, at: __irq_get_desc_lock+0x58/0xa0
> > 
> >      but task is already holding lock:
> >      ff12c49b28552110 (&svm->ir_list_lock){....}-{2:2}, at: avic_pi_update_irte+0x147/0x270 [kvm_amd]
> > 
> >      which lock already depends on the new lock.
> > 
> >    Chain exists of:
> >      &irq_desc_lock_class --> &rq->__lock --> &svm->ir_list_lock
> > 
> >    Possible unsafe locking scenario:
> > 
> >          CPU0                            CPU1
> >          ----                            ----
> >     lock(&svm->ir_list_lock);
> >                                        lock(&rq->__lock);
> >                                        lock(&svm->ir_list_lock);
> >     lock(&irq_desc_lock_class);
> > 
> >          *** DEADLOCK ***
> > 
> > So lockdep sees:
> > 
> >    &irq_desc_lock_class -> &rq->__lock -> &svm->ir_list_lock
> > 
> > while avic_pi_update_irte() currently holds svm->ir_list_lock and then
> > takes irq_desc_lock via irq_set_vcpu_affinity(), which creates the
> > potential inversion.
> > 
> >    - Is this lockdep warning expected/benign in this code path, or does it
> >      indicate a real potential deadlock between svm->ir_list_lock and
> >      irq_desc_lock with AVIC + irq_bypass + VFIO?
> 
> I'd treat it as a potential (if unlikely) deadlock:
> 
> (a) irq_set_thread_affinity triggers the scheduler via wake_up_process,
> while irq_desc->lock is taken
> 
> (b) the scheduler calls into KVM with rq_lock taken, and KVM uses
> ir_list_lock within __avic_vcpu_load/__avic_vcpu_put
> 
> (c) KVM wants to block scheduling for a while and uses ir_list_lock for
> that purpose, but then takes irq_set_vcpu_affinity takes irq_desc->lock.
> 
> I don't think there's an alternative choice of lock for (c); and there's
> no easy way to pull the irq_desc->lock out of the IRQ subsystem--in fact
> the stickiness of the situation comes from rq->rq_lock and
> irq_desc->lock being both internal and not leaf.
> 
> Of the three, the most sketchy is (a);

Maybe the most unnecessary, but I think there's a pretty strong argument that
(d) is the most sketchy:

  (d) KVM takes svm->ir_list_lock around the call to irq_set_vcpu_affinity()

> notably, __setup_irq() calls wake_up_process outside desc->lock.  Therefore
> I'd like so much to treat it as a kernel/irq/ bug; and the simplest (perhaps
> too simple...) fix is to drop the wake_up_process().  The only cost is extra
> latency on the next interrupt after an affinity change.

Alternatively, what if we rework the KVM<=>IOMMU exchange to decouple updating
the IRTE from binding the metadata to the vCPU?  KVM already has the necessary
exports to do "out-of-band" updates due to the AVIC architecture requiring IRTE
updates on scheduling changes.

It's a bit wonky (and not yet tested), but I like the idea of making
svm->ir_list_lock a leaf lock so that we don't end up with a game of whack-a-mole,
e.g. if something in the IRQ subsystem changes in the future.

---
 arch/x86/include/asm/irq_remapping.h |  3 --
 arch/x86/kvm/svm/avic.c              | 78 ++++++++++++++++++----------
 drivers/iommu/amd/iommu.c            | 24 +++------
 3 files changed, 57 insertions(+), 48 deletions(-)

diff --git a/arch/x86/include/asm/irq_remapping.h b/arch/x86/include/asm/irq_remapping.h
index 4e55d1755846..1426ecd09943 100644
--- a/arch/x86/include/asm/irq_remapping.h
+++ b/arch/x86/include/asm/irq_remapping.h
@@ -35,9 +35,6 @@ struct amd_iommu_pi_data {
 	u64 vapic_addr;		/* Physical address of the vCPU's vAPIC. */
 	u32 ga_tag;
 	u32 vector;		/* Guest vector of the interrupt */
-	int cpu;
-	bool ga_log_intr;
-	bool is_guest_mode;
 	void *ir_data;
 };
 
diff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c
index 6b77b2033208..0f4f353c7db6 100644
--- a/arch/x86/kvm/svm/avic.c
+++ b/arch/x86/kvm/svm/avic.c
@@ -868,6 +868,51 @@ static void svm_ir_list_del(struct kvm_kernel_irqfd *irqfd)
 	raw_spin_unlock_irqrestore(&to_svm(vcpu)->ir_list_lock, flags);
 }
 
+static int avic_pi_add_irte(struct kvm_kernel_irqfd *irqfd, void *ir_data,
+			    struct kvm_vcpu *vcpu)
+{
+	struct vcpu_svm *svm = to_svm(vcpu);
+	int r;
+
+	/*
+	 * Prevent the vCPU from being scheduled out or migrated until the IRTE
+	 * is updated and its metadata has been added to the list of IRQs being
+	 * posted to the vCPU, to ensure the IRTE isn't programmed with stale
+	 * pCPU/IsRunning information.
+	 */
+	guard(raw_spinlock_irqsave)(&svm->ir_list_lock);
+
+	if (kvm_vcpu_apicv_active(vcpu)) {
+		u64 entry = svm->avic_physical_id_entry;
+		bool ga_log_intr;
+		int cpu;
+
+		/*
+		 * Update the target pCPU for IOMMU doorbells if the vCPU is
+		 * running.  If the vCPU is NOT running, i.e. is blocking or
+		 * scheduled out, KVM will update the pCPU info when the vCPU
+		 * is awakened and/or scheduled in.  See also avic_vcpu_load().
+		 */
+		if (entry & AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK) {
+			cpu = entry & AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK;
+			ga_log_intr = false;
+		} else {
+			cpu = -1;
+			ga_log_intr = entry & AVIC_PHYSICAL_ID_ENTRY_GA_LOG_INTR;
+		}
+		r = amd_iommu_activate_guest_mode(ir_data, cpu, ga_log_intr);
+	} else {
+		r = amd_iommu_deactivate_guest_mode(ir_data);
+	}
+
+	if (r)
+		return r;
+
+	irqfd->irq_bypass_data = ir_data;
+	list_add(&irqfd->vcpu_list, &svm->ir_list);
+	return 0;
+}
+
 int avic_pi_update_irte(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,
 			unsigned int host_irq, uint32_t guest_irq,
 			struct kvm_vcpu *vcpu, u32 vector)
@@ -888,36 +933,11 @@ int avic_pi_update_irte(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,
 		struct amd_iommu_pi_data pi_data = {
 			.ga_tag = AVIC_GATAG(to_kvm_svm(kvm)->avic_vm_id,
 					     vcpu->vcpu_idx),
-			.is_guest_mode = kvm_vcpu_apicv_active(vcpu),
 			.vapic_addr = avic_get_backing_page_address(to_svm(vcpu)),
 			.vector = vector,
 		};
-		struct vcpu_svm *svm = to_svm(vcpu);
-		u64 entry;
 		int ret;
 
-		/*
-		 * Prevent the vCPU from being scheduled out or migrated until
-		 * the IRTE is updated and its metadata has been added to the
-		 * list of IRQs being posted to the vCPU, to ensure the IRTE
-		 * isn't programmed with stale pCPU/IsRunning information.
-		 */
-		guard(raw_spinlock_irqsave)(&svm->ir_list_lock);
-
-		/*
-		 * Update the target pCPU for IOMMU doorbells if the vCPU is
-		 * running.  If the vCPU is NOT running, i.e. is blocking or
-		 * scheduled out, KVM will update the pCPU info when the vCPU
-		 * is awakened and/or scheduled in.  See also avic_vcpu_load().
-		 */
-		entry = svm->avic_physical_id_entry;
-		if (entry & AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK) {
-			pi_data.cpu = entry & AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK;
-		} else {
-			pi_data.cpu = -1;
-			pi_data.ga_log_intr = entry & AVIC_PHYSICAL_ID_ENTRY_GA_LOG_INTR;
-		}
-
 		ret = irq_set_vcpu_affinity(host_irq, &pi_data);
 		if (ret)
 			return ret;
@@ -932,9 +952,11 @@ int avic_pi_update_irte(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,
 			return -EIO;
 		}
 
-		irqfd->irq_bypass_data = pi_data.ir_data;
-		list_add(&irqfd->vcpu_list, &svm->ir_list);
-		return 0;
+		ret = avic_pi_add_irte(irqfd, pi_data.ir_data, vcpu);
+		if (WARN_ON_ONCE(ret))
+			irq_set_vcpu_affinity(host_irq, NULL);
+
+		return ret;
 	}
 	return irq_set_vcpu_affinity(host_irq, NULL);
 }
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index 5d45795c367a..855c6309900c 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -3970,7 +3970,6 @@ EXPORT_SYMBOL(amd_iommu_deactivate_guest_mode);
 
 static int amd_ir_set_vcpu_affinity(struct irq_data *data, void *info)
 {
-	int ret;
 	struct amd_iommu_pi_data *pi_data = info;
 	struct amd_ir_data *ir_data = data->chip_data;
 	struct irq_2_irte *irte_info = &ir_data->irq_2_irte;
@@ -3993,25 +3992,16 @@ static int amd_ir_set_vcpu_affinity(struct irq_data *data, void *info)
 
 	ir_data->cfg = irqd_cfg(data);
 
-	if (pi_data) {
-		pi_data->ir_data = ir_data;
+	if (!pi_data)
+		return amd_iommu_deactivate_guest_mode(ir_data);
 
-		ir_data->ga_root_ptr = (pi_data->vapic_addr >> 12);
-		ir_data->ga_vector = pi_data->vector;
-		ir_data->ga_tag = pi_data->ga_tag;
-		if (pi_data->is_guest_mode)
-			ret = amd_iommu_activate_guest_mode(ir_data, pi_data->cpu,
-							    pi_data->ga_log_intr);
-		else
-			ret = amd_iommu_deactivate_guest_mode(ir_data);
-	} else {
-		ret = amd_iommu_deactivate_guest_mode(ir_data);
-	}
-
-	return ret;
+	pi_data->ir_data = ir_data;
+	ir_data->ga_root_ptr = (pi_data->vapic_addr >> 12);
+	ir_data->ga_vector = pi_data->vector;
+	ir_data->ga_tag = pi_data->ga_tag;
+	return 0;
 }
 
-
 static void amd_ir_update_irte(struct irq_data *irqd, struct amd_iommu *iommu,
 			       struct amd_ir_data *ir_data,
 			       struct irq_2_irte *irte_info,

base-commit: 9448598b22c50c8a5bb77a9103e2d49f134c9578
--
Re: possible deadlock due to irq_set_thread_affinity() calling into the scheduler (was Re: [PATCH v3 38/62] KVM: SVM: Take and hold ir_list_lock across IRTE updates in IOMMU)
Posted by Paolo Bonzini 1 month, 2 weeks ago
On 12/22/25 20:34, Sean Christopherson wrote:
> On Mon, Dec 22, 2025, Paolo Bonzini wrote:
>> On 12/22/25 10:16, Ankit Soni wrote:
>>>     - Is this lockdep warning expected/benign in this code path, or does it
>>>       indicate a real potential deadlock between svm->ir_list_lock and
>>>       irq_desc_lock with AVIC + irq_bypass + VFIO?
>>
>> I'd treat it as a potential (if unlikely) deadlock:
>>
>> (a) irq_set_thread_affinity triggers the scheduler via wake_up_process,
>> while irq_desc->lock is taken
>>
>> (b) the scheduler calls into KVM with rq_lock taken, and KVM uses
>> ir_list_lock within __avic_vcpu_load/__avic_vcpu_put
>>
>> (c) KVM wants to block scheduling for a while and uses ir_list_lock for
>> that purpose, but then irq_set_vcpu_affinity takes irq_desc->lock.
>>
>> I don't think there's an alternative choice of lock for (c); and there's
>> no easy way to pull the irq_desc->lock out of the IRQ subsystem--in fact
>> the stickiness of the situation comes from rq->rq_lock and
>> irq_desc->lock being both internal and not leaf.
>>
>> Of the three, the most sketchy is (a);
> 
> Maybe the most unnecessary, but I think there's a pretty strong argument that
> (d) is the most sketchy:
> 
>    (d) KVM takes svm->ir_list_lock around the call to irq_set_vcpu_affinity()

That's (c). :)

I called irq_set_thread_affinity() sketchy, because it's a core kernel 
subsystem that takes a pretty common lock, and directly calls a function 
that takes another very common lock.  KVM's deadlock scenario seems like 
a relatively natural occurrence, though in this case it can be fixed 
outside kernel/irq as well.

>> notably, __setup_irq() calls wake_up_process outside desc->lock.  Therefore
>> I'd like so much to treat it as a kernel/irq/ bug; and the simplest (perhaps
>> too simple...) fix is to drop the wake_up_process().  The only cost is extra
>> latency on the next interrupt after an affinity change.
> 
> Alternatively, what if we rework the KVM<=>IOMMU exchange to decouple updating
> the IRTE from binding the metadata to the vCPU?  KVM already has the necessary
> exports to do "out-of-band" updates due to the AVIC architecture requiring IRTE
> updates on scheduling changes.

In fact this was actually my first idea, exactly because it makes
svm->ir_list_lock a leaf lock!

I threw it away because it makes amd_ir_set_vcpu_affinity() weird, 
passing back the ir_data but not really doing anything else.  Basically 
its role becomes little more than violate abstractions, which seemed 
wrong.  On the other hand, drivers/iommu is already very much tied to 
the KVM vendor modules (in particular avic.c already calls 
amd_iommu_{,de}activate_guest_mode), so who am I to judge what the IOMMU 
driver does.

Paolo

> It's a bit wonky (and not yet tested), but I like the idea of making
> svm->ir_list_lock a leaf lock so that we don't end up with a game of whack-a-mole,
> e.g. if something in the IRQ subsystem changes in the future.
> 
> ---
>   arch/x86/include/asm/irq_remapping.h |  3 --
>   arch/x86/kvm/svm/avic.c              | 78 ++++++++++++++++++----------
>   drivers/iommu/amd/iommu.c            | 24 +++------
>   3 files changed, 57 insertions(+), 48 deletions(-)
> 
> diff --git a/arch/x86/include/asm/irq_remapping.h b/arch/x86/include/asm/irq_remapping.h
> index 4e55d1755846..1426ecd09943 100644
> --- a/arch/x86/include/asm/irq_remapping.h
> +++ b/arch/x86/include/asm/irq_remapping.h
> @@ -35,9 +35,6 @@ struct amd_iommu_pi_data {
>   	u64 vapic_addr;		/* Physical address of the vCPU's vAPIC. */
>   	u32 ga_tag;
>   	u32 vector;		/* Guest vector of the interrupt */
> -	int cpu;
> -	bool ga_log_intr;
> -	bool is_guest_mode;
>   	void *ir_data;
>   };
>   
> diff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c
> index 6b77b2033208..0f4f353c7db6 100644
> --- a/arch/x86/kvm/svm/avic.c
> +++ b/arch/x86/kvm/svm/avic.c
> @@ -868,6 +868,51 @@ static void svm_ir_list_del(struct kvm_kernel_irqfd *irqfd)
>   	raw_spin_unlock_irqrestore(&to_svm(vcpu)->ir_list_lock, flags);
>   }
>   
> +static int avic_pi_add_irte(struct kvm_kernel_irqfd *irqfd, void *ir_data,
> +			    struct kvm_vcpu *vcpu)
> +{
> +	struct vcpu_svm *svm = to_svm(vcpu);
> +	int r;
> +
> +	/*
> +	 * Prevent the vCPU from being scheduled out or migrated until the IRTE
> +	 * is updated and its metadata has been added to the list of IRQs being
> +	 * posted to the vCPU, to ensure the IRTE isn't programmed with stale
> +	 * pCPU/IsRunning information.
> +	 */
> +	guard(raw_spinlock_irqsave)(&svm->ir_list_lock);
> +
> +	if (kvm_vcpu_apicv_active(vcpu)) {
> +		u64 entry = svm->avic_physical_id_entry;
> +		bool ga_log_intr;
> +		int cpu;
> +
> +		/*
> +		 * Update the target pCPU for IOMMU doorbells if the vCPU is
> +		 * running.  If the vCPU is NOT running, i.e. is blocking or
> +		 * scheduled out, KVM will update the pCPU info when the vCPU
> +		 * is awakened and/or scheduled in.  See also avic_vcpu_load().
> +		 */
> +		if (entry & AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK) {
> +			cpu = entry & AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK;
> +			ga_log_intr = false;
> +		} else {
> +			cpu = -1;
> +			ga_log_intr = entry & AVIC_PHYSICAL_ID_ENTRY_GA_LOG_INTR;
> +		}
> +		r = amd_iommu_activate_guest_mode(ir_data, cpu, ga_log_intr);
> +	} else {
> +		r = amd_iommu_deactivate_guest_mode(ir_data);
> +	}
> +
> +	if (r)
> +		return r;
> +
> +	irqfd->irq_bypass_data = ir_data;
> +	list_add(&irqfd->vcpu_list, &svm->ir_list);
> +	return 0;
> +}
> +
>   int avic_pi_update_irte(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,
>   			unsigned int host_irq, uint32_t guest_irq,
>   			struct kvm_vcpu *vcpu, u32 vector)
> @@ -888,36 +933,11 @@ int avic_pi_update_irte(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,
>   		struct amd_iommu_pi_data pi_data = {
>   			.ga_tag = AVIC_GATAG(to_kvm_svm(kvm)->avic_vm_id,
>   					     vcpu->vcpu_idx),
> -			.is_guest_mode = kvm_vcpu_apicv_active(vcpu),
>   			.vapic_addr = avic_get_backing_page_address(to_svm(vcpu)),
>   			.vector = vector,
>   		};
> -		struct vcpu_svm *svm = to_svm(vcpu);
> -		u64 entry;
>   		int ret;
>   
> -		/*
> -		 * Prevent the vCPU from being scheduled out or migrated until
> -		 * the IRTE is updated and its metadata has been added to the
> -		 * list of IRQs being posted to the vCPU, to ensure the IRTE
> -		 * isn't programmed with stale pCPU/IsRunning information.
> -		 */
> -		guard(raw_spinlock_irqsave)(&svm->ir_list_lock);
> -
> -		/*
> -		 * Update the target pCPU for IOMMU doorbells if the vCPU is
> -		 * running.  If the vCPU is NOT running, i.e. is blocking or
> -		 * scheduled out, KVM will update the pCPU info when the vCPU
> -		 * is awakened and/or scheduled in.  See also avic_vcpu_load().
> -		 */
> -		entry = svm->avic_physical_id_entry;
> -		if (entry & AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK) {
> -			pi_data.cpu = entry & AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK;
> -		} else {
> -			pi_data.cpu = -1;
> -			pi_data.ga_log_intr = entry & AVIC_PHYSICAL_ID_ENTRY_GA_LOG_INTR;
> -		}
> -
>   		ret = irq_set_vcpu_affinity(host_irq, &pi_data);
>   		if (ret)
>   			return ret;
> @@ -932,9 +952,11 @@ int avic_pi_update_irte(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,
>   			return -EIO;
>   		}
>   
> -		irqfd->irq_bypass_data = pi_data.ir_data;
> -		list_add(&irqfd->vcpu_list, &svm->ir_list);
> -		return 0;
> +		ret = avic_pi_add_irte(irqfd, pi_data.ir_data, vcpu);
> +		if (WARN_ON_ONCE(ret))
> +			irq_set_vcpu_affinity(host_irq, NULL);
> +
> +		return ret;
>   	}
>   	return irq_set_vcpu_affinity(host_irq, NULL);
>   }
> diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
> index 5d45795c367a..855c6309900c 100644
> --- a/drivers/iommu/amd/iommu.c
> +++ b/drivers/iommu/amd/iommu.c
> @@ -3970,7 +3970,6 @@ EXPORT_SYMBOL(amd_iommu_deactivate_guest_mode);
>   
>   static int amd_ir_set_vcpu_affinity(struct irq_data *data, void *info)
>   {
> -	int ret;
>   	struct amd_iommu_pi_data *pi_data = info;
>   	struct amd_ir_data *ir_data = data->chip_data;
>   	struct irq_2_irte *irte_info = &ir_data->irq_2_irte;
> @@ -3993,25 +3992,16 @@ static int amd_ir_set_vcpu_affinity(struct irq_data *data, void *info)
>   
>   	ir_data->cfg = irqd_cfg(data);
>   
> -	if (pi_data) {
> -		pi_data->ir_data = ir_data;
> +	if (!pi_data)
> +		return amd_iommu_deactivate_guest_mode(ir_data);
>   
> -		ir_data->ga_root_ptr = (pi_data->vapic_addr >> 12);
> -		ir_data->ga_vector = pi_data->vector;
> -		ir_data->ga_tag = pi_data->ga_tag;
> -		if (pi_data->is_guest_mode)
> -			ret = amd_iommu_activate_guest_mode(ir_data, pi_data->cpu,
> -							    pi_data->ga_log_intr);
> -		else
> -			ret = amd_iommu_deactivate_guest_mode(ir_data);
> -	} else {
> -		ret = amd_iommu_deactivate_guest_mode(ir_data);
> -	}
> -
> -	return ret;
> +	pi_data->ir_data = ir_data;
> +	ir_data->ga_root_ptr = (pi_data->vapic_addr >> 12);
> +	ir_data->ga_vector = pi_data->vector;
> +	ir_data->ga_tag = pi_data->ga_tag;
> +	return 0;
>   }
>   
> -
>   static void amd_ir_update_irte(struct irq_data *irqd, struct amd_iommu *iommu,
>   			       struct amd_ir_data *ir_data,
>   			       struct irq_2_irte *irte_info,
> 
> base-commit: 9448598b22c50c8a5bb77a9103e2d49f134c9578
> --
>
Re: possible deadlock due to irq_set_thread_affinity() calling into the scheduler (was Re: [PATCH v3 38/62] KVM: SVM: Take and hold ir_list_lock across IRTE updates in IOMMU)
Posted by Sean Christopherson 1 month, 2 weeks ago
On Mon, Dec 22, 2025, Paolo Bonzini wrote:
> On 12/22/25 20:34, Sean Christopherson wrote:
> > On Mon, Dec 22, 2025, Paolo Bonzini wrote:
> > > notably, __setup_irq() calls wake_up_process outside desc->lock.  Therefore
> > > I'd like so much to treat it as a kernel/irq/ bug; and the simplest (perhaps
> > > too simple...) fix is to drop the wake_up_process().  The only cost is extra
> > > latency on the next interrupt after an affinity change.
> > 
> > Alternatively, what if we rework the KVM<=>IOMMU exchange to decouple updating
> > the IRTE from binding the metadata to the vCPU?  KVM already has the necessary
> > exports to do "out-of-band" updates due to the AVIC architecture requiring IRTE
> > updates on scheduling changes.
> 
> In fact this was actually my first idea, exactly because it makes
> svm->ir_list_lock a leaf lock!
> 
> I threw it away because it makes amd_ir_set_vcpu_affinity() weird, passing
> back the ir_data but not really doing anything else.  Basically its role
> becomes little more than violate abstractions, which seemed wrong.  On the
> other hand, drivers/iommu is already very much tied to the KVM vendor
> modules (in particular avic.c already calls
> amd_iommu_{,de}activate_guest_mode), so who am I to judge what the IOMMU
> driver does.

Yeah, I 100% agree the whole thing is a bit gross, but practically speaking it's
just not feasible to properly abstract the interaction, because in reality the
IOMMU implementation is tightly coupled to the CPU implementation.  E.g. passing
in the address of a PID isn't going to work well with an AMD IOMMU, and passing
in the address of a vCPI isn't going to work well with an Intel IOMMU.

And FWIW, the lack of true abstraction isn't limited to x86.  ARM's GIGv4 passes
around "struct its_cmd_info" and PPC uses "struct kvmppc_xive_irq_state".

I mean, we could do what GICv4 does and use irq_set_vcpu_affinity() to pass
different commands to the IOMMU, e.g. by formalizing "enum avic_vcpu_action"
between KVM and IOMMU so that avic_update_iommu_vcpu_affinity() wouldn't need to
_directly_ call AMD IOMMU code.  But IMO that would be a net negative because in
practice all it would do is make it harder to understand what's going on.  And
it would more directly create this potential deadlock.

Huh.  Which begs the question of whether or not ARM is also affected by this
deadlock, without the extra hop through svm->ir_list_lock:

  (a) irq_set_thread_affinity() triggers the scheduler via wake_up_process(),
      while irq_desc->lock is taken

  (b) the scheduler calls into KVM with rq_lock taken, and KVM uses
      irq_set_vcpu_affinity() via vgic_v4_{load,put}()

If ARM is affected, then maybe fixing this in irq_set_thread_affinity() is indeed
better than fudging around the deadlock in avic.c.
Re: possible deadlock due to irq_set_thread_affinity() calling into the scheduler (was Re: [PATCH v3 38/62] KVM: SVM: Take and hold ir_list_lock across IRTE updates in IOMMU)
Posted by Ankit Soni 1 month, 2 weeks ago
On Mon, Dec 22, 2025 at 03:09:13PM +0100, Paolo Bonzini wrote:
> On 12/22/25 10:16, Ankit Soni wrote:
> >    ======================================================
> >    WARNING: possible circular locking dependency detected
> >    6.19.0-rc2 #20 Tainted: G            E
> >    ------------------------------------------------------
> >    CPU 58/KVM/28597 is trying to acquire lock:
> >      ff12c47d4b1f34c0 (&irq_desc_lock_class){-.-.}-{2:2}, at: __irq_get_desc_lock+0x58/0xa0
> > 
> >      but task is already holding lock:
> >      ff12c49b28552110 (&svm->ir_list_lock){....}-{2:2}, at: avic_pi_update_irte+0x147/0x270 [kvm_amd]
> > 
> >      which lock already depends on the new lock.
> > 
> >    Chain exists of:
> >      &irq_desc_lock_class --> &rq->__lock --> &svm->ir_list_lock
> > 
> >    Possible unsafe locking scenario:
> > 
> >          CPU0                            CPU1
> >          ----                            ----
> >     lock(&svm->ir_list_lock);
> >                                        lock(&rq->__lock);
> >                                        lock(&svm->ir_list_lock);
> >     lock(&irq_desc_lock_class);
> > 
> >          *** DEADLOCK ***
> > 
> > So lockdep sees:
> > 
> >    &irq_desc_lock_class -> &rq->__lock -> &svm->ir_list_lock
> > 
> > while avic_pi_update_irte() currently holds svm->ir_list_lock and then
> > takes irq_desc_lock via irq_set_vcpu_affinity(), which creates the
> > potential inversion.
> > 
> >    - Is this lockdep warning expected/benign in this code path, or does it
> >      indicate a real potential deadlock between svm->ir_list_lock and
> >      irq_desc_lock with AVIC + irq_bypass + VFIO?
> 
> I'd treat it as a potential (if unlikely) deadlock:
> 
> (a) irq_set_thread_affinity triggers the scheduler via wake_up_process,
> while irq_desc->lock is taken
> 
> (b) the scheduler calls into KVM with rq_lock taken, and KVM uses
> ir_list_lock within __avic_vcpu_load/__avic_vcpu_put
> 
> (c) KVM wants to block scheduling for a while and uses ir_list_lock for
> that purpose, but then takes irq_set_vcpu_affinity takes irq_desc->lock.
> 
> I don't think there's an alternative choice of lock for (c); and there's
> no easy way to pull the irq_desc->lock out of the IRQ subsystem--in fact
> the stickiness of the situation comes from rq->rq_lock and
> irq_desc->lock being both internal and not leaf.
> 
> Of the three, the most sketchy is (a); notably, __setup_irq() calls
> wake_up_process outside desc->lock.  Therefore I'd like so much to treat
> it as a kernel/irq/ bug; and the simplest (perhaps too simple...) fix is
> to drop the wake_up_process().  The only cost is extra latency on the
> next interrupt after an affinity change.
> 
> diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
> index 8b1b4c8a4f54..fc135bd079a4 100644
> --- a/kernel/irq/manage.c
> +++ b/kernel/irq/manage.c
> @@ -189,14 +189,10 @@ static void irq_set_thread_affinity(struct irq_desc *desc)
>  	struct irqaction *action;
>  	for_each_action_of_desc(desc, action) {
> -		if (action->thread) {
> +		if (action->thread)
>  			set_bit(IRQTF_AFFINITY, &action->thread_flags);
> -			wake_up_process(action->thread);
> -		}
> -		if (action->secondary && action->secondary->thread) {
> +		if (action->secondary && action->secondary->thread)
>  			set_bit(IRQTF_AFFINITY, &action->secondary->thread_flags);
> -			wake_up_process(action->secondary->thread);
> -		}
>  	}
>  }
> Marc, what do you think?
> 
> Paolo
> 

Hi Paolo,
With the above patch I’m still seeing the same circular dependency warning.
However, and with Sean’s patch I’m not seeing any warnings.

[  335.128640] ======================================================
[  335.128650] WARNING: possible circular locking dependency detected
[  335.128660] 6.19.0-rc2-dirty #21 Tainted: G            E
[  335.128668] ------------------------------------------------------
[  335.128675] CPU 96/KVM/28699 is trying to acquire lock:
[  335.128682] ff453c6b59bb18c0 (&irq_desc_lock_class){-.-.}-{2:2}, at: __irq_get_desc_lock+0x58/0xa0
[  335.128704]
               but task is already holding lock:
[  335.128712] ff453c8b0946e600 (&svm->ir_list_lock){....}-{2:2}, at: avic_pi_update_irte+0x147/0x270 [kvm_amd]
[  335.128732]
               which lock already depends on the new lock.

[  335.128742]
               the existing dependency chain (in reverse order) is:
[  335.128751]
               -> #4 (&svm->ir_list_lock){....}-{2:2}:
[  335.128760]        _raw_spin_lock_irqsave+0x4e/0xb0
[  335.128772]        __avic_vcpu_put+0x7a/0x150 [kvm_amd]
[  335.128783]        avic_vcpu_put+0x50/0x70 [kvm_amd]
[  335.128791]        svm_vcpu_put+0x38/0x70 [kvm_amd]
[  335.128800]        kvm_arch_vcpu_put+0x21b/0x330 [kvm]
[  335.128854]        kvm_sched_out+0x62/0x90 [kvm]
[  335.128893]        __schedule+0x8d3/0x1d10
[  335.128901]        __cond_resched+0x5c/0x80
[  335.128909]        __kmalloc_cache_noprof+0x3d7/0x730
[  335.128920]        kvm_hv_vcpu_init+0x48/0x260 [kvm]
[  335.128957]        kvm_hv_set_msr_common+0x5b/0x12a0 [kvm]
[  335.128988]        kvm_set_msr_common+0x468/0x1310 [kvm]
[  335.129019]        svm_set_msr+0x645/0x730 [kvm_amd]
[  335.129028]        __kvm_set_msr+0xa3/0x2f0 [kvm]
[  335.129066]        kvm_set_msr_ignored_check+0x23/0x1b0 [kvm]
[  335.129096]        do_set_msr+0x76/0xd0 [kvm]
[  335.129126]        msr_io+0xbe/0x1c0 [kvm]
[  335.129152]        kvm_arch_vcpu_ioctl+0x700/0x2090 [kvm]
[  335.129181]        kvm_vcpu_ioctl+0x632/0xc60 [kvm]
[  335.129215]        __x64_sys_ioctl+0xa5/0x100
[  335.129224]        x64_sys_call+0x1243/0x26b0
[  335.129234]        do_syscall_64+0x93/0x1470
[  335.129242]        entry_SYSCALL_64_after_hwframe+0x76/0x7e
[  335.129251]
               -> #3 (&rq->__lock){-.-.}-{2:2}:
[  335.129259]        _raw_spin_lock_nested+0x32/0x80
[  335.129267]        raw_spin_rq_lock_nested+0x22/0xa0
[  335.129276]        task_rq_lock+0x5f/0x150
[  335.129392]        cgroup_move_task+0x46/0x110
[  335.129494]        css_set_move_task+0xe1/0x240
[  335.129614]        cgroup_post_fork+0x98/0x2d0
[  335.129704]        copy_process+0x1ea8/0x2330
[  335.129795]        kernel_clone+0xa7/0x440
[  335.129883]        user_mode_thread+0x63/0x90
[  335.129970]        rest_init+0x28/0x200
[  335.130056]        start_kernel+0xae0/0xcd0
[  335.130144]        x86_64_start_reservations+0x18/0x30
[  335.130230]        x86_64_start_kernel+0xfd/0x150
[  335.130312]        common_startup_64+0x13e/0x141
[  335.130396]
               -> #2 (&p->pi_lock){-.-.}-{2:2}:
[  335.130554]        _raw_spin_lock_irqsave+0x4e/0xb0
[  335.130631]        try_to_wake_up+0x59/0xaa0
[  335.130709]        wake_up_process+0x15/0x30
[  335.130785]        create_worker+0x154/0x250
[  335.130862]        workqueue_init+0x414/0x760
[  335.130938]        kernel_init_freeable+0x24f/0x630
[  335.131013]        kernel_init+0x1b/0x200
[  335.131086]        ret_from_fork+0x344/0x3a0
[  335.131161]        ret_from_fork_asm+0x1a/0x30
[  335.131235]
               -> #1 (&pool->lock){-.-.}-{2:2}:
[  335.131375]        _raw_spin_lock+0x34/0x80
[  335.131448]        __queue_work+0xf4/0x740
[  335.131523]        queue_work_on+0x70/0xd0
[  335.131595]        irq_set_affinity_locked+0x13b/0x250
[  335.131669]        __irq_apply_affinity_hint+0xf8/0x120
[  335.131742]        mlx5_irq_alloc+0x28e/0x4e0 [mlx5_core]
[  335.131884]        mlx5_irq_request+0x125/0x140 [mlx5_core]
[  335.131997]        mlx5_irq_request_vector+0xb4/0x110 [mlx5_core]
[  335.132107]        comp_irq_request_pci+0x68/0xf0 [mlx5_core]
[  335.132219]        mlx5_comp_eqn_get+0x127/0x850 [mlx5_core]
[  335.132327]        mlx5e_create_cq+0x58/0x260 [mlx5_core]
[  335.132452]        mlx5e_open_drop_rq+0x11c/0x220 [mlx5_core]
[  335.132573]        mlx5e_init_nic_rx+0x2c/0x270 [mlx5_core]
[  335.132687]        mlx5e_attach_netdev+0xed/0x340 [mlx5_core]
[  335.132794]        _mlx5e_resume+0x6a/0xd0 [mlx5_core]
[  335.132900]        mlx5e_probe+0x5e3/0xa50 [mlx5_core]
[  335.133010]        auxiliary_bus_probe+0x45/0x90
[  335.133086]        really_probe+0xf1/0x410
[  335.133160]        __driver_probe_device+0x8c/0x190
[  335.133233]        driver_probe_device+0x24/0xd0
[  335.133305]        __device_attach_driver+0xcd/0x170
[  335.133377]        bus_for_each_drv+0x99/0x100
[  335.133450]        __device_attach+0xba/0x1f0
[  335.133523]        device_initial_probe+0x4e/0x50
[  335.133595]        bus_probe_device+0x3c/0xa0
[  335.133668]        device_add+0x6af/0x8a0
[  335.133740]        __auxiliary_device_add+0x43/0xc0
[  335.133813]        add_adev+0xd3/0x160 [mlx5_core]
[  335.133931]        mlx5_rescan_drivers_locked+0x1ee/0x340 [mlx5_core]
[  335.134045]        mlx5_register_device+0x37/0xb0 [mlx5_core]
[  335.134156]        mlx5_init_one_devl_locked+0x43e/0x710 [mlx5_core]
[  335.134267]        probe_one+0x35b/0x530 [mlx5_core]
[  335.134382]        local_pci_probe+0x47/0xb0
[  335.134460]        work_for_cpu_fn+0x1a/0x30
[  335.134538]        process_one_work+0x22b/0x6f0
[  335.134613]        worker_thread+0x1c6/0x3b0
[  335.134687]        kthread+0x110/0x230
[  335.134764]        ret_from_fork+0x344/0x3a0
[  335.134838]        ret_from_fork_asm+0x1a/0x30
[  335.134913]
               -> #0 (&irq_desc_lock_class){-.-.}-{2:2}:
[  335.135059]        __lock_acquire+0x1595/0x2640
[  335.135135]        lock_acquire+0xc4/0x2c0
[  335.135210]        _raw_spin_lock_irqsave+0x4e/0xb0
[  335.135286]        __irq_get_desc_lock+0x58/0xa0
[  335.135362]        irq_set_vcpu_affinity+0x4a/0x100
[  335.135438]        avic_pi_update_irte+0x170/0x270 [kvm_amd]
[  335.135521]        kvm_pi_update_irte+0xea/0x220 [kvm]
[  335.135633]        kvm_arch_irq_bypass_add_producer+0x9b/0xb0 [kvm]
[  335.135737]        __connect+0x5f/0x100 [irqbypass]
[  335.135815]        irq_bypass_register_producer+0xe4/0xb90 [irqbypass]
[  335.135895]        vfio_msi_set_vector_signal+0x1b0/0x330 [vfio_pci_core]
[  335.135979]        vfio_msi_set_block+0x5a/0xd0 [vfio_pci_core]
[  335.136060]        vfio_pci_set_msi_trigger+0x19e/0x260 [vfio_pci_core]
[  335.136142]        vfio_pci_set_irqs_ioctl+0x46/0x140 [vfio_pci_core]
[  335.136224]        vfio_pci_core_ioctl+0x6ea/0xc20 [vfio_pci_core]
[  335.136306]        vfio_device_fops_unl_ioctl+0xb1/0x9d0 [vfio]
[  335.136390]        __x64_sys_ioctl+0xa5/0x100
[  335.136470]        x64_sys_call+0x1243/0x26b0
[  335.136553]        do_syscall_64+0x93/0x1470
[  335.136632]        entry_SYSCALL_64_after_hwframe+0x76/0x7e
[  335.136712]
               other info that might help us debug this:

[  335.136942] Chain exists of:
                 &irq_desc_lock_class --> &rq->__lock --> &svm->ir_list_lock

[  335.137178]  Possible unsafe locking scenario:

[  335.137340]        CPU0                    CPU1
[  335.137420]        ----                    ----
[  335.137502]   lock(&svm->ir_list_lock);
[  335.137582]                                lock(&rq->__lock);
[  335.137664]                                lock(&svm->ir_list_lock);
[  335.137746]   lock(&irq_desc_lock_class);
[  335.137826]
                *** DEADLOCK ***

[  335.138057] 4 locks held by CPU 96/KVM/28699:
[  335.138136]  #0: ff453c6c28bae800 (&vdev->igate){+.+.}-{4:4}, at: vfio_pci_core_ioctl+0x6d2/0xc20 [vfio_pci_core]
[  335.138223]  #1: ffffffffc0faf110 (lock#10){+.+.}-{4:4}, at: irq_bypass_register_producer+0x31/0xb90 [irqbypass]
[  335.138310]  #2: ff453c8b11179478 (&kvm->irqfds.lock){....}-{3:3}, at: kvm_arch_irq_bypass_add_producer+0x2d/0xb0 [kvm]
[  335.138423]  #3: ff453c8b0946e600 (&svm->ir_list_lock){....}-{2:2}, at: avic_pi_update_irte+0x147/0x270 [kvm_amd]

-Ankit