]> 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>
Fri, 4 Apr 2025 19:38:19 +0000 (12:38 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 28 Aug 2025 14:26:12 +0000 (16:26 +0200)
commit f1fb088d9cecde5c3066d8ff8846789667519b7d upstream.

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>
[sean: account for lack of kvm_x86_call()]
Signed-off-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
arch/x86/kvm/x86.c

index dfecf5ba5aa7a9511535ba2f0810c0328ff3e3ff..f542ab5e86981f767ea9918020dcc62c3b0cde1a 100644 (file)
@@ -13387,16 +13387,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 = static_call(kvm_x86_pi_update_irte)(irqfd->kvm,
                                         prod->irq, irqfd->gsi, 1);
-
        if (ret)
                kvm_arch_end_assignment(irqfd->kvm);
 
+       spin_unlock_irq(&kvm->irqfds.lock);
+
+
        return ret;
 }
 
@@ -13406,9 +13412,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
@@ -13416,11 +13422,18 @@ 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 = static_call(kvm_x86_pi_update_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);
 }