git: f6f8cbda8efc - main - kern_reboot(9): describe event handlers

From: Mitchell Horne <mhorne_at_FreeBSD.org>
Date: Mon, 20 Mar 2023 20:13:30 UTC
The branch main has been updated by mhorne:

URL: https://cgit.FreeBSD.org/src/commit/?id=f6f8cbda8efcd32a312655842097e9095ee3e0fb

commit f6f8cbda8efcd32a312655842097e9095ee3e0fb
Author:     Mitchell Horne <mhorne@FreeBSD.org>
AuthorDate: 2023-03-20 19:58:48 +0000
Commit:     Mitchell Horne <mhorne@FreeBSD.org>
CommitDate: 2023-03-20 20:12:12 +0000

    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 <pauamma@gundo.com>
    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