Re: [PATCH 1/1] x86/crash: reserve elfcorehdr for CONFIG_NR_CPUS, not CONFIG_NR_CPUS_DEFAULT
Bradley Morgan <[email protected]>
| Newsgroups | org.infradead.lists.kexec,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
On 17 August 2026 02:18:59 BST, Jinjie Ruan <[email protected]> wrote: > > >在 2026/8/13 1:04, Ionut Nechita (Wind River) 写道: >> From: Ionut Nechita <[email protected]> >> >> kexec_file_load(2) fails with -EINVAL when loading a crash kernel on a >> machine whose number of possible CPUs exceeds CONFIG_NR_CPUS_DEFAULT, >> even though the classic kexec_load(2) path succeeds on the same machine. >> >> With CONFIG_CRASH_HOTPLUG=y the elfcorehdr segment is over-allocated so >> it can be updated in place on CPU/memory hotplug. crash_load_segments() >> and arch_crash_get_elfcorehdr_size() compute that reservation from >> CONFIG_NR_CPUS_DEFAULT: >> >> if (IS_ENABLED(CONFIG_MEMORY_HOTPLUG)) >> pnum = 2 + CONFIG_NR_CPUS_DEFAULT + CONFIG_CRASH_MAX_MEMORY_RANGES; >> else >> pnum += 2 + CONFIG_NR_CPUS_DEFAULT; >> >> However the actual header produced by crash_prepare_elf64_headers() >> contains one PT_NOTE per *possible* CPU, i.e. num_possible_cpus(), which >> is bounded by CONFIG_NR_CPUS, not by CONFIG_NR_CPUS_DEFAULT. On configs >> that raise CONFIG_NR_CPUS above the arch default while leaving >> CONFIG_NR_CPUS_DEFAULT untouched (e.g. CONFIG_NR_CPUS=256, >> CONFIG_NR_CPUS_DEFAULT=64 on x86_64 without MAXSMP), a system with more >> than ~CONFIG_NR_CPUS_DEFAULT possible CPUs builds a header whose bufsz >> exceeds the reserved, page-aligned memsz. sanity_check_segment_list() >> then rejects the image: >> >> if (image->segment[i].bufsz > image->segment[i].memsz) >> return -EINVAL; >> >> kexec_load(2) is unaffected because user space builds the elfcorehdr >> without the hotplug over-allocation. >> >> Observed on a single-socket Xeon 6776P (144 possible CPUs) running a >> PREEMPT_RT kernel with: >> >> # CONFIG_MAXSMP is not set >> CONFIG_NR_CPUS_RANGE_BEGIN=2 >> CONFIG_NR_CPUS_RANGE_END=512 >> CONFIG_NR_CPUS_DEFAULT=64 >> CONFIG_NR_CPUS=256 >> >> kexec -p -s fails with "kexec_file_load failed: Invalid argument". >> Reducing the possible CPU count below the page-rounding threshold >> (e.g. 72 via firmware) makes it succeed, confirming the reservation is >> the limiting factor. >> >> Reserve 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. >> >> Fixes: a72bbec70da2 ("crash: hotplug support for kexec_load()") >> Signed-off-by: Ionut Nechita <[email protected]> >> --- >> arch/x86/kernel/crash.c | 6 +++--- > >We should also update the comment in crash_handle_hotplug_event() to >avoid misleading people. > >diff --git a/kernel/crash_core.c b/kernel/crash_core.c >index 4f21fc3b108b..b046c1682aad 100644 >--- a/kernel/crash_core.c >+++ b/kernel/crash_core.c >@@ -565,7 +565,7 @@ int crash_check_hotplug_support(void) > * new list of CPUs and memory. To make changes to the elfcorehdr, it > * should be large enough to permit a growing number of CPU and Memory > * resources. One can estimate the elfcorehdr memory size based on >- * NR_CPUS_DEFAULT and CRASH_MAX_MEMORY_RANGES. The elfcorehdr is >+ * NR_CPUS and CRASH_MAX_MEMORY_RANGES. The elfcorehdr is One more spot carries the same stale name though: kernel/Kconfig.kexec: "This value is combined with NR_CPUS_DEFAULT and multiplied by sizeof(Elf64_Phdr) to determine the final elfcorehdr memory buffer/segment size." The CRASH_MAX_MEMORY_RANGES help text needs the same s/NR_CPUS_DEFAULT/NR_CPUS/, either here or in Ionut's v2. Reviewed-by: Bradley Morgan <[email protected]> > * excluded from SHA verification by default if the architecture > * supports crash hotplug. > */ > > >> 1 file changed, 3 insertions(+), 3 deletions(-) >> >> diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c >> index e681ec9cf1dc8..e6f23933a6df2 100644 >> --- a/arch/x86/kernel/crash.c >> +++ b/arch/x86/kernel/crash.c >> @@ -369,9 +369,9 @@ int crash_load_segments(struct kimage *image) >> * maximum CPUs and maximum memory ranges. >> */ >> if (IS_ENABLED(CONFIG_MEMORY_HOTPLUG)) >> - pnum = 2 + CONFIG_NR_CPUS_DEFAULT + CONFIG_CRASH_MAX_MEMORY_RANGES; >> + pnum = 2 + CONFIG_NR_CPUS + CONFIG_CRASH_MAX_MEMORY_RANGES; >> else >> - pnum += 2 + CONFIG_NR_CPUS_DEFAULT; >> + pnum += 2 + CONFIG_NR_CPUS; >> >> if (pnum < (unsigned long)PN_XNUM) { >> kbuf.memsz = pnum * sizeof(Elf64_Phdr); >> @@ -430,7 +430,7 @@ unsigned int arch_crash_get_elfcorehdr_size(void) >> unsigned int sz; >> >> /* kernel_map, VMCOREINFO and maximum CPUs */ >> - sz = 2 + CONFIG_NR_CPUS_DEFAULT; >> + sz = 2 + CONFIG_NR_CPUS; >> if (IS_ENABLED(CONFIG_MEMORY_HOTPLUG)) >> sz += CONFIG_CRASH_MAX_MEMORY_RANGES; >> sz *= sizeof(Elf64_Phdr); > > > Thanks!