On 02/24/26 at 04:53pm, Jinjie Ruan wrote: > The crash memory alloc, and the exclude of crashk_res, crashk_low_res > and crashk_cma memory are almost identical across different architectures, > handling them in the crash core would eliminate a lot of duplication, so > do them in the common code. > > To achieve the above goal, three architecture-specific functions are > introduced: > > - arch_get_system_nr_ranges(). Pre-counts the max number of memory ranges. > > - arch_crash_populate_cmem(). Collects the memory ranges and fills them > into cmem. > > - arch_crash_exclude_ranges(). Architecture's additional crash memory > ranges exclusion, defaulting to empty. > > Signed-off-by: Jinjie Ruan <[email protected]> > --- > arch/arm64/kernel/machine_kexec_file.c | 39 +++------- > arch/loongarch/kernel/machine_kexec_file.c | 39 +++------- > arch/riscv/kernel/machine_kexec_file.c | 38 +++------ > arch/x86/kernel/crash.c | 89 +++------------------- > include/linux/crash_core.h | 5 ++ > kernel/crash_core.c | 82 +++++++++++++++++++- > 6 files changed, 132 insertions(+), 160 deletions(-)
LGTM, Acked-by: Baoquan He <[email protected]> > > diff --git a/arch/arm64/kernel/machine_kexec_file.c > b/arch/arm64/kernel/machine_kexec_file.c > index fba260ad87a9..c338506a580b 100644 > --- a/arch/arm64/kernel/machine_kexec_file.c > +++ b/arch/arm64/kernel/machine_kexec_file.c > @@ -40,23 +40,23 @@ int arch_kimage_file_post_load_cleanup(struct kimage > *image) > } > > #ifdef CONFIG_CRASH_DUMP > -static int prepare_elf_headers(void **addr, unsigned long *sz) > +unsigned int arch_get_system_nr_ranges(void) > { > - struct crash_mem *cmem; > - unsigned int nr_ranges; > - int ret; > - u64 i; > + unsigned int nr_ranges = 2; /* for exclusion of crashkernel region */ > phys_addr_t start, end; > + u64 i; > > - nr_ranges = 2; /* for exclusion of crashkernel region */ > for_each_mem_range(i, &start, &end) > nr_ranges++; > > - cmem = kmalloc_flex(*cmem, ranges, nr_ranges); > - if (!cmem) > - return -ENOMEM; > + return nr_ranges; > +} > + > +int arch_crash_populate_cmem(struct crash_mem *cmem) > +{ > + phys_addr_t start, end; > + u64 i; > > - cmem->max_nr_ranges = nr_ranges; > cmem->nr_ranges = 0; > for_each_mem_range(i, &start, &end) { > cmem->ranges[cmem->nr_ranges].start = start; > @@ -64,22 +64,7 @@ static int prepare_elf_headers(void **addr, unsigned long > *sz) > cmem->nr_ranges++; > } > > - /* Exclude crashkernel region */ > - ret = crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end); > - if (ret) > - goto out; > - > - if (crashk_low_res.end) { > - ret = crash_exclude_mem_range(cmem, crashk_low_res.start, > crashk_low_res.end); > - if (ret) > - goto out; > - } > - > - ret = crash_prepare_elf64_headers(cmem, true, addr, sz); > - > -out: > - kfree(cmem); > - return ret; > + return 0; > } > #endif > > @@ -109,7 +94,7 @@ int load_other_segments(struct kimage *image, > void *headers; > unsigned long headers_sz; > if (image->type == KEXEC_TYPE_CRASH) { > - ret = prepare_elf_headers(&headers, &headers_sz); > + ret = crash_prepare_headers(true, &headers, &headers_sz, NULL); > if (ret) { > pr_err("Preparing elf core header failed\n"); > goto out_err; > diff --git a/arch/loongarch/kernel/machine_kexec_file.c > b/arch/loongarch/kernel/machine_kexec_file.c > index 5584b798ba46..4b318a94b564 100644 > --- a/arch/loongarch/kernel/machine_kexec_file.c > +++ b/arch/loongarch/kernel/machine_kexec_file.c > @@ -56,23 +56,23 @@ static void cmdline_add_initrd(struct kimage *image, > unsigned long *cmdline_tmpl > } > > #ifdef CONFIG_CRASH_DUMP > - > -static int prepare_elf_headers(void **addr, unsigned long *sz) > +unsigned int arch_get_system_nr_ranges(void) > { > - int ret, nr_ranges; > - uint64_t i; > + int nr_ranges = 2; /* for exclusion of crashkernel region */ > phys_addr_t start, end; > - struct crash_mem *cmem; > + uint64_t i; > > - nr_ranges = 2; /* for exclusion of crashkernel region */ > for_each_mem_range(i, &start, &end) > nr_ranges++; > > - cmem = kmalloc_flex(*cmem, ranges, nr_ranges); > - if (!cmem) > - return -ENOMEM; > + return nr_ranges; > +} > + > +int arch_crash_populate_cmem(struct crash_mem *cmem) > +{ > + phys_addr_t start, end; > + uint64_t i; > > - cmem->max_nr_ranges = nr_ranges; > cmem->nr_ranges = 0; > for_each_mem_range(i, &start, &end) { > cmem->ranges[cmem->nr_ranges].start = start; > @@ -80,22 +80,7 @@ static int prepare_elf_headers(void **addr, unsigned long > *sz) > cmem->nr_ranges++; > } > > - /* Exclude crashkernel region */ > - ret = crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end); > - if (ret < 0) > - goto out; > - > - if (crashk_low_res.end) { > - ret = crash_exclude_mem_range(cmem, crashk_low_res.start, > crashk_low_res.end); > - if (ret < 0) > - goto out; > - } > - > - ret = crash_prepare_elf64_headers(cmem, true, addr, sz); > - > -out: > - kfree(cmem); > - return ret; > + return 0; > } > > /* > @@ -163,7 +148,7 @@ int load_other_segments(struct kimage *image, > void *headers; > unsigned long headers_sz; > > - ret = prepare_elf_headers(&headers, &headers_sz); > + ret = crash_prepare_headers(true, &headers, &headers_sz, NULL); > if (ret < 0) { > pr_err("Preparing elf core header failed\n"); > goto out_err; > diff --git a/arch/riscv/kernel/machine_kexec_file.c > b/arch/riscv/kernel/machine_kexec_file.c > index 54e2d9552e93..d0e331d87155 100644 > --- a/arch/riscv/kernel/machine_kexec_file.c > +++ b/arch/riscv/kernel/machine_kexec_file.c > @@ -44,6 +44,15 @@ static int get_nr_ram_ranges_callback(struct resource > *res, void *arg) > return 0; > } > > +unsigned int arch_get_system_nr_ranges(void) > +{ > + unsigned int nr_ranges = 1; /* For exclusion of crashkernel region */ > + > + walk_system_ram_res(0, -1, &nr_ranges, get_nr_ram_ranges_callback); > + > + return nr_ranges; > +} > + > static int prepare_elf64_ram_headers_callback(struct resource *res, void > *arg) > { > struct crash_mem *cmem = arg; > @@ -55,33 +64,10 @@ static int prepare_elf64_ram_headers_callback(struct > resource *res, void *arg) > return 0; > } > > -static int prepare_elf_headers(void **addr, unsigned long *sz) > +int arch_crash_populate_cmem(struct crash_mem *cmem) > { > - struct crash_mem *cmem; > - unsigned int nr_ranges; > - int ret; > - > - nr_ranges = 1; /* For exclusion of crashkernel region */ > - walk_system_ram_res(0, -1, &nr_ranges, get_nr_ram_ranges_callback); > - > - cmem = kmalloc_flex(*cmem, ranges, nr_ranges); > - if (!cmem) > - return -ENOMEM; > - > - cmem->max_nr_ranges = nr_ranges; > cmem->nr_ranges = 0; > - ret = walk_system_ram_res(0, -1, cmem, > prepare_elf64_ram_headers_callback); > - if (ret) > - goto out; > - > - /* Exclude crashkernel region */ > - ret = crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end); > - if (!ret) > - ret = crash_prepare_elf64_headers(cmem, true, addr, sz); > - > -out: > - kfree(cmem); > - return ret; > + return walk_system_ram_res(0, -1, cmem, > prepare_elf64_ram_headers_callback); > } > > static char *setup_kdump_cmdline(struct kimage *image, char *cmdline, > @@ -273,7 +259,7 @@ int load_extra_segments(struct kimage *image, unsigned > long kernel_start, > if (image->type == KEXEC_TYPE_CRASH) { > void *headers; > unsigned long headers_sz; > - ret = prepare_elf_headers(&headers, &headers_sz); > + ret = crash_prepare_headers(true, &headers, &headers_sz, NULL); > if (ret) { > pr_err("Preparing elf core header failed\n"); > goto out; > diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c > index 335fd2ee9766..3ad3f8b758a4 100644 > --- a/arch/x86/kernel/crash.c > +++ b/arch/x86/kernel/crash.c > @@ -152,16 +152,8 @@ static int get_nr_ram_ranges_callback(struct resource > *res, void *arg) > return 0; > } > > -/* Gather all the required information to prepare elf headers for ram > regions */ > -static struct crash_mem *fill_up_crash_elf_data(void) > +unsigned int arch_get_system_nr_ranges(void) > { > - unsigned int nr_ranges = 0; > - struct crash_mem *cmem; > - > - walk_system_ram_res(0, -1, &nr_ranges, get_nr_ram_ranges_callback); > - if (!nr_ranges) > - return NULL; > - > /* > * Exclusion of crash region, crashk_low_res and/or crashk_cma_ranges > * may cause range splits. So add extra slots here. > @@ -176,49 +168,16 @@ static struct crash_mem *fill_up_crash_elf_data(void) > * But in order to lest the low 1M could be changed in the future, > * (e.g. [start, 1M]), add a extra slot. > */ > - nr_ranges += 3 + crashk_cma_cnt; > - cmem = vzalloc(struct_size(cmem, ranges, nr_ranges)); > - if (!cmem) > - return NULL; > - > - cmem->max_nr_ranges = nr_ranges; > + unsigned int nr_ranges = 3 + crashk_cma_cnt; > > - return cmem; > + walk_system_ram_res(0, -1, &nr_ranges, get_nr_ram_ranges_callback); > + return nr_ranges; > } > > -/* > - * Look for any unwanted ranges between mstart, mend and remove them. This > - * might lead to split and split ranges are put in cmem->ranges[] array > - */ > -static int elf_header_exclude_ranges(struct crash_mem *cmem) > +int arch_crash_exclude_ranges(struct crash_mem *cmem) > { > - int ret = 0; > - int i; > - > /* Exclude the low 1M because it is always reserved */ > - ret = crash_exclude_mem_range(cmem, 0, SZ_1M - 1); > - if (ret) > - return ret; > - > - /* Exclude crashkernel region */ > - ret = crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end); > - if (ret) > - return ret; > - > - if (crashk_low_res.end) > - ret = crash_exclude_mem_range(cmem, crashk_low_res.start, > - crashk_low_res.end); > - if (ret) > - return ret; > - > - for (i = 0; i < crashk_cma_cnt; ++i) { > - ret = crash_exclude_mem_range(cmem, crashk_cma_ranges[i].start, > - crashk_cma_ranges[i].end); > - if (ret) > - return ret; > - } > - > - return 0; > + return crash_exclude_mem_range(cmem, 0, SZ_1M - 1); > } > > static int prepare_elf64_ram_headers_callback(struct resource *res, void > *arg) > @@ -232,35 +191,9 @@ static int prepare_elf64_ram_headers_callback(struct > resource *res, void *arg) > return 0; > } > > -/* Prepare elf headers. Return addr and size */ > -static int prepare_elf_headers(void **addr, unsigned long *sz, > - unsigned long *nr_mem_ranges) > +int arch_crash_populate_cmem(struct crash_mem *cmem) > { > - struct crash_mem *cmem; > - int ret; > - > - cmem = fill_up_crash_elf_data(); > - if (!cmem) > - return -ENOMEM; > - > - ret = walk_system_ram_res(0, -1, cmem, > prepare_elf64_ram_headers_callback); > - if (ret) > - goto out; > - > - /* Exclude unwanted mem ranges */ > - ret = elf_header_exclude_ranges(cmem); > - if (ret) > - goto out; > - > - /* Return the computed number of memory ranges, for hotplug usage */ > - *nr_mem_ranges = cmem->nr_ranges; > - > - /* By default prepare 64bit headers */ > - ret = crash_prepare_elf64_headers(cmem, IS_ENABLED(CONFIG_X86_64), > addr, sz); > - > -out: > - vfree(cmem); > - return ret; > + return walk_system_ram_res(0, -1, cmem, > prepare_elf64_ram_headers_callback); > } > #endif > > @@ -418,7 +351,8 @@ int crash_load_segments(struct kimage *image) > .buf_max = ULONG_MAX, .top_down = false }; > > /* Prepare elf headers and add a segment */ > - ret = prepare_elf_headers(&kbuf.buffer, &kbuf.bufsz, &pnum); > + ret = crash_prepare_headers(IS_ENABLED(CONFIG_X86_64), &kbuf.buffer, > + &kbuf.bufsz, &pnum); > if (ret) > return ret; > > @@ -529,7 +463,8 @@ void arch_crash_handle_hotplug_event(struct kimage > *image, void *arg) > * Create the new elfcorehdr reflecting the changes to CPU and/or > * memory resources. > */ > - if (prepare_elf_headers(&elfbuf, &elfsz, &nr_mem_ranges)) { > + if (crash_prepare_headers(IS_ENABLED(CONFIG_X86_64), &elfbuf, &elfsz, > + &nr_mem_ranges)) { > pr_err("unable to create new elfcorehdr"); > goto out; > } > diff --git a/include/linux/crash_core.h b/include/linux/crash_core.h > index d35726d6a415..033b20204aca 100644 > --- a/include/linux/crash_core.h > +++ b/include/linux/crash_core.h > @@ -66,6 +66,8 @@ extern int crash_exclude_mem_range(struct crash_mem *mem, > unsigned long long mend); > extern int crash_prepare_elf64_headers(struct crash_mem *mem, int > need_kernel_map, > void **addr, unsigned long *sz); > +extern int crash_prepare_headers(int need_kernel_map, void **addr, > + unsigned long *sz, unsigned long > *nr_mem_ranges); > > struct kimage; > struct kexec_segment; > @@ -83,6 +85,9 @@ int kexec_should_crash(struct task_struct *p); > int kexec_crash_loaded(void); > void crash_save_cpu(struct pt_regs *regs, int cpu); > extern int kimage_crash_copy_vmcoreinfo(struct kimage *image); > +extern unsigned int arch_get_system_nr_ranges(void); > +extern int arch_crash_populate_cmem(struct crash_mem *cmem); > +extern int arch_crash_exclude_ranges(struct crash_mem *cmem); > > #else /* !CONFIG_CRASH_DUMP*/ > struct pt_regs; > diff --git a/kernel/crash_core.c b/kernel/crash_core.c > index 2c1a3791e410..96a96e511f5a 100644 > --- a/kernel/crash_core.c > +++ b/kernel/crash_core.c > @@ -170,9 +170,6 @@ static inline resource_size_t crash_resource_size(const > struct resource *res) > return !res->end ? 0 : resource_size(res); > } > > - > - > - > int crash_prepare_elf64_headers(struct crash_mem *mem, int need_kernel_map, > void **addr, unsigned long *sz) > { > @@ -274,6 +271,85 @@ int crash_prepare_elf64_headers(struct crash_mem *mem, > int need_kernel_map, > return 0; > } > > +static struct crash_mem *alloc_cmem(unsigned int nr_ranges) > +{ > + struct crash_mem *cmem; > + > + cmem = kvzalloc_flex(*cmem, ranges, nr_ranges); > + if (!cmem) > + return NULL; > + > + cmem->max_nr_ranges = nr_ranges; > + return cmem; > +} > + > +unsigned int __weak arch_get_system_nr_ranges(void) { return 0; } > +int __weak arch_crash_populate_cmem(struct crash_mem *cmem) { return -1; } > +int __weak arch_crash_exclude_ranges(struct crash_mem *cmem) { return 0; } > + > +static int crash_exclude_core_ranges(struct crash_mem *cmem) > +{ > + int ret, i; > + > + /* Exclude crashkernel region */ > + ret = crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end); > + if (ret) > + return ret; > + > + if (crashk_low_res.end) { > + ret = crash_exclude_mem_range(cmem, crashk_low_res.start, > crashk_low_res.end); > + if (ret) > + return ret; > + } > + > + for (i = 0; i < crashk_cma_cnt; ++i) { > + ret = crash_exclude_mem_range(cmem, crashk_cma_ranges[i].start, > + crashk_cma_ranges[i].end); > + if (ret) > + return ret; > + } > + > + return 0; > +} > + > +int crash_prepare_headers(int need_kernel_map, void **addr, unsigned long > *sz, > + unsigned long *nr_mem_ranges) > +{ > + unsigned int max_nr_ranges; > + struct crash_mem *cmem; > + int ret; > + > + max_nr_ranges = arch_get_system_nr_ranges(); > + if (!max_nr_ranges) > + return -ENOMEM; > + > + cmem = alloc_cmem(max_nr_ranges); > + if (!cmem) > + return -ENOMEM; > + > + ret = arch_crash_populate_cmem(cmem); > + if (ret) > + goto out; > + > + ret = crash_exclude_core_ranges(cmem); > + if (ret) > + goto out; > + > + ret = arch_crash_exclude_ranges(cmem); > + if (ret) > + goto out; > + > + /* Return the computed number of memory ranges, for hotplug usage */ > + if (nr_mem_ranges) > + *nr_mem_ranges = cmem->nr_ranges; > + > + ret = crash_prepare_elf64_headers(cmem, need_kernel_map, addr, sz); > + > +out: > + kvfree(cmem); > + return ret; > +} > + > /** > * crash_exclude_mem_range - exclude a mem range for existing ranges > * @mem: mem->range contains an array of ranges sorted in ascending order > -- > 2.34.1 >
