]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
genirq/manage: Make NMI cleanup RT safe
authorThomas Gleixner <tglx@kernel.org>
Sun, 17 May 2026 20:02:14 +0000 (22:02 +0200)
committerThomas Gleixner <tglx@kernel.org>
Tue, 26 May 2026 14:21:13 +0000 (16:21 +0200)
Eventually blocking functions cannot be invoked with interrupts disabled
and a raw spin lock held. Restructure the code so this happens outside of
the descriptor lock held region.

Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Tested-by: Michael Kelley <mhklinux@outlook.com>
Link: https://patch.msgid.link/20260517194931.601972758@kernel.org
kernel/irq/manage.c

index 2e8072437826765ca15a7e2ee3c66028dc3b5263..8863b2d4b8ca40fcdf55fa2075031c95e9cd484a 100644 (file)
@@ -2026,24 +2026,30 @@ const void *free_irq(unsigned int irq, void *dev_id)
 }
 EXPORT_SYMBOL(free_irq);
 
-/* This function must be called with desc->lock held */
 static const void *__cleanup_nmi(unsigned int irq, struct irq_desc *desc)
 {
+       struct irqaction *action = NULL;
        const char *devname = NULL;
 
-       desc->istate &= ~IRQS_NMI;
+       scoped_guard(raw_spinlock_irqsave, &desc->lock) {
+               irq_nmi_teardown(desc);
 
-       if (!WARN_ON(desc->action == NULL)) {
-               irq_pm_remove_action(desc, desc->action);
-               devname = desc->action->name;
-               unregister_handler_proc(irq, desc->action);
+               desc->istate &= ~IRQS_NMI;
 
-               kfree(desc->action);
+               if (!WARN_ON(desc->action == NULL)) {
+                       action = desc->action;
+                       irq_pm_remove_action(desc, action);
+                       devname = action->name;
+               }
                desc->action = NULL;
+
+               irq_settings_clr_disable_unlazy(desc);
+               irq_shutdown_and_deactivate(desc);
        }
 
-       irq_settings_clr_disable_unlazy(desc);
-       irq_shutdown_and_deactivate(desc);
+       if (action)
+               unregister_handler_proc(irq, action);
+       kfree(action);
 
        irq_release_resources(desc);
 
@@ -2067,8 +2073,6 @@ const void *free_nmi(unsigned int irq, void *dev_id)
        if (WARN_ON(desc->depth == 0))
                disable_nmi_nosync(irq);
 
-       guard(raw_spinlock_irqsave)(&desc->lock);
-       irq_nmi_teardown(desc);
        return __cleanup_nmi(irq, desc);
 }
 
@@ -2318,13 +2322,14 @@ int request_nmi(unsigned int irq, irq_handler_t handler,
                /* Setup NMI state */
                desc->istate |= IRQS_NMI;
                retval = irq_nmi_setup(desc);
-               if (retval) {
-                       __cleanup_nmi(irq, desc);
-                       return -EINVAL;
-               }
-               return 0;
        }
 
+       if (retval) {
+               __cleanup_nmi(irq, desc);
+               return -EINVAL;
+       }
+       return 0;
+
 err_irq_setup:
        irq_chip_pm_put(&desc->irq_data);
 err_out: