[PATCH 1/1] x86/crash: reserve elfcorehdr for CONFIG_NR_CPUS, not CONFIG_NR_CPUS_DEFAULT

Jinjie Ruan ruanjinjie at huawei.com
Thu Aug 13 19:05:59 PDT 2026



在 2026/8/13 1:04, Ionut Nechita (Wind River) 写道:
> From: Ionut Nechita <ionut.nechita at windriver.com>
> 
> 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 <ionut.nechita at windriver.com>
> ---
>  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 <ruanjinjie at huawei.com>

>  	if (IS_ENABLED(CONFIG_MEMORY_HOTPLUG))
>  		sz += CONFIG_CRASH_MAX_MEMORY_RANGES;
>  	sz *= sizeof(Elf64_Phdr);




More information about the kexec mailing list