[PATCH] kexec: fix kexec_file_load fallback error handling
Mukesh Pilaniya
mpilaniy at redhat.com
Fri Aug 14 00:53:29 PDT 2026
With the default -a (--kexec-syscall-auto) option, kexec-tools first
tries kexec_file_load() and falls back to kexec_load() when the syscall
is not implemented (ENOSYS) or the kernel does not have a loader for the
image format (ENOEXEC/ENOTSUP). With -s (--kexec-file-syscall),
kexec-tools uses only kexec_file_load() and does not fall back.
Falling back on EINVAL hides the real error, because EINVAL means
something went wrong during loading.
Remove EINVAL from the fallback path. Print the actual errno for
ENOEXEC/ENOTSUP before falling back and track it so the final message
distinguishes a missing syscall from other failures.
Several kexec_file_load() image probe functions incorrectly return
-EINVAL rather than -ENOEXEC when encountering an unrecognized image
format. This kernel patch fixes the issue:
https://lore.kernel.org/all/20260813-mpilaniy-v1-1-777d4d0e30f7@redhat.com/
Signed-off-by: Mukesh Pilaniya <mpilaniy at redhat.com>
Reviewed-by: Tao Liu <ltao at redhat.com>
Reviewed-by: Philipp Rudo <prudo at redhat.com>
---
kernel patch:
https://lore.kernel.org/all/20260813-mpilaniy-v1-1-777d4d0e30f7@redhat.com/
---
kexec/kexec.c | 63 ++++++++++++++++++++++++++++++++++++---------------
1 file changed, 45 insertions(+), 18 deletions(-)
diff --git a/kexec/kexec.c b/kexec/kexec.c
index 4a49ad4..0726996 100644
--- a/kexec/kexec.c
+++ b/kexec/kexec.c
@@ -68,6 +68,8 @@ int do_hotplug = 0;
static unsigned long kexec_flags = 0;
/* Flags for kexec file (fd) based syscall */
static unsigned long kexec_file_flags = 0;
+/* errno from kexec_file_load when it returned EFALLBACK */
+static int kexec_file_load_errno;
/* initrd detected in probe phase */
int implicit_initrd_fd = -1;
int kexec_debug = 0;
@@ -869,12 +871,16 @@ static int my_load(const char *type, int fileind, int argc, char **argv,
info.nr_segments, info.segment,
info.kexec_flags);
if (result != 0) {
- /* The load failed, print some debugging information */
- fprintf(stderr, "kexec_load failed: %s\n",
- strerror(errno));
- fprintf(stderr, "entry = %p flags = 0x%lx\n",
- info.entry, info.kexec_flags);
- print_segments(stderr, &info);
+ if (errno == ENOSYS) {
+ fprintf(stderr,
+ "syscall kexec_load is not available on this system.\n");
+ } else {
+ fprintf(stderr, "kexec_load failed: %s\n",
+ strerror(errno));
+ fprintf(stderr, "entry = %p flags = 0x%lx\n",
+ info.entry, info.kexec_flags);
+ print_segments(stderr, &info);
+ }
}
return result;
}
@@ -883,12 +889,15 @@ static int kexec_file_unload(unsigned long kexec_file_flags)
{
int ret = 0;
- if (!is_kexec_file_load_implemented())
+ if (!is_kexec_file_load_implemented()) {
+ kexec_file_load_errno = ENOSYS;
return EFALLBACK;
+ }
ret = kexec_file_load(-1, -1, 0, NULL, kexec_file_flags);
if (ret != 0) {
if (errno == ENOSYS) {
+ kexec_file_load_errno = ENOSYS;
ret = EFALLBACK;
} else {
/*
@@ -919,9 +928,12 @@ static int k_unload (unsigned long kexec_flags)
else
result = kexec_load(NULL, 0, NULL, kexec_flags);
if (result != 0) {
- /* The unload failed, print some debugging information */
- fprintf(stderr, "kexec unload failed: %s\n",
- strerror(errno));
+ if (errno == ENOSYS)
+ fprintf(stderr,
+ "syscall kexec_load is not available on this system.\n");
+ else
+ fprintf(stderr, "kexec unload failed: %s\n",
+ strerror(errno));
}
return result;
}
@@ -1336,8 +1348,10 @@ static int do_kexec_file_load(int fileind, int argc, char **argv,
info.kernel_fd = -1;
info.initrd_fd = -1;
- if (!is_kexec_file_load_implemented())
+ if (!is_kexec_file_load_implemented()) {
+ kexec_file_load_errno = ENOSYS;
return EFALLBACK;
+ }
if (argc - fileind <= 0) {
fprintf(stderr, "No kernel specified\n");
@@ -1441,13 +1455,14 @@ static int do_kexec_file_load(int fileind, int argc, char **argv,
/* Not implemented. */
case ENOSYS:
+ kexec_file_load_errno = ENOSYS;
+ ret = EFALLBACK;
+ break;
+
/*
- * Parsing image or other options failed
- * The image may be invalid or image
- * type may not supported by kernel so
- * retry parsing in kexec-tools.
+ * The kernel does not have a loader for this
+ * image format, retry parsing in kexec-tools.
*/
- case EINVAL:
case ENOEXEC:
/*
* ENOTSUP can be unsupported image
@@ -1455,6 +1470,9 @@ static int do_kexec_file_load(int fileind, int argc, char **argv,
* wrapper type, duh.
*/
case ENOTSUP:
+ kexec_file_load_errno = errno;
+ fprintf(stderr, "kexec_file_load failed: %s\n",
+ strerror(errno));
ret = EFALLBACK;
break;
}
@@ -1823,8 +1841,17 @@ int main(int argc, char *argv[])
if ((result == 0) && do_load_jump_back_helper) {
result = my_load_jump_back_helper(kexec_flags, entry);
}
- if (result == EFALLBACK)
- fputs("syscall kexec_file_load not available.\n", stderr);
+ /*
+ * When fallback to kexec_load was attempted, my_load()
+ * already reported the kexec_load error and overwrote
+ * result with its own return value, so this condition
+ * is only true when no fallback was attempted and
+ * kexec_file_load does not exist.
+ */
+ if (result == EFALLBACK && kexec_file_load_errno == ENOSYS) {
+ fputs("syscall kexec_file_load is not available on this system.\n",
+ stderr);
+ }
fflush(stdout);
fflush(stderr);
--
2.50.1 (Apple Git-155)
More information about the kexec
mailing list