[PATCH v3 4/9] crash_core: add generic function to do reservation

Leizhen (ThunderTown) thunder.leizhen at huaweicloud.com
Mon Sep 18 05:44:48 PDT 2023



On 2023/9/14 11:31, Baoquan He wrote:
> In architecture like x86_64, arm64 and riscv, they have vast virtual
> address space and usually have huge physical memory RAM. Their
> crashkernel reservation doesn't have to be limited under 4G RAM,
> but can be extended to the whole physical memory via crashkernel=,high
> support.
> 
> Now add function reserve_crashkernel_generic() to reserve crashkernel
> memory if users specify any case of kernel pamameters, like
> crashkernel=xM[@offset] or crashkernel=,high|low.
> 
> This is preparation to simplify code of crashkernel=,high support
> in architecutures.

Reviewed-by: Zhen Lei <thunder.leizhen at huawei.com>

> 
> Signed-off-by: Baoquan He <bhe at redhat.com>
> ---
>  include/linux/crash_core.h |  28 ++++++++++
>  kernel/crash_core.c        | 107 ++++++++++++++++++++++++++++++++++++-
>  2 files changed, 134 insertions(+), 1 deletion(-)
> 
> diff --git a/include/linux/crash_core.h b/include/linux/crash_core.h
> index d8050a7eab01..4dbd6565e0ff 100644
> --- a/include/linux/crash_core.h
> +++ b/include/linux/crash_core.h
> @@ -93,6 +93,34 @@ int parse_crashkernel_high(char *cmdline, unsigned long long system_ram,
>  int parse_crashkernel_low(char *cmdline, unsigned long long system_ram,
>  		unsigned long long *crash_size, unsigned long long *crash_base);
>  
> +#ifdef CONFIG_ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION
> +#ifndef DEFAULT_CRASH_KERNEL_LOW_SIZE
> +#define DEFAULT_CRASH_KERNEL_LOW_SIZE	(128UL << 20)
> +#endif
> +#ifndef CRASH_ALIGN
> +#define CRASH_ALIGN			SZ_2M
> +#endif
> +#ifndef CRASH_ADDR_LOW_MAX
> +#define CRASH_ADDR_LOW_MAX		SZ_4G
> +#endif
> +#ifndef CRASH_ADDR_HIGH_MAX
> +#define CRASH_ADDR_HIGH_MAX		memblock_end_of_DRAM()
> +#endif
> +
> +void __init reserve_crashkernel_generic(char *cmdline,
> +		unsigned long long crash_size,
> +		unsigned long long crash_base,
> +		unsigned long long crash_low_size,
> +		bool high);
> +#else
> +static inline void __init reserve_crashkernel_generic(char *cmdline,
> +		unsigned long long crash_size,
> +		unsigned long long crash_base,
> +		unsigned long long crash_low_size,
> +		bool high)
> +{}
> +#endif
> +
>  /* Alignment required for elf header segment */
>  #define ELF_CORE_HEADER_ALIGN   4096
>  
> diff --git a/kernel/crash_core.c b/kernel/crash_core.c
> index dce2f5874fea..ca66b5f41dc7 100644
> --- a/kernel/crash_core.c
> +++ b/kernel/crash_core.c
> @@ -5,7 +5,6 @@
>   */
>  
>  #include <linux/buildid.h>
> -#include <linux/crash_core.h>
>  #include <linux/init.h>
>  #include <linux/utsname.h>
>  #include <linux/vmalloc.h>
> @@ -13,6 +12,9 @@
>  #include <linux/kexec.h>
>  #include <linux/memory.h>
>  #include <linux/cpuhotplug.h>
> +#include <linux/memblock.h>
> +#include <linux/kexec.h>
> +#include <linux/kmemleak.h>
>  
>  #include <asm/page.h>
>  #include <asm/sections.h>
> @@ -360,6 +362,109 @@ static int __init parse_crashkernel_dummy(char *arg)
>  }
>  early_param("crashkernel", parse_crashkernel_dummy);
>  
> +#ifdef CONFIG_ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION
> +static int __init reserve_crashkernel_low(unsigned long long low_size)
> +{
> +#ifdef CONFIG_64BIT
> +	unsigned long long low_base;
> +
> +	low_base = memblock_phys_alloc_range(low_size, CRASH_ALIGN, 0, CRASH_ADDR_LOW_MAX);
> +	if (!low_base) {
> +		pr_err("cannot allocate crashkernel low memory (size:0x%llx).\n", low_size);
> +		return -ENOMEM;
> +	}
> +
> +	pr_info("crashkernel low memory reserved: 0x%08llx - 0x%08llx (%lld MB)\n",
> +		low_base, low_base + low_size, low_size >> 20);
> +
> +	crashk_low_res.start = low_base;
> +	crashk_low_res.end   = low_base + low_size - 1;
> +	insert_resource(&iomem_resource, &crashk_low_res);
> +#endif
> +	return 0;
> +}
> +
> +void __init reserve_crashkernel_generic(char *cmdline,
> +			     unsigned long long crash_size,
> +			     unsigned long long crash_base,
> +			     unsigned long long crash_low_size,
> +			     bool high)
> +{
> +	unsigned long long search_end = CRASH_ADDR_LOW_MAX, search_base = 0;
> +	bool fixed_base = false;
> +
> +	/* User specifies base address explicitly. */
> +	if (crash_base) {
> +		fixed_base = true;
> +		search_base = crash_base;
> +		search_end = crash_base + crash_size;
> +	} else if (high) {
> +		search_base = CRASH_ADDR_LOW_MAX;
> +		search_end = CRASH_ADDR_HIGH_MAX;
> +	}
> +
> +retry:
> +	crash_base = memblock_phys_alloc_range(crash_size, CRASH_ALIGN,
> +					       search_base, search_end);
> +	if (!crash_base) {
> +		/*
> +		 * For crashkernel=size[KMG]@offset[KMG], print out failure
> +		 * message if can't reserve the specified region.
> +		 */
> +		if (fixed_base) {
> +			pr_warn("crashkernel reservation failed - memory is in use.\n");
> +			return;
> +		}
> +
> +		/*
> +		 * For crashkernel=size[KMG], if the first attempt was for
> +		 * low memory, fall back to high memory, the minimum required
> +		 * low memory will be reserved later.
> +		 */
> +		if (!high && search_end == CRASH_ADDR_LOW_MAX) {
> +			search_end = CRASH_ADDR_HIGH_MAX;
> +			search_base = CRASH_ADDR_LOW_MAX;
> +			crash_low_size = DEFAULT_CRASH_KERNEL_LOW_SIZE;
> +			goto retry;
> +		}
> +
> +		/*
> +		 * For crashkernel=size[KMG],high, if the first attempt was
> +		 * for high memory, fall back to low memory.
> +		 */
> +		if (high && search_end == CRASH_ADDR_HIGH_MAX) {
> +			search_end = CRASH_ADDR_LOW_MAX;
> +			search_base = 0;
> +			goto retry;
> +		}
> +		pr_warn("cannot allocate crashkernel (size:0x%llx)\n",
> +			crash_size);
> +		return;
> +	}
> +
> +	if ((crash_base > CRASH_ADDR_LOW_MAX) &&
> +	     crash_low_size && reserve_crashkernel_low(crash_low_size)) {
> +		memblock_phys_free(crash_base, crash_size);
> +		return;
> +	}
> +
> +	pr_info("crashkernel reserved: 0x%016llx - 0x%016llx (%lld MB)\n",
> +		crash_base, crash_base + crash_size, crash_size >> 20);
> +
> +	/*
> +	 * The crashkernel memory will be removed from the kernel linear
> +	 * map. Inform kmemleak so that it won't try to access it.
> +	 */
> +	kmemleak_ignore_phys(crash_base);
> +	if (crashk_low_res.end)
> +		kmemleak_ignore_phys(crashk_low_res.start);
> +
> +	crashk_res.start = crash_base;
> +	crashk_res.end = crash_base + crash_size - 1;
> +	insert_resource(&iomem_resource, &crashk_res);
> +}
> +#endif
> +
>  int crash_prepare_elf64_headers(struct crash_mem *mem, int need_kernel_map,
>  			  void **addr, unsigned long *sz)
>  {
> 

-- 
Regards,
  Zhen Lei




More information about the kexec mailing list