lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <50693f0c-c610-4347-86aa-40d50dc681fc@linux.ibm.com>
Date: Tue, 10 Feb 2026 18:00:21 +0530
From: Sourabh Jain <sourabhjain@...ux.ibm.com>
To: Jinjie Ruan <ruanjinjie@...wei.com>, corbet@....net,
        catalin.marinas@....com, will@...nel.org, chenhuacai@...nel.org,
        kernel@...0n.name, maddy@...ux.ibm.com, mpe@...erman.id.au,
        npiggin@...il.com, chleroy@...nel.org, pjw@...nel.org,
        palmer@...belt.com, aou@...s.berkeley.edu, alex@...ti.fr,
        tglx@...nel.org, mingo@...hat.com, bp@...en8.de,
        dave.hansen@...ux.intel.com, hpa@...or.com, akpm@...ux-foundation.org,
        bhe@...hat.com, vgoyal@...hat.com, dyoung@...hat.com,
        rdunlap@...radead.org, pmladek@...e.com, feng.tang@...ux.alibaba.com,
        pawan.kumar.gupta@...ux.intel.com, kees@...nel.org, elver@...gle.com,
        arnd@...db.de, lirongqing@...du.com, fvdl@...gle.com,
        leitao@...ian.org, rppt@...nel.org, ardb@...nel.org, jbohac@...e.cz,
        osandov@...com, ryan.roberts@....com, cfsworks@...il.com,
        tangyouling@...inos.cn, ritesh.list@...il.com, thuth@...hat.com,
        hbathini@...ux.ibm.com, eajames@...ux.ibm.com, bjorn@...osinc.com,
        songshuaishuai@...ylab.org, kevin.brodsky@....com,
        samuel.holland@...ive.com, vishal.moola@...il.com,
        junhui.liu@...moral.tech, dwmw@...zon.co.uk, pbonzini@...hat.com,
        thomas.lendacky@....com, kai.huang@...el.com, ubizjak@...il.com,
        coxu@...hat.com, liaoyuanhong@...o.com, fuqiang.wang@...ystack.cn,
        brgerst@...il.com, x86@...nel.org, linux-doc@...r.kernel.org,
        linux-kernel@...r.kernel.org, linux-arm-kernel@...ts.infradead.org,
        loongarch@...ts.linux.dev, linuxppc-dev@...ts.ozlabs.org,
        linux-riscv@...ts.infradead.org, kexec@...ts.infradead.org
Subject: Re: [PATCH v4 1/3] crash: Exclude crash kernel memory in crash core

Hello Jinjie,

