From f6f8cbda8efcd32a312655842097e9095ee3e0fb Mon Sep 17 00:00:00 2001 From: Mitchell Horne Date: Mon, 20 Mar 2023 16:58:48 -0300 Subject: [PATCH] kern_reboot(9): describe event handlers Add more details about the execution and purpose of these shutdown handlers. Make a point to mention the requirement that they can be run in a normal or panic context. Add some simple examples. Add a brief comment to the declaration in sys/eventhandler.h. Reviewed by: markj Discussed with: rpokala, Pau Amma MFC after: 1 week Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D39135 --- share/man/man9/kern_reboot.9 | 111 +++++++++++++++++++++++++++++++++++ sys/sys/eventhandler.h | 9 ++- 2 files changed, 119 insertions(+), 1 deletion(-) diff --git a/share/man/man9/kern_reboot.9 b/share/man/man9/kern_reboot.9 index d120a437c521..a82b53382687 100644 --- a/share/man/man9/kern_reboot.9 +++ b/share/man/man9/kern_reboot.9 @@ -128,6 +128,9 @@ Print a message indicating that the system is about to be halted or rebooted, and a report of the total system uptime. .It Execute all registered shutdown hooks. +See +.Sx SHUTDOWN HOOKS +below. .It As a last resort, if none of the shutdown hooks handled the reboot, call the machine-dependent @@ -172,6 +175,58 @@ is called before the process has been spawned, or if the system has panicked or otherwise halted, .Fn kern_reboot will be called directly. +.Sh SHUTDOWN HOOKS +The system defines three separate +.Xr EVENTHANDLER 9 +events, which are invoked successively during the shutdown procedure. +These are +.Va shutdown_pre_sync , +.Va shutdown_post_sync , +and +.Va shutdown_final . +They will be executed unconditionally in the listed order. +Handler functions registered to any of these events will receive the value of +.Fa howto +as their second argument, which may be used to decide what action to take. +.Pp +The +.Va shutdown_pre_sync +event is invoked before syncing filesystems to disk. +It enables any action or state transition that must happen before this point to +take place. +.Pp +The +.Va shutdown_post_sync +event is invoked at the point immediately after the filesystem sync has +finished. +It enables, for example, disk drivers to complete the sync by flushing their +cache to disk. +Note that this event still takes place before the optional kernel core dump. +.Pp +The +.Va shutdown_final +event is invoked as the very last step of +.Fn kern_reboot . +Drivers and subsystems such as +.Xr acpi 4 +can register handlers to this event that will perform the actual reboot, +power-off, or halt. +.Pp +Notably, the +.Va shutdown_final +event is also the point at which all kernel modules will have their shutdown +.Po +.Dv MOD_SHUTDOWN +.Pc +hooks executed, and when the +.Xr DEVICE_SHUTDOWN 9 +method will be executed recursively on all devices. +.Pp +All event handlers, like +.Fn kern_reboot +itself, may be run in either normal shutdown context or a kernel panic or +debugger context. +Handler functions are expected to take care not to trigger recursive panics. .Sh RETURN VALUES The .Fn kern_reboot @@ -183,9 +238,65 @@ function will usually return to its caller, having initiated the asynchronous system shutdown. It will not return when called from a panic or debugger context, or during early boot. +.Sh EXAMPLES +A hypothetical driver, foo(4), defines a +.Va shutdown_final +event handler that can handle system power-off by writing to a device register, +but it does not handle halt or reset. +.Bd -literal -offset indent +void +foo_poweroff_handler(struct void *arg, int howto) +{ + struct foo_softc *sc = arg; + uint32_t reg; + + if ((howto & RB_POWEROFF) != 0) { + reg = FOO_POWEROFF; + WRITE4(sc, FOO_POWEROFF_REG, reg); + } +} +.Ed +.Pp +The handler is then registered in the device attach routine: +.Bd -literal -offset indent +int +foo_attach(device_t dev) +{ + struct foo_softc *sc; + + ... + + /* Pass the device's software context as the private arg. */ + EVENTHANDLER_REGISTER(shutdown_final, foo_poweroff_handler, sc, + SHUTDOWN_PRI_DEFAULT); + + ... +} +.Ed +.Pp +This +.Va shutdown_final +handler uses the +.Dv RB_NOSYNC +flag to detect that a panic or other unusual condition has occurred, and +returns early: +.Bd -literal -offset indent +void +bar_shutdown_final(struct void *arg, int howto) +{ + + if ((howto & RB_NOSYNC) != 0) + return; + + /* Some code that is not panic-safe. */ + ... +} +.Ed .Sh SEE ALSO .Xr reboot 2 , .Xr init 8 , +.Xr DEVICE_SHUTDOWN 9 , .Xr EVENTHANDLER 9 , +.Xr module 9 , .Xr panic 9 , .Xr vfs_unmountall 9 diff --git a/sys/sys/eventhandler.h b/sys/sys/eventhandler.h index 8c45431c83c3..be5a027f4743 100644 --- a/sys/sys/eventhandler.h +++ b/sys/sys/eventhandler.h @@ -184,7 +184,14 @@ eventhandler_tag vimage_eventhandler_register(struct eventhandler_list *list, #define EVENTHANDLER_PRI_ANY 10000 #define EVENTHANDLER_PRI_LAST 20000 -/* Shutdown events */ +/* + * Successive shutdown events invoked by kern_reboot(9). + * + * Handlers will receive the 'howto' value as their second argument. + * + * All handlers must be prepared to be executed from a panic/debugger context; + * see the man page for details. + */ typedef void (*shutdown_fn)(void *, int); #define SHUTDOWN_PRI_FIRST EVENTHANDLER_PRI_FIRST