ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Linux arm64 crashkernel 内存预留机制深度解析:kdump 内核低/高内存保留实战指南

Linux arm64 crashkernel 内存预留机制深度解析:kdump 内核低/高内存保留实战指南 Linux arm64 crashkernel 内存预留机制深度解析kdump 内核低/高内存保留实战指南【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux导读本文以 Linux 内核 arm64 架构下 kdump 机制的内存预留crashkernel memory reservation为核心系统讲解crashkernel内核参数的三种配置形态sizeoffset、size、size,high/size,low、低内存Low memory与高内存High memory的划分规则以及内核在启动早期完成内存预留的完整实现路径。读完本文你将掌握在 arm64 平台含 Raspberry Pi 4 这类 DMA 寻址受限的特殊平台上正确配置 kdump 预留内存的方法理解默认低内存预留 128M 的由来并能从源码层面解释为什么我的 crashkernel 预留到了高内存区这类问题。kdump 机制与 crashkernel 预留的背景Kdump 机制用于捕获已崩溃内核的 vmcore以便后续对其进行分析。其核心流程是在第一个主内核启动的早期阶段预先保留一块连续的大块内存用于预加载 kdump捕获内核以及收集 vmcore 所需的用户空间程序一旦主内核发生崩溃corruption系统引导到这块预留内存中的 kdump 内核由它把崩溃现场的内存转储vmcore保存下来供离线分析。这一设计源于 kernel/crash_reserve.c 中定义的crashk_res与crashk_low_res两个 resource分别为 Crash kernel 与低内存 crash kernel 区域标志为IORESOURCE_BUSY | IORESOURCE_SYSTEM_RAM。从源码结构看crashkernel 预留功能由通用内核层kernel/crash_reserve.c与架构层arch/arm64/mm/init.c、arch/arm64/include/asm/crash_reserve.h协同实现预留的内存必须能够最小化地容纳 kdump 内核以及收集 vmcore 所需的用户空间程序因此预留量既不能太小导致 kdump 内核无法启动也不宜过大浪费正常运行系统的可用内存。内核参数crashkernel 的三种配置形态arm64 架构支持通过以下内核命令行参数在第一个内核启动早期预留内存以便找到连续的大块内存区域当从高内存区域预留 crashkernel 时还需要考虑低内存预留crashkernelsizeoffset在用户指定的物理地址偏移处预留指定大小内存crashkernelsize由内核自行搜索可用位置进行预留推荐用法crashkernelsize,high配合crashkernelsize,low分别指定从高内存与低内存预留的大小。这些参数的解析入口在 kernel/crash_reserve.c 的parse_crashkernel()函数。它首先按经典语法crashkernelX[offset]解析在配置了CONFIG_ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION时若未检测到普通 crashkernel 设置则继续尝试解析crashkernel,high|low后缀语法并支持可选的crashkernel,cmaCMA 预留。解析器还内置了校验crashkernel预留大小不能为 0也不能大于等于系统总内存*crash_size system_ram时返回-EINVAL。值得说明的是parse_crashkernel()支持三种子语法语法解析函数说明crashkernelramsize-range:size[,...][offset]parse_crashkernel_mem()按系统内存量分档预留扩展语法含冒号:crashkernelsize[offset]parse_crashkernel_simple()经典简单语法crashkernelsize,[high|low|cma]parse_crashkernel_suffix()后缀语法按高/低内存分别指定arm64 架构侧的调用点位于 arch/arm64/mm/init.c 的arch_reserve_crashkernel()它读取boot_command_line调用parse_crashkernel()得到crash_size、crash_base、low_size、cma_size与high标志随后依次调用reserve_crashkernel_generic()主预留和reserve_crashkernel_cma()可选 CMA 预留。该函数在bootmem_init()中被调用且注释明确指出request_standard_resources()依赖 crashkernel 内存已预留完成因此预留必须发生在资源注册之前。低内存与高内存的划分对于 kdump 预留而言低内存Low memory指特定上限以下的物理内存区域该上限通常由 kdump 内核运行所需的 DMA 能力设备可访问的地址位数决定与 vmcore 转储无关的设备可以忽略。在 arm64 上低内存上限并非固定值在 RPi4 平台上是 1G而在大多数其他系统上是 4G。在禁用了CONFIG_ZONE_(DMA|DMA32)的特殊内核中整个系统 RAM 都视为低内存。除上述低内存之外系统 RAM 的其余部分视为高内存High memory。源码层面这一划分体现在 arch/arm64/include/asm/crash_reserve.h/* Current arm64 boot protocol requires 2MB alignment */ #define CRASH_ALIGN SZ_2M #define CRASH_ADDR_LOW_MAX arm64_dma_phys_limit #define CRASH_ADDR_HIGH_MAX (PHYS_MASK 1)其中arm64_dma_phys_limit由 arch/arm64/mm/init.c 的dma_limits_init()在启动早期计算在启用CONFIG_ZONE_DMA时zone_dma_limit取设备树dma-rangesof_dma_get_max_cpu_address()与 ACPI IORTacpi_iort_dma_get_max_cpu_address()中较小的 DMA 上限为保证低 32 位内存中有 DMA zone当 DRAM 起始地址低于U32_MAX时还会把zone_dma_limit与U32_MAX取小随后arm64_dma_phys_limit max_zone_phys(zone_dma_limit)。若CONFIG_ZONE_DMA32启用且arm64_dma_phys_limit仍为 0则回退为 32 位 DMA 上限若仍为 0则退化为PHYS_MASK 1即整个物理地址空间。RPi4 的 1G 低内存上限正是来自其 30-bit DMA 限制平台dma-ranges收窄了 DMA zone。对于未覆盖上述架构头文件的通用情况include/linux/crash_reserve.h 提供了默认值CRASH_ALIGN为 2MSZ_2M、CRASH_ADDR_LOW_MAX为 4GSZ_4G、CRASH_ADDR_HIGH_MAX为memblock_end_of_DRAM()并定义了默认低内存预留大小DEFAULT_CRASH_KERNEL_LOW_SIZE为 128MB。arm64 通过自己的 asm 头文件覆盖了其中三项使低内存上限与实际 DMA 能力动态绑定。三种预留策略的实现细节1) crashkernelsizeoffset定点预留该形式要求 crashkernel 内存必须预留到用户指定的区域若该区域已被占用则预留失败。实现上reserve_crashkernel_generic()检测到crash_base非零时设置fixed_base true并将搜索区间固定为[crash_base, crash_base crash_size)随后调用memblock_phys_alloc_range()尝试在该精确区间分配分配失败即打印 cannot allocate crashkernel 告警并返回不会在其他位置兜底。这种形式适用于对预留位置有硬性要求的场景例如需要与固件、bootloader 约定固定地址但要求使用者精确掌握平台内存布局。2) crashkernelsize按搜索顺序自动预留推荐crashkernel 内存区域将按以下搜索顺序在任意可用位置预留内核首先在低内存区域[0, CRASH_ADDR_LOW_MAX)搜索指定大小的可用区域若低内存搜索失败内核回退到高内存区域[CRASH_ADDR_LOW_MAX, CRASH_ADDR_HIGH_MAX)搜索若高内存预留成功则随后在低内存中做一次默认大小的预留当前默认值为 128M足以满足 kdump 内核的低内存需求。注意crashkernelsize是 crashkernel 预留的推荐选项用户无需了解特定平台的内存布局。这一点在源码中体现得非常直观——kernel/crash_reserve.c 的reserve_crashkernel_generic()首次分配失败后若!high search_end CRASH_ADDR_LOW_MAX即本次尝试的是低内存则将搜索区间切换到高内存并设置crash_low_size DEFAULT_CRASH_KERNEL_LOW_SIZE后重试高内存预留成功后再检查crash_base CRASH_ADDR_LOW_MAX crash_low_size成立与否调用reserve_crashkernel_low()完成低内存默认预留低内存预留失败则会释放已预留的高内存区域并整体失败避免出现有高无低的不完整状态。3) crashkernelsize,high 与 crashkernelsize,low高低内存分别指定crashkernelsize,(high|low)是对crashkernelsize的重要补充允许用户分别指定需要从高内存和低内存分配多少内存。在许多系统上低内存非常宝贵应尽量将 crashkernel 预留控制到最小。预留流程如下首先尝试从高内存区域为crashkernelsize,high预留内存若预留成功随后进行低内存预留若高内存预留失败内核回退到低内存区域按crashkernel,high中指定的大小搜索若低内存预留成功则无需再额外做低内存预留。注意事项若未指定crashkernel,low将自动进行默认的低内存预留128M若指定crashkernel0,low表示有意省略低内存预留。在parse_crashkernel()中当crashkernel,high解析成功但未检测到crashkernel,low时返回-ENOENT*low_size会被赋值为DEFAULT_CRASH_KERNEL_LOW_SIZE128MB而crashkernel0,low则会解析出low_size 0配合reserve_crashkernel_generic()中crash_low_size为 0 时跳过低内存预留的逻辑实现有意省略。预留对齐与资源注册crashkernel 预留遵循 2MB 对齐CRASH_ALIGN SZ_2M这源于当前 arm64 启动协议对 2MB 对齐的要求。预留完成后内核通过insert_resource()将crashk_res以及HAVE_ARCH_ADD_CRASH_RES_TO_IOMEM_EARLY时的crashk_low_res注册进iomem_resource从而在/proc/iomem中以 Crash kernel 资源形式暴露给用户空间例如kexec-tools据此定位预留区。同时crashk_res/crashk_low_res在 kernel/crash_core.c 中被进一步用于 kdump 相关导出是kdump用户态工具完成预加载捕获内核的物理基础。实战配置示例与注意事项在实际部署 kdump 时可结合平台情况选择以下配置# 方案一推荐完全交由内核自动搜索无需了解内存布局 crashkernel512M # 方案二大内存预留放在高内存低内存只保留最小必要量 crashkernel512M,high crashkernel128M,low # 方案三有意省略低内存预留低内存极度紧张时慎用 crashkernel512M,high crashkernel0,low # 方案四指定精确物理地址需对平台内存布局有把握 crashkernel256M0x50000000 # 方案五扩展语法按系统内存量分档可选配 CMA 预留 crashkernel0M-2G:128M,2G-8G:256M,8G-:512M配置要点与限制预留大小校验解析器会拒绝大小为 0 或大于等于系统总内存的配置返回-EINVAL配置前应确认crashkernelsize的 size 小于系统 RAM。对齐要求预留区域按 2MB 对齐指定sizeoffset时 offset 也应遵循 2MB 对齐否则分配行为以memblock_phys_alloc_range的实际结果为准。低内存上限差异RPi4 平台低内存上限为 1G大多数其他 arm64 平台为 4G而CONFIG_ZONE_DMA/DMA32均被禁用时整个 RAM 都是低内存。判断当前平台上限可查看启动日志中 crashkernel 预留打印crashkernel reserved: ...与/proc/iomem中的 Crash kernel 区域位置。预留失败的观测若预留失败内核会打印pr_err(cannot allocate crashkernel low memory ...)或pr_warn(cannot allocate crashkernel ...)可在dmesg中定位原因通常是内存碎片导致无法找到连续大块或低内存不足。总结arm64 的 crashkernel 预留机制通过架构层动态确定低内存上限 通用层统一解析与搜索分配的分层设计既保证了crashkernelsize的易用性用户无需了解平台布局又通过crashkernelsize,high/size,low为低内存紧张的场景提供了精细控制手段。理解 Documentation/arch/arm64/kdump.rst 所描述的三种语法及其在 kernel/crash_reserve.c、arch/arm64/mm/init.c 中的实现路径将帮助你在各类 arm64 平台含 RPi4 等 DMA 受限平台上快速、正确地完成 kdump 内存预留配置并为 vmcore 的稳定捕获打下基础。【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表