On 09/02/26 15:29, Jinjie Ruan wrote:
> 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.
>
> And move the size calculation (and the realloc if needed) into the
> generic crash core so that:
>
> - New CMA regions or future crash-memory types can automatically
>    accounted for in crash core;
>
> - Each architecture no longer has to play whack-a-mole with
>    its private array size.
>
> To achieve the above goal, 4 architecture-specific functions are
> introduced:
>
> - arch_get_system_nr_ranges() and arch_prepare_elf64_ram_headers().
>    The 1st function pre-counts the number of memory ranges, and
>    the 2st function fill the memory ranges into the cmem->ranges[] array,
>    and count the actual number of ranges filled. The default implementation
>    is consistent with arm64 and loongson.
>
> - arch_crash_exclude_mem_range(). Realloc for powerpc. The default
>    implementation is crash_exclude_mem_range(), and use
>    crash_exclude_mem_range_guarded() to implement the arch version
>    for powerpc.
>
> - arch_get_crash_memory_ranges(). Get crash memory ranges for arch and
>    the default implementation is generic across x86, arm64, riscv, and
>    loongson by using the first two arch functions above. powerpc has its
>    own implementation by calling get_crash_memory_ranges().
>
> Tested on x86, arm64 and riscv with QEMU.
>
> Signed-off-by: Jinjie Ruan <ruanjinjie@...wei.com>
> ---
>   arch/arm64/kernel/machine_kexec_file.c     |  47 +--------
>   arch/loongarch/kernel/machine_kexec_file.c |  45 +-------
>   arch/powerpc/include/asm/kexec.h           |  13 +++
>   arch/powerpc/kexec/crash.c                 |  52 ++++++----
>   arch/powerpc/kexec/file_load_64.c          |  17 ++-
>   arch/powerpc/kexec/ranges.c                |  18 +---
>   arch/riscv/include/asm/kexec.h             |  10 ++
>   arch/riscv/kernel/machine_kexec_file.c     |  37 ++-----
>   arch/x86/include/asm/kexec.h               |  10 ++
>   arch/x86/kernel/crash.c                    | 104 ++-----------------
>   include/linux/crash_core.h                 | 114 +++++++++++++++++++--
>   kernel/crash_core.c                        |  71 +++++++++++--
>   12 files changed, 269 insertions(+), 269 deletions(-)
>
> diff --git a/arch/arm64/kernel/machine_kexec_file.c b/arch/arm64/kernel/machine_kexec_file.c
> index 410060ebd86d..8a29449e992d 100644
> --- a/arch/arm64/kernel/machine_kexec_file.c
> +++ b/arch/arm64/kernel/machine_kexec_file.c
> @@ -39,50 +39,6 @@ int arch_kimage_file_post_load_cleanup(struct kimage *image)
>   	return kexec_image_post_load_cleanup_default(image);
>   }
>   
> -#ifdef CONFIG_CRASH_DUMP
> -static int prepare_elf_headers(void **addr, unsigned long *sz)
> -{
> -	struct crash_mem *cmem;
> -	unsigned int nr_ranges;
> -	int ret;
> -	u64 i;
> -	phys_addr_t start, end;
> -
> -	nr_ranges = 2; /* for exclusion of crashkernel region */
> -	for_each_mem_range(i, &start, &end)
> -		nr_ranges++;
> -
> -	cmem = kmalloc(struct_size(cmem, ranges, nr_ranges), GFP_KERNEL);
> -	if (!cmem)
> -		return -ENOMEM;
> -
> -	cmem->max_nr_ranges = nr_ranges;
> -	cmem->nr_ranges = 0;
> -	for_each_mem_range(i, &start, &end) {
> -		cmem->ranges[cmem->nr_ranges].start = start;
> -		cmem->ranges[cmem->nr_ranges].end = end - 1;
> -		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;
> -}
> -#endif
> -
>   /*
>    * Tries to add the initrd and DTB to the image. If it is not possible to find
>    * valid locations, this function will undo changes to the image and return non
> @@ -109,7 +65,8 @@ 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_elf64_headers(true, &headers, &headers_sz,
> +						  NULL, NULL, 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 fb57026f5f25..93555b92bbeb 100644
> --- a/arch/loongarch/kernel/machine_kexec_file.c
> +++ b/arch/loongarch/kernel/machine_kexec_file.c
> @@ -56,48 +56,6 @@ 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)
> -{
> -	int ret, nr_ranges;
> -	uint64_t i;
> -	phys_addr_t start, end;
> -	struct crash_mem *cmem;
> -
> -	nr_ranges = 2; /* for exclusion of crashkernel region */
> -	for_each_mem_range(i, &start, &end)
> -		nr_ranges++;
> -
> -	cmem = kmalloc(struct_size(cmem, ranges, nr_ranges), GFP_KERNEL);
> -	if (!cmem)
> -		return -ENOMEM;
> -
> -	cmem->max_nr_ranges = nr_ranges;
> -	cmem->nr_ranges = 0;
> -	for_each_mem_range(i, &start, &end) {
> -		cmem->ranges[cmem->nr_ranges].start = start;
> -		cmem->ranges[cmem->nr_ranges].end = end - 1;
> -		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;
> -}
> -
>   /*
>    * Add the "mem=size@...rt" command line parameter to command line, indicating the
>    * memory region the new kernel can use to boot into.
> @@ -163,7 +121,8 @@ int load_other_segments(struct kimage *image,
>   		void *headers;
>   		unsigned long headers_sz;
>   
> -		ret = prepare_elf_headers(&headers, &headers_sz);
> +		ret = crash_prepare_elf64_headers(true, &headers, &headers_sz,
> +						  NULL, NULL, NULL);
>   		if (ret < 0) {
>   			pr_err("Preparing elf core header failed\n");
>   			goto out_err;
> diff --git a/arch/powerpc/include/asm/kexec.h b/arch/powerpc/include/asm/kexec.h
> index bd4a6c42a5f3..ec64c26ca81a 100644
> --- a/arch/powerpc/include/asm/kexec.h
> +++ b/arch/powerpc/include/asm/kexec.h
> @@ -123,6 +123,11 @@ static inline void kdump_cma_reserve(void) { }
>   #endif
>   
>   #if defined(CONFIG_CRASH_DUMP)
> +#include <asm/kexec_ranges.h>
> +
> +struct crash_mem;
> +struct memory_notify;
> +
>   /*
>    * This function is responsible for capturing register states if coming
>    * via panic or invoking dump using sysrq-trigger.
> @@ -147,6 +152,14 @@ unsigned int arch_crash_get_elfcorehdr_size(void);
>   #define crash_get_elfcorehdr_size arch_crash_get_elfcorehdr_size
>   #endif /* CONFIG_CRASH_HOTPLUG */
>   
> +int arch_crash_exclude_mem_range(struct crash_mem **mem, unsigned long long mstart,
> +				 unsigned long long mend);
> +#define arch_crash_exclude_mem_range arch_crash_exclude_mem_range
> +
> +int arch_get_crash_memory_ranges(struct crash_mem **cmem, unsigned long *nr_mem_ranges,
> +				 struct kimage *image, struct memory_notify *mn);
> +#define arch_get_crash_memory_ranges arch_get_crash_memory_ranges
> +
>   extern int crashing_cpu;
>   extern void crash_send_ipi(void (*crash_ipi_callback)(struct pt_regs *));
>   extern void crash_ipi_callback(struct pt_regs *regs);
> diff --git a/arch/powerpc/kexec/crash.c b/arch/powerpc/kexec/crash.c
> index a325c1c02f96..5ade9a853fb0 100644
> --- a/arch/powerpc/kexec/crash.c
> +++ b/arch/powerpc/kexec/crash.c
> @@ -419,30 +419,21 @@ unsigned int arch_crash_get_elfcorehdr_size(void)
>   	return sizeof(struct elfhdr) + (phdr_cnt * sizeof(Elf64_Phdr));
>   }
>   
> -/**
> - * update_crash_elfcorehdr() - Recreate the elfcorehdr and replace it with old
> - *			       elfcorehdr in the kexec segment array.
> - * @image: the active struct kimage
> - * @mn: struct memory_notify data handler
> - */
> -static void update_crash_elfcorehdr(struct kimage *image, struct memory_notify *mn)
> +int arch_get_crash_memory_ranges(struct crash_mem **cmem, unsigned long *nr_mem_ranges,
> +				 struct kimage *image, struct memory_notify *mn)
>   {
> +	unsigned long base_addr, size;
>   	int ret;
> -	struct crash_mem *cmem = NULL;
> -	struct kexec_segment *ksegment;
> -	void *ptr, *mem, *elfbuf = NULL;
> -	unsigned long elfsz, memsz, base_addr, size;
>   
> -	ksegment = &image->segment[image->elfcorehdr_index];
> -	mem = (void *) ksegment->mem;
> -	memsz = ksegment->memsz;
> -
> -	ret = get_crash_memory_ranges(&cmem);
> +	ret = get_crash_memory_ranges(cmem);
>   	if (ret) {
>   		pr_err("Failed to get crash mem range\n");
> -		return;
> +		return ret;
>   	}
>   
> +	if (!image || !mn)
> +		return 0;
> +
>   	/*
>   	 * The hot unplugged memory is part of crash memory ranges,
>   	 * remove it here.
> @@ -450,14 +441,34 @@ static void update_crash_elfcorehdr(struct kimage *image, struct memory_notify *
>   	if (image->hp_action == KEXEC_CRASH_HP_REMOVE_MEMORY) {
>   		base_addr = PFN_PHYS(mn->start_pfn);
>   		size = mn->nr_pages * PAGE_SIZE;
> -		ret = remove_mem_range(&cmem, base_addr, size);
> +		ret = remove_mem_range(cmem, base_addr, size);

I like the overall design for handling crashkernel memory exclusion
in this patch series, especially the way you managed to free the
crash_mem object (mem) in the generic code (crash_prepare_elf64_headers()).

However, the way crash memory is prepared after a memory hotplug
event on powerpc by calling remove_mem_range(), can leave the crash
memory ranges unsorted. This can cause issues in the generic code
when excluding crashkernel memory, because crash_exclude_mem_range()
expects crash_mem to be sorted.

So I wrote a simple patch to cover this scenario. Including the
patch below as the first patch in this series would be helpful.
https://lore.kernel.org/all/20260210120803.433978-1-sourabhjain@linux.ibm.com/

Jinjie, will it be possible for you to include the above patch in this 
patch series?
>   		if (ret) {
>   			pr_err("Failed to remove hot-unplugged memory from crash memory ranges\n");
> -			goto out;
> +			return ret;
>   		}
>   	}
>   
> -	ret = crash_prepare_elf64_headers(cmem, false, &elfbuf, &elfsz);
> +	return 0;
> +}
> +
> +/**
> + * update_crash_elfcorehdr() - Recreate the elfcorehdr and replace it with old
> + *			       elfcorehdr in the kexec segment array.
> + * @image: the active struct kimage
> + * @mn: struct memory_notify data handler
> + */
> +static void update_crash_elfcorehdr(struct kimage *image, struct memory_notify *mn)
> +{
> +	void *ptr, *mem, *elfbuf = NULL;
> +	struct kexec_segment *ksegment;
> +	unsigned long elfsz, memsz;
> +	int ret;
> +
> +	ksegment = &image->segment[image->elfcorehdr_index];
> +	mem = (void *) ksegment->mem;
> +	memsz = ksegment->memsz;
> +
> +	ret = crash_prepare_elf64_headers(false, &elfbuf, &elfsz, NULL, image, mn);
>   	if (ret) {
>   		pr_err("Failed to prepare elf header\n");
>   		goto out;
> @@ -486,7 +497,6 @@ static void update_crash_elfcorehdr(struct kimage *image, struct memory_notify *
>   		xchg(&kexec_crash_image, image);
>   	}
>   out:
> -	kvfree(cmem);
>   	kvfree(elfbuf);
>   }
>   
> diff --git a/arch/powerpc/kexec/file_load_64.c b/arch/powerpc/kexec/file_load_64.c
> index e7ef8b2a2554..6fe13031236c 100644
> --- a/arch/powerpc/kexec/file_load_64.c
> +++ b/arch/powerpc/kexec/file_load_64.c
> @@ -401,17 +401,17 @@ static void update_backup_region_phdr(struct kimage *image, Elf64_Ehdr *ehdr)
>   	}
>   }
>   
> -static unsigned int kdump_extra_elfcorehdr_size(struct crash_mem *cmem)
> +static unsigned int kdump_extra_elfcorehdr_size(unsigned long nr_mem_ranges)
>   {
>   #if defined(CONFIG_CRASH_HOTPLUG) && defined(CONFIG_MEMORY_HOTPLUG)
>   	unsigned int extra_sz = 0;
>   
>   	if (CONFIG_CRASH_MAX_MEMORY_RANGES > (unsigned int)PN_XNUM)
>   		pr_warn("Number of Phdrs %u exceeds max\n", CONFIG_CRASH_MAX_MEMORY_RANGES);
> -	else if (cmem->nr_ranges >= CONFIG_CRASH_MAX_MEMORY_RANGES)
> +	else if (nr_mem_ranges >= CONFIG_CRASH_MAX_MEMORY_RANGES)
>   		pr_warn("Configured crash mem ranges may not be enough\n");
>   	else
> -		extra_sz = (CONFIG_CRASH_MAX_MEMORY_RANGES - cmem->nr_ranges) * sizeof(Elf64_Phdr);
> +		extra_sz = (CONFIG_CRASH_MAX_MEMORY_RANGES - nr_mem_ranges) * sizeof(Elf64_Phdr);
>   
>   	return extra_sz;
>   #endif
> @@ -428,17 +428,13 @@ static unsigned int kdump_extra_elfcorehdr_size(struct crash_mem *cmem)
>    */
>   static int load_elfcorehdr_segment(struct kimage *image, struct kexec_buf *kbuf)
>   {
> -	struct crash_mem *cmem = NULL;
> +	unsigned long nr_mem_ranges;
>   	unsigned long headers_sz;
>   	void *headers = NULL;
>   	int ret;
>   
> -	ret = get_crash_memory_ranges(&cmem);
> -	if (ret)
> -		goto out;
> -
>   	/* Setup elfcorehdr segment */
> -	ret = crash_prepare_elf64_headers(cmem, false, &headers, &headers_sz);
> +	ret = crash_prepare_elf64_headers(false, &headers, &headers_sz, &nr_mem_ranges, NULL, NULL);
>   	if (ret) {
>   		pr_err("Failed to prepare elf headers for the core\n");
>   		goto out;
> @@ -450,7 +446,7 @@ static int load_elfcorehdr_segment(struct kimage *image, struct kexec_buf *kbuf)
>   	kbuf->buffer = headers;
>   	kbuf->mem = KEXEC_BUF_MEM_UNKNOWN;
>   	kbuf->bufsz = headers_sz;
> -	kbuf->memsz = headers_sz + kdump_extra_elfcorehdr_size(cmem);
> +	kbuf->memsz = headers_sz + kdump_extra_elfcorehdr_size(nr_mem_ranges);
>   	kbuf->top_down = false;
>   
>   	ret = kexec_add_buffer(kbuf);
> @@ -463,7 +459,6 @@ static int load_elfcorehdr_segment(struct kimage *image, struct kexec_buf *kbuf)
>   	image->elf_headers_sz = headers_sz;
>   	image->elf_headers = headers;
>   out:
> -	kfree(cmem);
>   	return ret;
>   }
>   
> diff --git a/arch/powerpc/kexec/ranges.c b/arch/powerpc/kexec/ranges.c
> index 867135560e5c..34e3058ff1d5 100644
> --- a/arch/powerpc/kexec/ranges.c
> +++ b/arch/powerpc/kexec/ranges.c
> @@ -553,9 +553,9 @@ int get_usable_memory_ranges(struct crash_mem **mem_ranges)
>   #endif /* CONFIG_KEXEC_FILE */
>   
>   #ifdef CONFIG_CRASH_DUMP
> -static int crash_exclude_mem_range_guarded(struct crash_mem **mem_ranges,
> -					   unsigned long long mstart,
> -					   unsigned long long mend)
> +int arch_crash_exclude_mem_range(struct crash_mem **mem_ranges,
> +				 unsigned long long mstart,
> +				 unsigned long long mend)
>   {
>   	struct crash_mem *tmem = *mem_ranges;
>   
> @@ -604,18 +604,6 @@ int get_crash_memory_ranges(struct crash_mem **mem_ranges)
>   			sort_memory_ranges(*mem_ranges, true);
>   	}
>   
> -	/* Exclude crashkernel region */
> -	ret = crash_exclude_mem_range_guarded(mem_ranges, crashk_res.start, crashk_res.end);
> -	if (ret)
> -		goto out;
> -
> -	for (i = 0; i < crashk_cma_cnt; ++i) {
> -		ret = crash_exclude_mem_range_guarded(mem_ranges, crashk_cma_ranges[i].start,
> -					      crashk_cma_ranges[i].end);
> -		if (ret)
> -			goto out;
> -	}
> -
>   	/*
>   	 * FIXME: For now, stay in parity with kexec-tools but if RTAS/OPAL
>   	 *        regions are exported to save their context at the time of
> diff --git a/arch/riscv/include/asm/kexec.h b/arch/riscv/include/asm/kexec.h
> index b9ee8346cc8c..daee8388a26d 100644
> --- a/arch/riscv/include/asm/kexec.h
> +++ b/arch/riscv/include/asm/kexec.h
> @@ -75,4 +75,14 @@ int load_extra_segments(struct kimage *image, unsigned long kernel_start,
>   			unsigned long cmdline_len);
>   #endif
>   
> +#ifdef CONFIG_CRASH_DUMP
> +struct crash_mem;
> +
> +int arch_get_system_nr_ranges(unsigned int *nr_ranges);
> +#define arch_get_system_nr_ranges arch_get_system_nr_ranges
> +
> +int arch_prepare_elf64_ram_headers(struct crash_mem *cmem);
> +#define arch_prepare_elf64_ram_headers arch_prepare_elf64_ram_headers
> +#endif
> +
>   #endif
> diff --git a/arch/riscv/kernel/machine_kexec_file.c b/arch/riscv/kernel/machine_kexec_file.c
> index dd9d92a96517..2f0e7bbeb2f0 100644
> --- a/arch/riscv/kernel/machine_kexec_file.c
> +++ b/arch/riscv/kernel/machine_kexec_file.c
> @@ -44,6 +44,13 @@ static int get_nr_ram_ranges_callback(struct resource *res, void *arg)
>   	return 0;
>   }
>   
> +int arch_get_system_nr_ranges(unsigned int *nr_ranges)
> +{
> +	walk_system_ram_res(0, -1, nr_ranges, get_nr_ram_ranges_callback);
> +
> +	return 0;
> +}
> +
>   static int prepare_elf64_ram_headers_callback(struct resource *res, void *arg)
>   {
>   	struct crash_mem *cmem = arg;
> @@ -55,33 +62,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_prepare_elf64_ram_headers(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(struct_size(cmem, ranges, nr_ranges), GFP_KERNEL);
> -	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 +257,8 @@ 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_elf64_headers(true, &headers, &headers_sz, NULL, NULL, NULL);
>   		if (ret) {
>   			pr_err("Preparing elf core header failed\n");
>   			goto out;
> diff --git a/arch/x86/include/asm/kexec.h b/arch/x86/include/asm/kexec.h
> index 5cfb27f26583..9939dd8715df 100644
> --- a/arch/x86/include/asm/kexec.h
> +++ b/arch/x86/include/asm/kexec.h
> @@ -232,6 +232,16 @@ unsigned int arch_crash_get_elfcorehdr_size(void);
>   #define crash_get_elfcorehdr_size arch_crash_get_elfcorehdr_size
>   #endif
>   
> +#ifdef CONFIG_CRASH_DUMP
> +struct crash_mem;
> +
> +int arch_get_system_nr_ranges(unsigned int *nr_ranges);
> +#define arch_get_system_nr_ranges arch_get_system_nr_ranges
> +
> +int arch_prepare_elf64_ram_headers(struct crash_mem *cmem);
> +#define arch_prepare_elf64_ram_headers arch_prepare_elf64_ram_headers
> +#endif
> +
>   #endif /* __ASSEMBLER__ */
>   
>   #endif /* _ASM_X86_KEXEC_H */
> diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c
> index 335fd2ee9766..3fbbd518604a 100644
> --- a/arch/x86/kernel/crash.c
> +++ b/arch/x86/kernel/crash.c
> @@ -152,73 +152,15 @@ 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)
> +int arch_get_system_nr_ranges(unsigned int *nr_ranges)
>   {
> -	unsigned int nr_ranges = 0;
> -	struct crash_mem *cmem;
> +	int ret;
>   
> -	walk_system_ram_res(0, -1, &nr_ranges, get_nr_ram_ranges_callback);
> +	ret = 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.
> -	 *
> -	 * Exclusion of low 1M may not cause another range split, because the
> -	 * range of exclude is [0, 1M] and the condition for splitting a new
> -	 * region is that the start, end parameters are both in a certain
> -	 * existing region in cmem and cannot be equal to existing region's
> -	 * start or end. Obviously, the start of [0, 1M] cannot meet this
> -	 * condition.
> -	 *
> -	 * 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;
> -
> -	return cmem;
> -}
> -
> -/*
> - * 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 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 -ENOMEM;
>   
> -	return 0;
> +	return ret;
>   }
>   
>   static int prepare_elf64_ram_headers_callback(struct resource *res, void *arg)
> @@ -232,35 +174,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_prepare_elf64_ram_headers(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 +334,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_elf64_headers(IS_ENABLED(CONFIG_X86_64), &kbuf.buffer,
> +					  &kbuf.bufsz, &pnum, NULL, NULL);
>   	if (ret)
>   		return ret;
>   
> @@ -529,7 +446,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_elf64_headers(IS_ENABLED(CONFIG_X86_64), &elfbuf, &elfsz,
> +					&nr_mem_ranges, NULL, NULL)) {
>   		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..8d92cd16b625 100644
> --- a/include/linux/crash_core.h
> +++ b/include/linux/crash_core.h
> @@ -2,11 +2,15 @@
>   #ifndef LINUX_CRASH_CORE_H
>   #define LINUX_CRASH_CORE_H
>   
> -#include <linux/linkage.h>
>   #include <linux/elfcore.h>
>   #include <linux/elf.h>
> +#include <linux/kexec.h>
> +#include <linux/linkage.h>
> +#include <linux/memblock.h>
> +#include <linux/vmalloc.h>
>   
>   struct kimage;
> +struct memory_notify;
>   
>   struct crash_mem {
>   	unsigned int max_nr_ranges;
> @@ -54,6 +58,104 @@ static inline int arch_crash_hotplug_support(struct kimage *image, unsigned long
>   }
>   #endif
>   
> +#ifndef arch_get_system_nr_ranges
> +static inline int arch_get_system_nr_ranges(unsigned int *nr_ranges)
> +{
> +	phys_addr_t start, end;
> +	u64 i;
> +
> +	for_each_mem_range(i, &start, &end)
> +		(*nr_ranges)++;
> +
> +	return 0;
> +}
> +#endif
> +
> +#ifndef arch_prepare_elf64_ram_headers
> +static inline int arch_prepare_elf64_ram_headers(struct crash_mem *cmem)
> +{
> +	phys_addr_t start, end;
> +	u64 i;
> +
> +	cmem->nr_ranges = 0;
> +	for_each_mem_range(i, &start, &end) {
> +		cmem->ranges[cmem->nr_ranges].start = start;
> +		cmem->ranges[cmem->nr_ranges].end = end - 1;
> +		cmem->nr_ranges++;
> +	}
> +
> +	for (i = 0; i < crashk_cma_cnt; i++) {
> +		cmem->ranges[cmem->nr_ranges].start = crashk_cma_ranges[i].start;
> +		cmem->ranges[cmem->nr_ranges].end = crashk_cma_ranges[i].end;
> +		cmem->nr_ranges++;
> +	}
> +
> +	return 0;
> +}
> +#endif
> +
> +extern int crash_exclude_mem_range(struct crash_mem *mem,
> +				   unsigned long long mstart,
> +				   unsigned long long mend);
> +
> +#ifndef arch_crash_exclude_mem_range
> +static __always_inline int arch_crash_exclude_mem_range(struct crash_mem **mem_ranges,
> +							unsigned long long mstart,
> +							unsigned long long mend)
> +{
> +	return crash_exclude_mem_range(*mem_ranges, mstart, mend);
> +}
> +#endif
> +
> +#ifndef arch_get_crash_memory_ranges
> +static inline int arch_get_crash_memory_ranges(struct crash_mem **cmem,
> +					       unsigned long *nr_mem_ranges,
> +					       struct kimage *image,
> +					       struct memory_notify *mn)
> +{
> +	unsigned int nr_ranges;
> +	int ret;
> +
> +#if defined(CONFIG_X86_64) || defined(CONFIG_X86_32)
> +	/*
> +	 * Exclusion of crash region, crashk_low_res and/or crashk_cma_ranges
> +	 * may cause range splits. So add extra slots here.
> +	 *
> +	 * Exclusion of low 1M may not cause another range split, because the
> +	 * range of exclude is [0, 1M] and the condition for splitting a new
> +	 * region is that the start, end parameters are both in a certain
> +	 * existing region in cmem and cannot be equal to existing region's
> +	 * start or end. Obviously, the start of [0, 1M] cannot meet this
> +	 * condition.
> +	 *
> +	 * 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;
> +#else
> +	/* For exclusion of crashkernel region*/
> +	nr_ranges = 1 + (crashk_low_res.end != 0) + crashk_cma_cnt;
> +#endif
> +
> +	ret = arch_get_system_nr_ranges(&nr_ranges);
> +	if (ret)
> +		return ret;
> +
> +	*cmem = kvzalloc(struct_size(*cmem, ranges, nr_ranges), GFP_KERNEL);
> +	if (!(*cmem))
> +		return -ENOMEM;
> +
> +	(*cmem)->max_nr_ranges = nr_ranges;
> +	ret = arch_prepare_elf64_ram_headers(*cmem);
> +	if (ret) {
> +		kvfree(*cmem);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +#endif
> +
>   #ifndef crash_get_elfcorehdr_size
>   static inline unsigned int crash_get_elfcorehdr_size(void) { return 0; }
>   #endif
> @@ -61,11 +163,11 @@ static inline unsigned int crash_get_elfcorehdr_size(void) { return 0; }
>   /* Alignment required for elf header segment */
>   #define ELF_CORE_HEADER_ALIGN   4096
>   
> -extern int crash_exclude_mem_range(struct crash_mem *mem,
> -				   unsigned long long mstart,
> -				   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_elf64_headers(int need_kernel_map,
> +				       void **addr, unsigned long *sz,
> +				       unsigned long *nr_mem_ranges,
> +				       struct kimage *image,
> +				       struct memory_notify *mn);
>   
>   struct kimage;
>   struct kexec_segment;
> diff --git a/kernel/crash_core.c b/kernel/crash_core.c
> index 99dac1aa972a..39048c87d7a2 100644
> --- a/kernel/crash_core.c
> +++ b/kernel/crash_core.c
> @@ -18,6 +18,7 @@
>   #include <linux/memblock.h>
>   #include <linux/kmemleak.h>
>   #include <linux/crash_core.h>
> +#include <linux/crash_reserve.h>
>   #include <linux/reboot.h>
>   #include <linux/btf.h>
>   #include <linux/objtool.h>
> @@ -161,19 +162,66 @@ static inline resource_size_t crash_resource_size(const struct resource *res)
>   	return !res->end ? 0 : resource_size(res);
>   }
>   
> +static int crash_exclude_mem_ranges(struct crash_mem *cmem,
> +				    unsigned long *nr_mem_ranges)
> +{
> +	int ret, i;
> +
> +#if defined(CONFIG_X86_64) || defined(CONFIG_X86_32)
> +	/* Exclude the low 1M because it is always reserved */
> +	ret = crash_exclude_mem_range(cmem, 0, SZ_1M - 1);
> +	if (ret)
> +		return ret;
> +#endif
>   
> +	/* Exclude crashkernel region */
> +	ret = arch_crash_exclude_mem_range(&cmem, crashk_res.start, crashk_res.end);
> +	if (ret)
> +		return ret;
> +
> +	if (crashk_low_res.end) {
> +		ret = arch_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 = arch_crash_exclude_mem_range(&cmem, crashk_cma_ranges[i].start,
> +						   crashk_cma_ranges[i].end);
> +		if (ret)
> +			return ret;
> +	}
>   
> +	/* Return the computed number of memory ranges, for hotplug usage */
> +	if (nr_mem_ranges)
> +		*nr_mem_ranges = cmem->nr_ranges;
>   
> -int crash_prepare_elf64_headers(struct crash_mem *mem, int need_kernel_map,
> -			  void **addr, unsigned long *sz)
> +	return 0;
> +}
> +
> +int crash_prepare_elf64_headers(int need_kernel_map, void **addr,
> +				unsigned long *sz, unsigned long *nr_mem_ranges,
> +				struct kimage *image, struct memory_notify *mn)
>   {
> -	Elf64_Ehdr *ehdr;
> -	Elf64_Phdr *phdr;
>   	unsigned long nr_cpus = num_possible_cpus(), nr_phdr, elf_sz;
> -	unsigned char *buf;
> -	unsigned int cpu, i;
>   	unsigned long long notes_addr;
> +	struct crash_mem *mem = NULL;
>   	unsigned long mstart, mend;
> +	unsigned int cpu, i;
> +	unsigned char *buf;
> +	Elf64_Ehdr *ehdr;
> +	Elf64_Phdr *phdr;
> +	int ret = 0;
> +
> +	ret = arch_get_crash_memory_ranges(&mem, nr_mem_ranges, image, mn);
> +	if (ret)
> +		return ret;
> +
> +	if (mem) {
> +		ret = crash_exclude_mem_ranges(mem, nr_mem_ranges);
> +		if (ret)
> +			goto out;
> +	}
>   
>   	/* extra phdr for vmcoreinfo ELF note */
>   	nr_phdr = nr_cpus + 1;
> @@ -192,8 +240,10 @@ int crash_prepare_elf64_headers(struct crash_mem *mem, int need_kernel_map,
>   	elf_sz = ALIGN(elf_sz, ELF_CORE_HEADER_ALIGN);
>   
>   	buf = vzalloc(elf_sz);
> -	if (!buf)
> -		return -ENOMEM;
> +	if (!buf) {
> +		ret = -ENOMEM;
> +		goto out;
> +	}
>   
>   	ehdr = (Elf64_Ehdr *)buf;
>   	phdr = (Elf64_Phdr *)(ehdr + 1);
> @@ -262,7 +312,10 @@ int crash_prepare_elf64_headers(struct crash_mem *mem, int need_kernel_map,
>   
>   	*addr = buf;
>   	*sz = elf_sz;
> -	return 0;
> +
> +out:
> +	kvfree(mem);
> +	return ret;
>   }
>   
>   /**


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