From: Zak Brighton Knight <zakbrightonknight@gmail.com>
To: Andrew Morton <akpm@linux-foundation.org>, linux-kernel@vger.kernel.org
Cc: "Rafael J. Wysocki" <rafael@kernel.org>,
Daniel Lezcano <daniel.lezcano@kernel.org>,
Zhang Rui <rui.zhang@intel.com>,
Lukasz Luba <lukasz.luba@arm.com>,
linux-pm@vger.kernel.org, Ahmad Fatoum <a.fatoum@pengutronix.de>,
Matti Vaittinen <mazziesaccount@gmail.com>,
Zak Brighton Knight <zakbrightonknight@gmail.com>
Subject: [PATCH] reboot: fail run_cmd() before init so hw protection can force the action
Date: Sat, 7 Nov 2026 14:31:29 +0000 [thread overview]
Message-ID: <20261107143129.875202-1-zakbrightonknight@gmail.com> (raw)
__hw_protection_trigger() asks userspace to power off through
orderly_poweroff(). It only forces the power-off when running
poweroff_cmd fails. run_cmd() waits for the exec only (UMH_WAIT_EXEC)
so a successful exec counts as a started shutdown.
Before init has started that exec can succeed and do nothing. Usermode
helpers are enabled at rootfs_initcall and wait for the initramfs to
be unpacked. So a built-in driver that triggers during device
initcalls runs the initramfs copy of /sbin/poweroff. On a
dracut/systemd initramfs that is systemctl. It finds /proc not mounted
and decides it is in a chroot. It logs "Running in chroot, ignoring
request." and exits 0. Nobody sees the message because a usermode
helper starts with no stdout or stderr. The default
CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 arms no backup timer. The
one-shot latch in __hw_protection_trigger() then makes the kernel
ignore every later request. The machine runs without its critical
temperature protection until the next boot.
I hit this on a ThinkPad T520 running Fedora's 7.2.15 kernel, booted
while still hot from a long memtest run. The ACPI zone read 101 C
against a 100 C _CRT 0.29 s into boot. The kernel logged "HARDWARE
PROTECTION shutdown (Temperature too high)" and the machine kept
running for 90 minutes.
It reproduces in QEMU with Fedora's 7.2.13 kernel and with current
tip. The test uses an SSDT thermal zone whose _TMP is above its _CRT
and an initramfs with Fedora's systemctl as /sbin/poweroff.
hw_protection=reboot fails the same way. Setting
sysctl.kernel.poweroff_cmd on the command line does not help either
because do_sysctl_args() runs after the initcalls.
Make run_cmd() fail with -EBUSY until system_state reaches
SYSTEM_RUNNING. Both callers then take the fallback they already have.
__orderly_poweroff(true) syncs and powers off. __orderly_reboot()
syncs and restarts.
Firmware that reports a bogus critical temperature only during early
boot used to get away with it. Such a machine will now power off at
boot, as it already does when the same reading comes after init has
started.
A short window remains between SYSTEM_RUNNING and init being ready to
handle the request. A non-zero CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS
still covers that.
An AI coding assistant (Claude by Anthropic) helped find the cause,
build the reproducer and draft this patch.
Fixes: 10a0a8d4e3f6 ("Add common orderly_poweroff()")
Signed-off-by: Zak Brighton Knight <zakbrightonknight@gmail.com>
---
I haven't tested this on the T520 itself, only in QEMU (x86_64
defconfig with ACPI_THERMAL=y). Without the patch the guest keeps
running after the trip. With it the guest powers off within a
millisecond and logs "Failed to start orderly shutdown: forcing the
issue". With hw_protection=reboot it restarts instead. A trip after
init still runs /sbin/poweroff as before.
The reproducer is an SSDT thermal zone whose _TMP is above its _CRT,
passed to QEMU with -acpitable, and an initramfs with Fedora's
systemctl as /sbin/poweroff. I can send it if that helps.
Commit ef1d87e06ab4 ("thermal: core: Add a back up thermal shutdown
mechanism") noted in 2017 that /sbin/poweroff can return success during
boot without doing anything. It added
CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS, which defaults to 0. This
patch covers the early boot case whatever that option is set to.
kernel/reboot.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/kernel/reboot.c b/kernel/reboot.c
index 9a84401adde5..14c2bbbc5a3e 100644
--- a/kernel/reboot.c
+++ b/kernel/reboot.c
@@ -858,6 +858,18 @@ static int run_cmd(const char *cmd)
NULL
};
int ret;
+
+ /*
+ * Until init has started, no userspace can carry out an orderly
+ * poweroff or reboot. Running the command can still succeed: an
+ * initramfs usually has /sbin/poweroff, and it does nothing when
+ * there is no init to talk to. As we only wait for the exec, that
+ * would look like success and the caller would never force the
+ * action. Fail instead.
+ */
+ if (system_state < SYSTEM_RUNNING)
+ return -EBUSY;
+
argv = argv_split(GFP_KERNEL, cmd, NULL);
if (argv) {
ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
base-commit: d48723711bae9b8cdc56719c448ba42fef28cbee
--
2.56.0
next reply other threads:[~2026-11-07 14:31 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-07 14:31 Zak Brighton Knight [this message]
2026-11-07 15:13 ` Bradley Morgan
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261107143129.875202-1-zakbrightonknight@gmail.com \
--to=zakbrightonknight@gmail.com \
--cc=a.fatoum@pengutronix.de \
--cc=akpm@linux-foundation.org \
--cc=daniel.lezcano@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pm@vger.kernel.org \
--cc=lukasz.luba@arm.com \
--cc=mazziesaccount@gmail.com \
--cc=rafael@kernel.org \
--cc=rui.zhang@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®