Re: [PATCH 1/6] irq_work: Re-raise pending irq_work after system resume

From: Julian Vetter

Date: Mon Nov 09 2026 - 09:35:28 EST


On 11/4/26 8:48 AM, Adrian Hunter wrote:
On 04/11/2026 09:32, Sebastian Andrzej Siewior wrote:
On 2026-11-03 17:46:32 [+0200], Adrian Hunter wrote:
On 02/11/2026 18:39, Sebastian Andrzej Siewior wrote:
On 2026-11-02 12:54:22 [+0200], Adrian Hunter wrote:

Yes CPUs remain online for suspend2idle, but currently the choice between
suspend2idle and "deep" (S3) suspend is a user space choice,
refer /sys/power/mem_sleep. Many modern systems do not support S3
anymore, but it has not gone away.


Anyway, I'm torn; I would much rather make this trigger a WARN and have

AI now also identifies ftrace, BPF, GHES NMI, and #MC as possible causes,
not just perf. I haven't tried to confirm any of those.

And, belatedly, AI is now saying an irq_work raised before lapic_resume()
might result in #GP if the APIC is left in xAPIC mode at resume. Also
not confirmed.

Could we flush this before similarly to what happens during CPU-hotplug.
The question is if this event can stay enqueued during suspend (and
handled on resume) or should be taken care before entering suspend.

WRT "might result in #GP if the APIC is left in xAPIC mode at resume",
the systems I have checked restore the APIC in x2APIC mode, so the
issue is theoretical at this point, although I can get "unchecked MSR
access error: WRMSR to 0x83f" if I deliberately add code to change
x2APIC to xAPIC early in S3 wake (in x86_acpi_suspend_lowlevel()),
and then do:

perf record -e power:suspend_resume --filter 'action == "machine_suspend" && start == 0' --no-buffering -C 0 -o /tmp/x.data &
rtcwake -m mem -s 10

The error can be avoided with:

I meant flush it via irq_work_run_cpu() like in smpcfd_dead_cpu() (the
CPU-hotplug path) and not go via APIC. You should do it late once the
interrupts are disabled so no new irq-work can be enqueued.
Disabling IRQs doesn't stop NMI or syscore enqueues, and the resume-side
raise still goes through the APIC

Hello Adrian,
I ran into the same lost irq_work self-IPI independently, in a different
context. I triggered that same issue with a live migration of Xen HVM guests. I sent a fix for it, but the posting only reached xen-devel and the maintainers, and not the Linux mailinglist (because my company email has some issues), so here is a short summary for everyone on this thread:

My Setup: XCP-ng 8.3 (Xen 4.17), Ubuntu 26.04 cloud image (kernel 7.0.0-38), 4 vCPUs, "console=tty1 console=ttyS0". After a live migration the guest hangs, e.g. "systemctl restart systemd-resolved" never returns, and fsnotify/SRCU users block.

Mechanism: On Xen, live migration suspends the guest through xen_suspend() (drivers/xen/manage.c), which runs inside stop_machine():

syscore_suspend() -> lapic_suspend() disables the local APIC
HYPERVISOR_suspend()
gnttab_resume(), xen_irq_resume(), ... -> printk()
syscore_resume()

With the 8250 console being nbcon, the printk() in that window queues
nbcon_irq_work to the raised_list on CPU0 and then sends the self-IPI. But, the APIC is disabled at that point, so it's dropped. Afterwards, the raised_list stays non-empty, so irq_work_queue() never raises the IPI again and we are in that same situation.

In mainline the nbcon trigger is hidden by 560f4deda327 ("printk/nbcon: Change nbcon_irq_work to IRQ_WORK_LAZY"), but the underlying problem is still there for any non-lazy irq_work queued in that window. To reproduce it on mainline I reverted 560f4deda327 on top of v7.4-rc1:

v7.4-rc1 + revert of 560f4deda327 -> hangs after the first migration

v7.4-rc1 + revert of 560f4deda327 + this patch (1/6 only) -> 6 live migrations between two hosts, no hang, no SRCU or hung-task warnings, systemctl returns immediately

Since xen_suspend() calls syscore_resume() after the window above, this fix with the new irq_work_resend() functions covers the Xen case as well, without any Xen-specific changes.

Regarding the flush-before-suspend: In the Xen case that would not help. The lost irq_work is queued by printk() after syscore_suspend() has already disabled the local APIC, with interrupts off, so there is nothing to flush yet when suspend starts.

Tested-by: Julian Vetter <julian.vetter@xxxxxxxxxx>

Thank you,
Julian