KVM: x86: Take irqfds.lock when adding/deleting IRQ bypass producer

Take irqfds.lock when adding/deleting an IRQ bypass producer to ensure
irqfd->producer isn't modified while kvm_irq_routing_update() is running.
The only lock held when a producer is added/removed is irqbypass's mutex.

Fixes: 872768800652 ("KVM: x86: select IRQ_BYPASS_MANAGER")
Cc: stable@vger.kernel.org
Signed-off-by: Sean Christopherson <seanjc@google.com>
Message-ID: <20250404193923.1413163-5-seanjc@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

authored by Sean Christopherson and committed by Paolo Bonzini f1fb088d bcda70c5

+15 -2
+15 -2
arch/x86/kvm/x86.c
··· 13561 13561 { 13562 13562 struct kvm_kernel_irqfd *irqfd = 13563 13563 container_of(cons, struct kvm_kernel_irqfd, consumer); 13564 + struct kvm *kvm = irqfd->kvm; 13564 13565 int ret; 13565 13566 13566 - irqfd->producer = prod; 13567 13567 kvm_arch_start_assignment(irqfd->kvm); 13568 + 13569 + spin_lock_irq(&kvm->irqfds.lock); 13570 + irqfd->producer = prod; 13571 + 13568 13572 ret = kvm_x86_call(pi_update_irte)(irqfd->kvm, 13569 13573 prod->irq, irqfd->gsi, 1); 13570 13574 if (ret) 13571 13575 kvm_arch_end_assignment(irqfd->kvm); 13576 + 13577 + spin_unlock_irq(&kvm->irqfds.lock); 13578 + 13572 13579 13573 13580 return ret; 13574 13581 } ··· 13586 13579 int ret; 13587 13580 struct kvm_kernel_irqfd *irqfd = 13588 13581 container_of(cons, struct kvm_kernel_irqfd, consumer); 13582 + struct kvm *kvm = irqfd->kvm; 13589 13583 13590 13584 WARN_ON(irqfd->producer != prod); 13591 - irqfd->producer = NULL; 13592 13585 13593 13586 /* 13594 13587 * When producer of consumer is unregistered, we change back to ··· 13596 13589 * when the irq is masked/disabled or the consumer side (KVM 13597 13590 * int this case doesn't want to receive the interrupts. 13598 13591 */ 13592 + spin_lock_irq(&kvm->irqfds.lock); 13593 + irqfd->producer = NULL; 13594 + 13599 13595 ret = kvm_x86_call(pi_update_irte)(irqfd->kvm, 13600 13596 prod->irq, irqfd->gsi, 0); 13601 13597 if (ret) 13602 13598 printk(KERN_INFO "irq bypass consumer (token %p) unregistration" 13603 13599 " fails: %d\n", irqfd->consumer.token, ret); 13600 + 13601 + spin_unlock_irq(&kvm->irqfds.lock); 13602 + 13604 13603 13605 13604 kvm_arch_end_assignment(irqfd->kvm); 13606 13605 }