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
> 


Reply via email to