[tip: irq/core] genirq/manage: Make NMI cleanup RT safe

From: tip-bot2 for Thomas Gleixner

Date: Tue May 26 2026 - 10:36:42 EST


The following commit has been merged into the irq/core branch of tip:

Commit-ID: 3ba92f6a28203e30d0b2c7d75b59f48d5ff9fbcc
Gitweb: https://git.kernel.org/tip/3ba92f6a28203e30d0b2c7d75b59f48d5ff9fbcc
Author: Thomas Gleixner <tglx@xxxxxxxxxx>
AuthorDate: Sun, 17 May 2026 22:02:14 +02:00
Committer: Thomas Gleixner <tglx@xxxxxxxxxx>
CommitterDate: Tue, 26 May 2026 16:21:13 +02:00

genirq/manage: Make NMI cleanup RT safe

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@xxxxxxxxxx>
Tested-by: Michael Kelley <mhklinux@xxxxxxxxxxx>
Link: https://patch.msgid.link/20260517194931.601972758@xxxxxxxxxx
---
kernel/irq/manage.c | 37 +++++++++++++++++++++----------------
1 file changed, 21 insertions(+), 16 deletions(-)

diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 2e80724..8863b2d 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -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: