Re: [PATCH v3 4/9] crash_core: add generic function to do reservation
From: Leizhen (ThunderTown)
Date: Mon Sep 18 2023 - 08:47:13 EST
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@xxxxxxxxxx>
>
> Signed-off-by: Baoquan He <bhe@xxxxxxxxxx>
> ---
> 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