diff mbox series

[bug#73992,Shepherd] shepherd: Add support for rebooting using kexec

Message ID ZxqMHnI0nNuvbK71@kernelpanicroom
State New
Headers show
Series [bug#73992,Shepherd] shepherd: Add support for rebooting using kexec | expand

Commit Message

Jakob Kirsch Oct. 24, 2024, 6:04 p.m. UTC
This is my improved patch for using kexec with shepherd as I sent the last one to the wrong address (someone should update the description of the shepherd project to link to the correct patch submission list).
From 762fbee53fb890a7cf5e26abcc2dcfad03b1bab4 Mon Sep 17 00:00:00 2001
From: Jakob Kirsch <jakob.kirsch@web.de>
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(-)

--
2.46.0
diff mbox series

Patch

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 <alex.sassmannshausen@gmail.com>
             David Thompson <dthompson2@worcester.edu>
              Andy Wingo <wingo@pobox.com>
+            Jakob Kirsch <jakob.kirsch@web.de>
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 <sys/reboot.h>])
     AC_COMPUTE_INT([RB_POWER_OFF], [RB_POWER_OFF], [#include <sys/reboot.h>])
     AC_COMPUTE_INT([RB_SW_SUSPEND], [RB_SW_SUSPEND], [#include <sys/reboot.h>])
+    AC_COMPUTE_INT([RB_KEXEC], [RB_KEXEC], [#include <sys/reboot.h>])
     ;;
   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 <sys/reboot.h>])
     AC_COMPUTE_INT([RB_POWER_OFF], [RB_HALT], [#include <sys/reboot.h>])
     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 <sys/reboot.h>])
     AC_COMPUTE_INT([RB_POWER_OFF], [RB_HALT_SYSTEM], [#include <sys/reboot.h>])
     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([<sys/prctl.h> 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\"))