Re: [PATCH 1/1] x86/crash: reserve elfcorehdr for CONFIG_NR_CPUS, not CONFIG_NR_CPUS_DEFAULT
Jinjie Ruan <[email protected]>
| Newsgroups | org.infradead.lists.kexec,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
在 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() Right > 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 +++--- > 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; Could we just use num_possible_cpus()? Either way, I think it's okay. Reviewed-by: Jinjie Ruan <[email protected]> > if (IS_ENABLED(CONFIG_MEMORY_HOTPLUG)) > sz += CONFIG_CRASH_MAX_MEMORY_RANGES; > sz *= sizeof(Elf64_Phdr);