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@kernel.org>
Tested-by: Michael Kelley <mhklinux@outlook.com>
Link: https://patch.msgid.link/20260517194931.601972758@kernel.org
This commit is contained in:
Thomas Gleixner
2026-05-17 22:02:14 +02:00
parent b99dc723b1
commit 3ba92f6a28

View 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: