]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
shutdown: Add Xen kexec support
authorSamuel Thibault <samuel.thibault@ens-lyon.org>
Tue, 1 Nov 2022 15:53:02 +0000 (16:53 +0100)
committerLuca Boccassi <luca.boccassi@gmail.com>
Wed, 2 Nov 2022 19:47:41 +0000 (20:47 +0100)
In the Xen case, it's the hypervisor which manages kexec. We thus
have to ask it whether a kernel is loaded, instead of relying on
/sys/kernel/kexec_loaded.

15 files changed:
.github/workflows/build_test.sh
meson.build
meson_options.txt
mkosi.default.d/debian/10-mkosi.debian
mkosi.default.d/fedora/10-mkosi.fedora
mkosi.default.d/opensuse/10-mkosi.opensuse
mkosi.default.d/ubuntu/10-mkosi.ubuntu
src/basic/util.c
src/basic/util.h
src/initctl/initctl.c
src/shared/meson.build
src/shared/reboot-util.c
src/shared/reboot-util.h
src/systemctl/systemctl-compat-shutdown.c
src/systemctl/systemctl.c

index b60db29efcb3bdeb4544171094c192ca1c1e36d3..1eed81600cc79c091bd3822c4b17ed2b8d11c992 100755 (executable)
@@ -42,6 +42,7 @@ PACKAGES=(
     libqrencode-dev
     libssl-dev
     libtss2-dev
+    libxen-dev
     libxkbcommon-dev
     libxtables-dev
     libzstd-dev
index ce23181cb49625ec74c218f836dd8bb9456a8b78..b128d6b00b8b1a7602ff32e7a3a692f90f16e19f 100644 (file)
@@ -1273,6 +1273,18 @@ else
 endif
 conf.set10('HAVE_KMOD', have)
 
+want_xenctrl = get_option('xenctrl')
+if want_xenctrl != 'false' and not skip_deps
+        libxenctrl = dependency('xencontrol',
+                                version : '>= 4.9',
+                                required : want_xenctrl == 'true')
+        have = libxenctrl.found()
+else
+        have = false
+        libxenctrl = []
+endif
+conf.set10('HAVE_XENCTRL', have)
+
 want_pam = get_option('pam')
 if want_pam != 'false' and not skip_deps
         libpam = cc.find_library('pam', required : want_pam == 'true')
@@ -4398,6 +4410,7 @@ foreach tuple : [
         ['nscd'],
         ['legacy-pkla',            install_polkit_pkla],
         ['kmod'],
+        ['xenctrl'],
         ['dbus'],
         ['glib'],
         ['tpm'],
index 814f34084099a21cd259a565b591a1c0d5d93e0e..19e9c2d990949feffd9a5c954a278c6195f85a51 100644 (file)
@@ -371,6 +371,8 @@ option('fdisk', type : 'combo', choices : ['auto', 'true', 'false'],
        description : 'libfdisk support')
 option('kmod', type : 'combo', choices : ['auto', 'true', 'false'],
        description : 'support for loadable modules')
+option('xenctrl', type : 'combo', choices : ['auto', 'true', 'false'],
+       description : 'support for Xen kexec')
 option('pam', type : 'combo', choices : ['auto', 'true', 'false'],
        description : 'PAM support')
 option('pwquality', type : 'combo', choices : ['auto', 'true', 'false'],
index 3eea0c74b94dec66aed9510efb344683b780fd41..fcde20e8fb5ecd67710e4edc6f094545b4ff555c 100644 (file)
@@ -61,6 +61,7 @@ BuildPackages=
         libseccomp-dev
         libsmartcols-dev
         libssl-dev
+        libxen-dev
         libxkbcommon-dev
         libzstd-dev
         pahole
index ab230f0b243cbf9081ffd07de078cfaf4c840a7c..8154bd1b7481c21ebf5f03f7e83106bf657205a3 100644 (file)
@@ -67,6 +67,7 @@ BuildPackages=
         pkgconfig(tss2-mu)
         pkgconfig(tss2-rc)
         pkgconfig(valgrind)
+        pkgconfig(xencontrol)
         pkgconfig(xkbcommon)
         python3dist(jinja2)
         python3dist(lxml)
index 804213baabf7ccfe1c8348c440b03a16113d81c1..b59e7b2333008733cb5e0dc43c1ae2f3486ef3aa 100644 (file)
@@ -80,4 +80,5 @@ BuildPackages=
         systemd-sysvinit
         timezone
         tpm2-0-tss-devel
+        xen-devel
         zlib-devel
index 14f337b7ea9f162d0cbe53ccf5fa595542ec9824..192c37888656b309bad97e5f4bd324ac65563e53 100644 (file)
@@ -62,6 +62,7 @@ BuildPackages=
         libseccomp-dev
         libsmartcols-dev
         libssl-dev
+        libxen-dev
         libxkbcommon-dev
         libzstd-dev
         pahole
index d7ef382737e913a035e00f25d77642e90c4c4974..fbcb87001a900d55be06176674134c67a6996130 100644 (file)
@@ -23,15 +23,6 @@ int saved_argc = 0;
 char **saved_argv = NULL;
 static int saved_in_initrd = -1;
 
-bool kexec_loaded(void) {
-       _cleanup_free_ char *s = NULL;
-
-       if (read_one_line_file("/sys/kernel/kexec_loaded", &s) < 0)
-               return false;
-
-       return s[0] == '1';
-}
-
 int prot_from_flags(int flags) {
 
         switch (flags & O_ACCMODE) {
index 68ae3b51e0e0a897ee02b8661ca95589141459f1..5d5d8216108391291b721dcf80948a4ec44e854d 100644 (file)
@@ -19,8 +19,6 @@ static inline void save_argc_argv(int argc, char **argv) {
         saved_argv = argv;
 }
 
-bool kexec_loaded(void);
-
 int prot_from_flags(int flags) _const_;
 
 bool in_initrd(void);
index 52b1ba199a177aeb905d67deba7e3eebd0fac31c..e1b85d521835e1395645f7635429b32d09286ebb 100644 (file)
@@ -24,6 +24,7 @@
 #include "main-func.h"
 #include "memory-util.h"
 #include "process-util.h"
+#include "reboot-util.h"
 #include "special.h"
 
 #define SERVER_FD_MAX 16
index 9e11e1393448b7d28ffd0cd418be9a08578a9d40..97e52c2335df826a9ee96e2f86b02059c4c93a08 100644 (file)
@@ -465,7 +465,8 @@ libshared_deps = [threads,
                   libseccomp,
                   libselinux,
                   libzstd,
-                  libxz]
+                  libxz,
+                  libxenctrl]
 
 libshared_sym_path = '@0@/libshared.sym'.format(meson.current_source_dir())
 
index 756f9d30e0becb51ff9018e957d4c2538134a487..e761bc25a4a83d6373c93b857ab1e05cd7a6d9ac 100644 (file)
@@ -1,11 +1,28 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
 #include <unistd.h>
 
+#if HAVE_XENCTRL
+#define __XEN_INTERFACE_VERSION__ 0x00040900
+#include <xen/xen.h>
+#include <xen/kexec.h>
+#include <xen/sys/privcmd.h>
+#endif
+
 #include "alloc-util.h"
+#include "errno-util.h"
+#include "fd-util.h"
 #include "fileio.h"
 #include "log.h"
+#include "memory-util.h"
 #include "proc-cmdline.h"
 #include "raw-reboot.h"
 #include "reboot-util.h"
@@ -107,3 +124,74 @@ int shall_restore_state(void) {
 
         return r > 0 ? ret : true;
 }
+
+static int xen_kexec_loaded(void) {
+#if HAVE_XENCTRL
+        size_t size;
+        _cleanup_close_ int privcmd_fd = -1, buf_fd = -1;
+        void *buffer;
+        int r;
+
+        if (access("/proc/xen", F_OK) < 0) {
+                if (errno == ENOENT)
+                        return -EOPNOTSUPP;
+                return log_debug_errno(errno, "Unable to test whether /proc/xen exists: %m");
+        }
+
+        size = page_size();
+        if (sizeof(xen_kexec_status_t) > size)
+                return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "page_size is too small for hypercall");
+
+        privcmd_fd = open("/dev/xen/privcmd", O_RDWR|O_CLOEXEC);
+        if (privcmd_fd < 0)
+                return log_debug_errno(errno, "Cannot access /dev/xen/privcmd: %m");
+
+        buf_fd = open("/dev/xen/hypercall", O_RDWR|O_CLOEXEC);
+        if (buf_fd < 0)
+                return log_debug_errno(errno, "Cannot access /dev/xen/hypercall: %m");
+
+        buffer = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, buf_fd, 0);
+        if (buffer == MAP_FAILED)
+                return log_debug_errno(errno, "Cannot allocate buffer for hypercall: %m");
+
+        *(xen_kexec_status_t*) buffer = (xen_kexec_status_t) {
+                .type = KEXEC_TYPE_DEFAULT,
+        };
+
+        privcmd_hypercall_t call = {
+                .op = __HYPERVISOR_kexec_op,
+                .arg = {
+                        KEXEC_CMD_kexec_status,
+                        PTR_TO_UINT64(buffer),
+                },
+        };
+
+        r = RET_NERRNO(ioctl(privcmd_fd, IOCTL_PRIVCMD_HYPERCALL, &call));
+        if (r < 0)
+                log_debug_errno(r, "kexec_status failed: %m");
+
+        munmap(buffer, size);
+
+        return r;
+#else
+        return -EOPNOTSUPP;
+#endif
+}
+
+bool kexec_loaded(void) {
+       _cleanup_free_ char *s = NULL;
+       int r;
+
+       r = xen_kexec_loaded();
+       if (r >= 0)
+               return r;
+
+       r = read_one_line_file("/sys/kernel/kexec_loaded", &s);
+       if (r < 0) {
+               if (r != -ENOENT)
+                       log_debug_errno(r, "Unable to read /sys/kernel/kexec_loaded, ignoring: %m");
+               return false;
+       }
+
+       return s[0] == '1';
+}
index bbca8b858d7018bab892006fb9bebece68b40075..9e6366206e56030b4e447a7d0c02b88c32578d5e 100644 (file)
@@ -13,3 +13,5 @@ int read_reboot_parameter(char **parameter);
 int reboot_with_parameter(RebootFlags flags);
 
 int shall_restore_state(void);
+
+bool kexec_loaded(void);
index 6571802f95bf8bbd972e5d169630acdc30b05941..9d39e362eae54a434ec48745071bd7a2554f06ff 100644 (file)
@@ -4,6 +4,7 @@
 
 #include "alloc-util.h"
 #include "pretty-print.h"
+#include "reboot-util.h"
 #include "systemctl-compat-shutdown.h"
 #include "systemctl-sysv-compat.h"
 #include "systemctl.h"
index 5858c3f6d34d9fb6c85bd92cc043a8ef8b52626a..02a298d5729bd646e224969fb4c1827f269653f0 100644 (file)
@@ -17,6 +17,7 @@
 #include "path-util.h"
 #include "pretty-print.h"
 #include "process-util.h"
+#include "reboot-util.h"
 #include "rlimit-util.h"
 #include "sigbus.h"
 #include "signal-util.h"