[PATCH 1/1] x86/crash: reserve elfcorehdr for CONFIG_NR_CPUS, not CONFIG_NR_CPUS_DEFAULT
"Ionut Nechita (Wind River)" <[email protected]>
| Newsgroups | org.infradead.lists.kexec,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
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 +++--- 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); -- 2.43.0