public inbox for linux-doc@vger.kernel.org
 help / color / mirror / Atom feed
From: Sourabh Jain <sourabhjain@linux.ibm.com>
To: Jinjie Ruan <ruanjinjie@huawei.com>,
	corbet@lwn.net, catalin.marinas@arm.com, will@kernel.org,
	chenhuacai@kernel.org, kernel@xen0n.name, maddy@linux.ibm.com,
	mpe@ellerman.id.au, npiggin@gmail.com, chleroy@kernel.org,
	pjw@kernel.org, palmer@dabbelt.com, aou@eecs.berkeley.edu,
	alex@ghiti.fr, tglx@kernel.org, mingo@redhat.com, bp@alien8.de,
	dave.hansen@linux.intel.com, hpa@zytor.com,
	akpm@linux-foundation.org, bhe@redhat.com, vgoyal@redhat.com,
	dyoung@redhat.com, rdunlap@infradead.org, pmladek@suse.com,
	feng.tang@linux.alibaba.com, pawan.kumar.gupta@linux.intel.com,
	kees@kernel.org, elver@google.com, arnd@arndb.de,
	lirongqing@baidu.com, fvdl@google.com, leitao@debian.org,
	rppt@kernel.org, ardb@kernel.org, jbohac@suse.cz, osandov@fb.com,
	ryan.roberts@arm.com, cfsworks@gmail.com, tangyouling@kylinos.cn,
	ritesh.list@gmail.com, thuth@redhat.com, hbathini@linux.ibm.com,
	eajames@linux.ibm.com, bjorn@rivosinc.com,
	songshuaishuai@tinylab.org, kevin.brodsky@arm.com,
	samuel.holland@sifive.com, vishal.moola@gmail.com,
	junhui.liu@pigmoral.tech, dwmw@amazon.co.uk, pbonzini@redhat.com,
	thomas.lendacky@amd.com, kai.huang@intel.com, ubizjak@gmail.com,
	coxu@redhat.com, liaoyuanhong@vivo.com,
	fuqiang.wang@easystack.cn, brgerst@gmail.com, x86@kernel.org,
	linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, loongarch@lists.linux.dev,
	linuxppc-dev@lists.ozlabs.org, linux-riscv@lists.infradead.org,
	kexec@lists.infradead.org
Subject: Re: [PATCH v4 1/3] crash: Exclude crash kernel memory in crash core
Date: Tue, 10 Feb 2026 18:00:21 +0530	[thread overview]
Message-ID: <50693f0c-c610-4347-86aa-40d50dc681fc@linux.ibm.com> (raw)
In-Reply-To: <20260209095931.2813152-2-ruanjinjie@huawei.com>

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@huawei.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@start" 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;
>   }
>   
>   /**


  reply	other threads:[~2026-02-10 12:31 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-02-09  9:59 [PATCH v4 0/3] arm64/riscv: Add support for crashkernel CMA reservation Jinjie Ruan
2026-02-09  9:59 ` [PATCH v4 1/3] crash: Exclude crash kernel memory in crash core Jinjie Ruan
2026-02-10 12:30   ` Sourabh Jain [this message]
2026-02-12  3:28     ` Jinjie Ruan
2026-02-12  6:11       ` Sourabh Jain
2026-02-09  9:59 ` [PATCH v4 2/3] arm64: kexec: Add support for crashkernel CMA reservation Jinjie Ruan
2026-02-09  9:59 ` [PATCH v4 3/3] riscv: " Jinjie Ruan

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=50693f0c-c610-4347-86aa-40d50dc681fc@linux.ibm.com \
    --to=sourabhjain@linux.ibm.com \
    --cc=akpm@linux-foundation.org \
    --cc=alex@ghiti.fr \
    --cc=aou@eecs.berkeley.edu \
    --cc=ardb@kernel.org \
    --cc=arnd@arndb.de \
    --cc=bhe@redhat.com \
    --cc=bjorn@rivosinc.com \
    --cc=bp@alien8.de \
    --cc=brgerst@gmail.com \
    --cc=catalin.marinas@arm.com \
    --cc=cfsworks@gmail.com \
    --cc=chenhuacai@kernel.org \
    --cc=chleroy@kernel.org \
    --cc=corbet@lwn.net \
    --cc=coxu@redhat.com \
    --cc=dave.hansen@linux.intel.com \
    --cc=dwmw@amazon.co.uk \
    --cc=dyoung@redhat.com \
    --cc=eajames@linux.ibm.com \
    --cc=elver@google.com \
    --cc=feng.tang@linux.alibaba.com \
    --cc=fuqiang.wang@easystack.cn \
    --cc=fvdl@google.com \
    --cc=hbathini@linux.ibm.com \
    --cc=hpa@zytor.com \
    --cc=jbohac@suse.cz \
    --cc=junhui.liu@pigmoral.tech \
    --cc=kai.huang@intel.com \
    --cc=kees@kernel.org \
    --cc=kernel@xen0n.name \
    --cc=kevin.brodsky@arm.com \
    --cc=kexec@lists.infradead.org \
    --cc=leitao@debian.org \
    --cc=liaoyuanhong@vivo.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-riscv@lists.infradead.org \
    --cc=linuxppc-dev@lists.ozlabs.org \
    --cc=lirongqing@baidu.com \
    --cc=loongarch@lists.linux.dev \
    --cc=maddy@linux.ibm.com \
    --cc=mingo@redhat.com \
    --cc=mpe@ellerman.id.au \
    --cc=npiggin@gmail.com \
    --cc=osandov@fb.com \
    --cc=palmer@dabbelt.com \
    --cc=pawan.kumar.gupta@linux.intel.com \
    --cc=pbonzini@redhat.com \
    --cc=pjw@kernel.org \
    --cc=pmladek@suse.com \
    --cc=rdunlap@infradead.org \
    --cc=ritesh.list@gmail.com \
    --cc=rppt@kernel.org \
    --cc=ruanjinjie@huawei.com \
    --cc=ryan.roberts@arm.com \
    --cc=samuel.holland@sifive.com \
    --cc=songshuaishuai@tinylab.org \
    --cc=tangyouling@kylinos.cn \
    --cc=tglx@kernel.org \
    --cc=thomas.lendacky@amd.com \
    --cc=thuth@redhat.com \
    --cc=ubizjak@gmail.com \
    --cc=vgoyal@redhat.com \
    --cc=vishal.moola@gmail.com \
    --cc=will@kernel.org \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox