From 762fbee53fb890a7cf5e26abcc2dcfad03b1bab4 Mon Sep 17 00:00:00 2001 From: Jakob Kirsch Date: Thu, 24 Oct 2024 19:45:31 +0200 Subject: [PATCH v3] shepherd: Add support for rebooting using kexec --- AUTHORS | 1 + configure.ac | 4 ++++ doc/shepherd.texi | 9 +++++++++ modules/shepherd/scripts/reboot.scm | 12 ++++++++++-- modules/shepherd/service.scm | 9 +++++++++ modules/shepherd/system.scm.in | 10 ++++++++++ tests/status-sexp.sh | 2 +- 7 files changed, 44 insertions(+), 3 deletions(-) diff --git a/AUTHORS b/AUTHORS index 19132a7..6642bdc 100644 --- a/AUTHORS +++ b/AUTHORS @@ -10,3 +10,4 @@ when it was known as GNU dmd. Others have since contributed: Alex Sassmannshausen David Thompson Andy Wingo + Jakob Kirsch diff --git a/configure.ac b/configure.ac index bcfef13..db1dc95 100644 --- a/configure.ac +++ b/configure.ac @@ -124,6 +124,7 @@ case "$host_os" in AC_COMPUTE_INT([RB_DISABLE_CAD], [RB_DISABLE_CAD], [#include ]) AC_COMPUTE_INT([RB_POWER_OFF], [RB_POWER_OFF], [#include ]) AC_COMPUTE_INT([RB_SW_SUSPEND], [RB_SW_SUSPEND], [#include ]) + AC_COMPUTE_INT([RB_KEXEC], [RB_KEXEC], [#include ]) ;; gnu*) # On GNU/Hurd, the Mach-derived reboot.h uses different names, and @@ -131,6 +132,7 @@ case "$host_os" in AC_COMPUTE_INT([RB_HALT_SYSTEM], [RB_HALT], [#include ]) AC_COMPUTE_INT([RB_POWER_OFF], [RB_HALT], [#include ]) RB_DISABLE_CAD="#f" + RB_KEXEC="#f" ;; *) # What is this? GNU/kFreeBSD? @@ -138,6 +140,7 @@ case "$host_os" in AC_COMPUTE_INT([RB_HALT_SYSTEM], [RB_HALT_SYSTEM], [#include ]) AC_COMPUTE_INT([RB_POWER_OFF], [RB_HALT_SYSTEM], [#include ]) RB_DISABLE_CAD="#f" + RB_KEXEC="#f" ;; esac @@ -145,6 +148,7 @@ AC_SUBST([RB_DISABLE_CAD]) AC_SUBST([RB_AUTOBOOT]) AC_SUBST([RB_HALT_SYSTEM]) AC_SUBST([RB_POWER_OFF]) +AC_SUBST([RB_KEXEC]) AC_MSG_RESULT([done]) AC_MSG_CHECKING([ constants]) diff --git a/doc/shepherd.texi b/doc/shepherd.texi index 0e627b3..921bf40 100644 --- a/doc/shepherd.texi +++ b/doc/shepherd.texi @@ -14,6 +14,7 @@ Copyright @copyright{} @value{NEW-YEARS} Ludovic Courtès@* Copyright @copyright{} 2020 Brice Waegeneire@* Copyright @copyright{} 2020 Oleg Pykhalov@* Copyright @copyright{} 2020, 2023 Jan (janneke) Nieuwenhuizen@* +Copyright @copyright{} 2024 Jakob Kirsch@* Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or @@ -600,6 +601,14 @@ It is equivalent to running @command{herd stop shepherd}. The Send commands to the socket special file @var{file}. If this option is not specified, @file{@var{localstatedir}/run/shepherd/socket} is taken. +@item -k +@itemx --do-kexec +Reboot the system using kexec. The kernel that was previously loaded +using @command{kexec -l @var{file}} is executed instead of rebooting +into the BIOS in order to keep the down time to a minimum or to chainload +another kernel. This feature is only available on Linux-based systems and will +throw an exception on GNU/Hurd. This is also equivalent to running @command{herd kexec shepherd}. + @end table @c @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ diff --git a/modules/shepherd/scripts/reboot.scm b/modules/shepherd/scripts/reboot.scm index 6be5414..4c2448e 100644 --- a/modules/shepherd/scripts/reboot.scm +++ b/modules/shepherd/scripts/reboot.scm @@ -30,6 +30,8 @@ (define (main . args) (initialize-cli) + (define action 'stop) + (parameterize ((program-name "reboot")) (let ((socket-file %system-socket-file) (command-args '())) @@ -44,13 +46,19 @@ #:argument-name "FILE" #:description "send commands to FILE" #:action (lambda (file) - (set! socket-file file)))) + (set! socket-file file))) + (option + #:long-name "do-kexec" #:short-name #\k + #:takes-argument? #f + #:description "reboot using kexec" + #:action (lambda () (set! action 'kexec)) + )) (set! command-args (reverse command-args)) (with-system-error-handling (let ((sock (open-connection socket-file))) ;; Send the command without further ado. - (write-command (shepherd-command 'stop 'root) sock) + (write-command (shepherd-command action 'root) sock) ;; Receive output if we're not already dead. (match (read sock) diff --git a/modules/shepherd/service.scm b/modules/shepherd/service.scm index 5942b0a..6a5e112 100644 --- a/modules/shepherd/service.scm +++ b/modules/shepherd/service.scm @@ -2707,6 +2707,15 @@ Clients such as 'herd' can read it and format it in a human-readable way." (lambda (key) (local-output (l10n "Shutting down...")) (power-off))))) + + (kexec + "Reboot the system and run kexec." + (lambda (running) + (catch 'quit + (cut stop root-service) + (lambda (key) + (local-output (l10n "Rebooting with kexec...")) + (reboot-kexec))))) ;; Evaluate arbitrary code. (load "Load the Scheme code from FILE into shepherd. This is potentially diff --git a/modules/shepherd/system.scm.in b/modules/shepherd/system.scm.in index 4c83175..1168c15 100644 --- a/modules/shepherd/system.scm.in +++ b/modules/shepherd/system.scm.in @@ -26,6 +26,7 @@ #:use-module (srfi srfi-26) #:export (disable-reboot-on-ctrl-alt-del reboot + reboot-kexec halt power-off max-file-descriptors @@ -51,6 +52,7 @@ (define RB_HALT_SYSTEM @RB_HALT_SYSTEM@) (define RB_POWER_OFF @RB_POWER_OFF@) (define RB_DISABLE_CAD @RB_DISABLE_CAD@) ; integer | #f +(define RB_KEXEC @RB_KEXEC@) ; integer | #f (define (syscall->procedure return-type name argument-types) "Return a procedure that wraps the C function NAME using the dynamic FFI, @@ -95,6 +97,14 @@ ctrlaltdel(8) and see kernel/reboot.c in Linux." "Perform a hard reset of the system now. Return #f on failure." (%libc-reboot RB_AUTOBOOT)) +(define (reboot-kexec) + "Execute kernel loaded with 'kexec -l' now. Kexec is a feature of the +Linux kernel that allows you to instantly reboot into a new kernel while skipping +the BIOS phase. Return #f on failure or throw an exception on non-Linux systems." + (if RB_KEXEC + (%libc-reboot RB_KEXEC) + (throw 'system-error 'kexec "~A" (list (strerror ENOSYS)) (list ENOSYS)))) + (define (halt) "Halt the system. Return #f on failure." (%libc-reboot RB_HALT_SYSTEM)) diff --git a/tests/status-sexp.sh b/tests/status-sexp.sh index 14b1e72..3fa0283 100644 --- a/tests/status-sexp.sh +++ b/tests/status-sexp.sh @@ -91,7 +91,7 @@ root_service_sexp=" (transient? #f) (respawn-limit (5 . 7)) (respawn-delay 0.1) - (actions (help status halt power-off load eval unload reload daemonize restart)) + (actions (help status halt power-off kexec load eval unload reload daemonize restart)) (exit-statuses ()) (recent-messages ()) (log-files (\"$PWD/$log\")) -- 2.46.0