diff options
| author | Thomas Gleixner <tglx@kernel.org> | 2026-05-17 23:02:14 +0300 |
|---|---|---|
| committer | Thomas Gleixner <tglx@kernel.org> | 2026-05-26 17:21:13 +0300 |
| commit | 3ba92f6a28203e30d0b2c7d75b59f48d5ff9fbcc (patch) | |
| tree | e654af1612cf0a6322a5ac31df5d8a423bd7baae | |
| parent | b99dc723b12ea587fc8b2e07bd8401433eec58d8 (diff) | |
| download | linux-3ba92f6a28203e30d0b2c7d75b59f48d5ff9fbcc.tar.xz | |
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
| -rw-r--r-- | kernel/irq/manage.c | 37 |
1 files changed, 21 insertions, 16 deletions
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 2e8072437826..8863b2d4b8ca 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: |
