shutdown: remove kexec-tools dependency

'kexec -e' is just a small wrapper that does the xen hypercall
on xen, or otherwise just calls reboot(). Drop the dependency,
and reuse the existing xen hypercall helper.
This commit is contained in:
Luca Boccassi
2026-03-27 23:03:01 +01:00
committed by Daan De Meyer
parent 5f2258affc
commit 1224e5d195
4 changed files with 46 additions and 27 deletions
-4
View File
@@ -222,10 +222,6 @@ static int handle_action_execute(
assert(m);
assert(!IN_SET(handle, HANDLE_IGNORE, HANDLE_LOCK, HANDLE_SLEEP));
if (handle == HANDLE_KEXEC && access(KEXEC, X_OK) < 0)
return log_warning_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"Requested %s operation not supported, ignoring.", handle_action_to_string(handle));
if (m->delayed_action)
return log_debug_errno(SYNTHETIC_ERRNO(EALREADY),
"Action %s already in progress, ignoring requested %s operation.",
+44 -8
View File
@@ -139,13 +139,15 @@ bool shall_restore_state(void) {
return (cached = b);
}
static int xen_kexec_loaded(void) {
#if HAVE_XENCTRL
static int xen_kexec_command(uint64_t cmd) {
_cleanup_close_ int privcmd_fd = -EBADF, buf_fd = -EBADF;
xen_kexec_status_t *buffer;
void *buffer;
size_t size;
int r;
assert(IN_SET(cmd, KEXEC_CMD_kexec, KEXEC_CMD_kexec_status));
if (access("/proc/xen", F_OK) < 0) {
if (errno == ENOENT)
return -EOPNOTSUPP;
@@ -153,7 +155,8 @@ static int xen_kexec_loaded(void) {
}
size = page_size();
if (sizeof(xen_kexec_status_t) > size)
if ((cmd == KEXEC_CMD_kexec_status && sizeof(xen_kexec_status_t) > size) ||
(cmd == KEXEC_CMD_kexec && sizeof(xen_kexec_exec_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);
@@ -168,25 +171,44 @@ static int xen_kexec_loaded(void) {
if (buffer == MAP_FAILED)
return log_debug_errno(errno, "Cannot allocate buffer for hypercall: %m");
*buffer = (xen_kexec_status_t) {
.type = KEXEC_TYPE_DEFAULT,
};
if (cmd == KEXEC_CMD_kexec_status)
*(xen_kexec_status_t *)buffer = (xen_kexec_status_t) {
.type = KEXEC_TYPE_DEFAULT,
};
else
*(xen_kexec_exec_t *)buffer = (xen_kexec_exec_t) {
.type = KEXEC_TYPE_DEFAULT,
};
privcmd_hypercall_t call = {
.op = __HYPERVISOR_kexec_op,
.arg = {
KEXEC_CMD_kexec_status,
cmd,
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");
log_debug_errno(r, "kexec%s failed: %m", cmd == KEXEC_CMD_kexec_status ? "_status" : "");
munmap(buffer, size);
return r;
}
#endif
static int xen_kexec(void) {
#if HAVE_XENCTRL
return xen_kexec_command(KEXEC_CMD_kexec);
#else
return -EOPNOTSUPP;
#endif
}
static int xen_kexec_loaded(void) {
#if HAVE_XENCTRL
return xen_kexec_command(KEXEC_CMD_kexec_status);
#else
return -EOPNOTSUPP;
#endif
@@ -210,6 +232,20 @@ bool kexec_loaded(void) {
return s[0] == '1';
}
int kexec(void) {
int r;
r = xen_kexec();
if (r < 0 && r != -EOPNOTSUPP)
return log_error_errno(r, "Failed to call xen kexec: %m");
r = reboot(LINUX_REBOOT_CMD_KEXEC);
if (r < 0)
return log_error_errno(errno, "Failed to kexec: %m");
return 0;
}
int create_shutdown_run_nologin_or_warn(void) {
int r;
+1
View File
@@ -26,5 +26,6 @@ int reboot_with_parameter(RebootFlags flags);
bool shall_restore_state(void);
bool kexec_loaded(void);
int kexec(void);
int create_shutdown_run_nologin_or_warn(void);
+1 -15
View File
@@ -609,23 +609,9 @@ int main(int argc, char *argv[]) {
case LINUX_REBOOT_CMD_KEXEC:
if (!in_container) {
/* We cheat and exec kexec to avoid doing all its work */
log_info("Rebooting with kexec.");
r = pidref_safe_fork(
"(sd-kexec)",
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_LOG|FORK_WAIT,
/* ret= */ NULL);
if (r == 0) {
/* Child */
(void) execl(KEXEC, KEXEC, "-e", NULL);
log_debug_errno(errno, "Failed to execute '" KEXEC "' binary, proceeding with reboot(RB_KEXEC): %m");
/* execv failed (kexec binary missing?), so try simply reboot(RB_KEXEC) */
(void) reboot(cmd);
_exit(EXIT_FAILURE);
}
(void) kexec();
/* If we are still running, then the kexec can't have worked, let's fall through */
}