[PATCH v3 0/2] x86/crash: fix kexec_file_load(2) -EINVAL on machines with many possible CPUs

From: Ionut Nechita (Wind River)

Date: Wed Aug 26 2026 - 03:39:05 EST


From: Ionut Nechita <ionut.nechita@xxxxxxxxxxxxx>

Hi,

On x86 with CONFIG_CRASH_HOTPLUG=y and CONFIG_MEMORY_HOTPLUG=n, the
crash elfcorehdr segment is reserved for

nr_mem_ranges + 2 + CONFIG_NR_CPUS_DEFAULT

program headers, while the header that crash_prepare_elf64_headers()
actually builds carries

nr_mem_ranges + 2 + num_possible_cpus()

of them. num_possible_cpus() is bounded by CONFIG_NR_CPUS, not by
CONFIG_NR_CPUS_DEFAULT, so on configs that raise CONFIG_NR_CPUS above
the arch default without MAXSMP the header outgrows its reservation once
the excess exceeds the page padding, and kexec_file_load(2) is rejected
by sanity_check_segment_list() with -EINVAL.

Patch 1 reserves the elfcorehdr for CONFIG_NR_CPUS, the compile-time
upper bound of num_possible_cpus(), so the reservation always covers the
header that is actually generated. It also fixes the same shortfall in
arch_crash_get_elfcorehdr_size(), which feeds
/sys/kernel/crash_elfcorehdr_size and therefore the kexec_load(2) path.

Patch 2 is a documentation-only follow-up requested during v1 review: it
updates the two remaining places that still name NR_CPUS_DEFAULT when
describing the elfcorehdr sizing (the comment above
crash_handle_hotplug_event() and the CRASH_MAX_MEMORY_RANGES help text).

Based on linux-next (next-20260825, base-commit a8406e6c0b79b).

Verified on a single-socket Xeon 6776P running a PREEMPT_RT kernel with:

# CONFIG_MAXSMP is not set
# CONFIG_MEMORY_HOTPLUG is not set
CONFIG_NR_CPUS_RANGE_BEGIN=2
CONFIG_NR_CPUS_RANGE_END=512
CONFIG_NR_CPUS_DEFAULT=64
CONFIG_NR_CPUS=256
CONFIG_CRASH_MAX_MEMORY_RANGES=8192

- 144 possible CPUs: excess is (144 - 64) * 56 = 4480 bytes, more than
the 4096 bytes of page padding, so 'kexec -p -s' fails with
"kexec_file_load failed: Invalid argument"
- 72 possible CPUs (reduced via firmware): excess is (72 - 64) * 56 =
448 bytes, still absorbed by the page rounding, and the load succeeds

Changes since v2:
- No code changes. The diff is byte-identical to v2; only the patch 1/2
changelog and the collected tags differ.
- Patch 1/2: corrected the claim that kexec_load(2) is "unaffected".
As Sourabh Jain pointed out, with crash hotplug enabled kexec-tools
sizes the elfcorehdr segment from /sys/kernel/crash_elfcorehdr_size in
load_crashdump_segments(), i.e. from arch_crash_get_elfcorehdr_size(),
which uses the same CONFIG_NR_CPUS_DEFAULT; add_segment_phys_virt()
then clamps bufsz to memsz. So that path does not fail the load, it
silently truncates the elfcorehdr, which shows up later as a bad dump.
Switching arch_crash_get_elfcorehdr_size() to CONFIG_NR_CPUS - which
this patch already did - fixes that path as well. The changelog now
says so instead of claiming immunity.
- Patch 1/2: picked up Reviewed-by from Sourabh Jain and Acked-by from
Baoquan He.
- Patch 2/2: picked up Reviewed-by from Bradley Morgan.
- Both patches: added an Assisted-by: LLM trailer, per
Documentation/process/coding-assistants.rst. An LLM was used for the
root cause analysis and the changelog wording; the bug itself was
found and reproduced on real hardware, the fix was reviewed by me, and
the Signed-off-by is mine. This should have been present in v1 and
v2, and was not - my oversight.
- Rebased from next-20260824 onto next-20260825.

The two further issues Sourabh raised on the v2 thread - the
add_segment_phys_virt() bufsz truncation in kexec-tools, and having
crash_load_segments() skip the kbuf.memsz update when the prepared
buffer is already larger than the statically computed size - are
deliberately left out of this series and are worth handling separately,
as he suggested.

On the num_possible_cpus() alternative raised by Jinjie in v1: it would
give a tighter reservation and powerpc's arch_crash_get_elfcorehdr_size()
already does exactly that. I kept CONFIG_NR_CPUS here because it is the
minimal, easy-to-backport fix - it just swaps the wrong compile-time
constant for the correct compile-time upper bound. I am happy to respin
with num_possible_cpus() if maintainers prefer that.

v1: https://lore.kernel.org/lkml/20260812170433.533845-1-ionut.nechita@xxxxxxxxxxxxx/
v2: https://lore.kernel.org/lkml/20260825075043.42041-1-ionut.nechita@xxxxxxxxxxxxx/

Ionut Nechita (2):
x86/crash: reserve elfcorehdr for CONFIG_NR_CPUS, not
CONFIG_NR_CPUS_DEFAULT
crash: update stale NR_CPUS_DEFAULT references in elfcorehdr sizing
docs

arch/x86/kernel/crash.c | 6 +++---
kernel/Kconfig.kexec | 2 +-
kernel/crash_core.c | 2 +-
3 files changed, 5 insertions(+), 5 deletions(-)


base-commit: a8406e6c0b793ce0788019683837c40855b55995
--
2.55.0