From 178301baf2ce2c26a4d6f180606db7e163cdaf69 Mon Sep 17 00:00:00 2001 From: Joachim Wiberg Date: Sat, 6 Dec 2025 15:01:31 +0100 Subject: [PATCH] Change default reboot to SOC reset from WDT reset Fixes #460 Signed-off-by: Joachim Wiberg --- doc/config/runlevels.md | 20 +++++++++++++++++++- doc/watchdog.md | 21 ++++++++++++++------- src/conf.c | 6 ++++++ src/conf.h | 1 + src/sig.c | 8 ++++---- 5 files changed, 44 insertions(+), 12 deletions(-) diff --git a/doc/config/runlevels.md b/doc/config/runlevels.md index adf230e2..042ab8b4 100644 --- a/doc/config/runlevels.md +++ b/doc/config/runlevels.md @@ -165,4 +165,22 @@ sync(2) has been called, twice. > "On Linux, sync is only guaranteed to schedule the dirty blocks for > writing; it can actually take a short time before all the blocks are -> finally written. \ No newline at end of file +> finally written. + +**Syntax:** `reboot-watchdog ` + +Controls whether the system should reboot via the watchdog timer (WDT) +or directly via the SoC/kernel. When enabled, Finit will: + + 1. Send `SIGPWR` to the registered watchdog daemon before shutdown + 2. Send `SIGTERM` to the watchdog daemon and wait up to 10 seconds + for the watchdog to trigger a hardware reset + +When disabled (default), Finit skips the watchdog reboot logic and +calls the kernel's `reboot(2)` syscall directly for a clean SoC reboot. + +*Default:* off (reboot via SoC) + +> [!NOTE] +> This setting only affects reboots. The watchdog daemon will still +> run and monitor the system during normal operation. diff --git a/doc/watchdog.md b/doc/watchdog.md index c46d60e2..f75406b6 100644 --- a/doc/watchdog.md +++ b/doc/watchdog.md @@ -10,14 +10,21 @@ many embedded systems this is crucial to ensure all circuits on the board are properly reset for the next boot, in effect ensuring the system works the same after both a power-on and reboot event. +> [!NOTE] +> The watchdog reboot delegation can be enabled with the `reboot-watchdog` +> configuration option in `/etc/finit.conf`. By default this is disabled +> and the system reboots directly via the SoC using the kernel's `reboot(2)` +> syscall. See [Runlevels](config/runlevels.md) for details. + The delegation is performed at the very last steps of system shutdown, -if reboot has been selected and an elected watchdog is known, first a -`SIGPWR` is sent to advise watchdogd of the pending reboot. Then, when -the necessary steps of preparing the system for shutdown (umount etc.) -are completed, Finit sends `SIGTERM` to watchdogd and puts itself in a -10 sec timeout loop waiting for the WDT to reset the board. If a reset -is not done before the timeout, Finit falls back to`reboot(RB_AUTOBOOT)` -which tells the kernel to do the reboot. +if reboot has been selected, `reboot-watchdog` is enabled, and an elected +watchdog is known. First a `SIGPWR` is sent to advise watchdogd of the +pending reboot. Then, when the necessary steps of preparing the system +for shutdown (umount etc.) are completed, Finit sends `SIGTERM` to +watchdogd and puts itself in a 10 sec timeout loop waiting for the WDT +to reset the board. If a reset is not done before the timeout, Finit +falls back to `reboot(RB_AUTOBOOT)` which tells the kernel to do the +reboot. An external watchdog service can also be used. The more advanced cousin [watchdogd](https://github.com/troglobit/watchdogd/) is the recommended diff --git a/src/conf.c b/src/conf.c index d763dbb6..0d8f2ffb 100644 --- a/src/conf.c +++ b/src/conf.c @@ -60,6 +60,7 @@ int single = 0; /* single user mode from kernel cmdline */ int bootstrap = 1; /* set while bootstrapping (for TTYs) */ int kerndebug = 0; /* set if /proc/sys/kernel/printk > 7 */ int syncsec = 0; /* reboot delay */ +int wdtreboot = 0; /* reboot via watchdog, default: SOC */ int readiness = SVC_NOTIFY_PID; char *finit_conf= NULL; char *finit_rcsd= NULL; @@ -1034,6 +1035,11 @@ static int parse_static(char *line, int is_rcsd) return 0; } + if (MATCH_CMD(line, "reboot-watchdog ", x)) { + wdtreboot = get_bool(strip_line(x), 0); + return 0; + } + /* * Periodic check and instability index leveler, seconds */ diff --git a/src/conf.h b/src/conf.h index f81cfbf1..ab2e82e6 100644 --- a/src/conf.h +++ b/src/conf.h @@ -37,6 +37,7 @@ extern int single; extern int bootstrap; extern int kerndebug; extern int syncsec; +extern int wdtreboot; extern int readiness; extern char *fstab; extern char *sdown; diff --git a/src/sig.c b/src/sig.c index dcbeb088..424b67dc 100644 --- a/src/sig.c +++ b/src/sig.c @@ -358,7 +358,7 @@ void do_shutdown(shutop_t op) return; } - if (wdog) { + if (wdtreboot && wdog) { print(kill(wdog->pid, SIGPWR) == 1, "Advising watchdog, system going down"); do_sleep(2); } @@ -405,17 +405,17 @@ void do_shutdown(shutop_t op) /* Reboot via watchdog or kernel, or shutdown? */ if (op == SHUT_REBOOT) { - print(0, "Rebooting ..."); - if (wdog && wdog->pid > 1) { + if (wdtreboot && wdog && wdog->pid > 1) { int timeout = 10; /* Wait here until the WDT reboots, or timeout with fallback */ + print(0, "Rebooting using WDT, please wait ..."); print(kill(wdog->pid, SIGTERM) == 1, "Pending watchdog reboot"); while (timeout--) do_sleep(1); } - dbg("Rebooting ..."); + print(0, "Rebooting ..."); reboot(RB_AUTOBOOT); } else if (op == SHUT_OFF) { print(0, "Powering down ...");