]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
KVM: x86: Take irqfds.lock when adding/deleting IRQ bypass producer
authorSean Christopherson <seanjc@google.com>
Sat, 6 Sep 2025 14:57:16 +0000 (10:57 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 9 Sep 2025 16:45:22 +0000 (18:45 +0200)
[ Upstream commit f1fb088d9cecde5c3066d8ff8846789667519b7d ]

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>
[ Adjust context ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
arch/x86/kvm/x86.c

index 63df6c33e3a4709f443af885c22e37c4c81e78f9..8952f3567b69acad3d624560122e4f63fcfdae29 100644 (file)
@@ -11417,16 +11417,22 @@ int kvm_arch_irq_bypass_add_producer(struct irq_bypass_consumer *cons,
 {
        struct kvm_kernel_irqfd *irqfd =
                container_of(cons, struct kvm_kernel_irqfd, consumer);
+       struct kvm *kvm = irqfd->kvm;
        int ret;
 
-       irqfd->producer = prod;
        kvm_arch_start_assignment(irqfd->kvm);
+
+       spin_lock_irq(&kvm->irqfds.lock);
+       irqfd->producer = prod;
+
        ret = kvm_x86_ops.update_pi_irte(irqfd->kvm,
                                         prod->irq, irqfd->gsi, 1);
-
        if (ret)
                kvm_arch_end_assignment(irqfd->kvm);
 
+       spin_unlock_irq(&kvm->irqfds.lock);
+
+
        return ret;
 }
 
@@ -11436,9 +11442,9 @@ void kvm_arch_irq_bypass_del_producer(struct irq_bypass_consumer *cons,
        int ret;
        struct kvm_kernel_irqfd *irqfd =
                container_of(cons, struct kvm_kernel_irqfd, consumer);
+       struct kvm *kvm = irqfd->kvm;
 
        WARN_ON(irqfd->producer != prod);
-       irqfd->producer = NULL;
 
        /*
         * When producer of consumer is unregistered, we change back to
@@ -11446,11 +11452,17 @@ void kvm_arch_irq_bypass_del_producer(struct irq_bypass_consumer *cons,
         * when the irq is masked/disabled or the consumer side (KVM
         * int this case doesn't want to receive the interrupts.
        */
+       spin_lock_irq(&kvm->irqfds.lock);
+       irqfd->producer = NULL;
+
        ret = kvm_x86_ops.update_pi_irte(irqfd->kvm, prod->irq, irqfd->gsi, 0);
        if (ret)
                printk(KERN_INFO "irq bypass consumer (token %p) unregistration"
                       " fails: %d\n", irqfd->consumer.token, ret);
 
+       spin_unlock_irq(&kvm->irqfds.lock);
+
+
        kvm_arch_end_assignment(irqfd->kvm);
 }