KVM: Acquire SCRU lock outside of irqfds.lock during assignment

Acquire SRCU outside of irqfds.lock so that the locking is symmetrical,
and add a comment explaining why on earth KVM holds SRCU for so long.

Tested-by: K Prateek Nayak <kprateek.nayak@amd.com>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/r/20250522235223.3178519-3-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
pull/1309/head
Sean Christopherson 2025-05-22 16:52:12 -07:00
parent 283ed5001d
commit 140768a7bf
1 changed files with 16 additions and 3 deletions

View File

@ -394,6 +394,18 @@ kvm_irqfd_assign(struct kvm *kvm, struct kvm_irqfd *args)
*/
init_waitqueue_func_entry(&irqfd->wait, irqfd_wakeup);
/*
* Set the irqfd routing and add it to KVM's list before registering
* the irqfd with the eventfd, so that the routing information is valid
* and stays valid, e.g. if there are GSI routing changes, prior to
* making the irqfd visible, i.e. before it might be signaled.
*
* Note, holding SRCU ensures a stable read of routing information, and
* also prevents irqfd_shutdown() from freeing the irqfd before it's
* fully initialized.
*/
idx = srcu_read_lock(&kvm->irq_srcu);
spin_lock_irq(&kvm->irqfds.lock);
ret = 0;
@ -402,11 +414,9 @@ kvm_irqfd_assign(struct kvm *kvm, struct kvm_irqfd *args)
continue;
/* This fd is used for another irq already. */
ret = -EBUSY;
spin_unlock_irq(&kvm->irqfds.lock);
goto fail;
goto fail_duplicate;
}
idx = srcu_read_lock(&kvm->irq_srcu);
irqfd_update(kvm, irqfd);
list_add_tail(&irqfd->list, &kvm->irqfds.items);
@ -441,6 +451,9 @@ kvm_irqfd_assign(struct kvm *kvm, struct kvm_irqfd *args)
srcu_read_unlock(&kvm->irq_srcu, idx);
return 0;
fail_duplicate:
spin_unlock_irq(&kvm->irqfds.lock);
srcu_read_unlock(&kvm->irq_srcu, idx);
fail:
if (irqfd->resampler)
irqfd_resampler_shutdown(irqfd);