栏目介绍:“玩转OurBMC”是OurBMC社区开创的知识分享类栏目,主要聚焦于社区和BMC全栈技术相关基础知识的分享,全方位涵盖了从理论原理到实践操作的知识传递。OurBMC社区将通过“玩转OurBMC”栏目,帮助开发者们深入了解到社区文化、理念及特色,增进开发者对BMC全栈技术的理解。
欢迎各位关注“玩转OurBMC”栏目,共同探索OurBMC社区的精彩世界。同时,我们诚挚地邀请各位开发者向“玩转OurBMC”栏目投稿,共同学习进步,将栏目打造成为汇聚智慧、激发创意的知识园地。
在BMC对服务器的监控与管理过程中,我们为了实现对服务器的更优化管理,往往需要与其它工具紧密协同工作,以增强监控的全面性,提高管理的灵活性,并促进问题的快速解决。本期内容,我们将对 内核崩溃转储机制kdump 进行介绍。首先,对kdump整体运行流程进行介绍,然后分别对kdump配置工具、内核启动参数、服务程序、系统重启转储流程等方面内容进行概述,以帮助读者更好的理解和运用kdump。
Kdump整体流程(简单流程)
Kdump是Linux系统中的一个内核崩溃转储机制,用于在系统崩溃时自动捕获系统内存和寄存器状态,从而允许系统管理员或开发者在事后分析崩溃原因。这一机制对于诊断系统稳定性问题、硬件故障或内核错误等非常有用。下图为kdump工作流程图。
Kexec-tools 工具
Kexec-tools是用于配置和启动kdump的核心工具,它允许在系统崩溃时自动捕获内存映像,并可用于在不影响当前运行的系统的情况下加载和启动另一个内核。这对于进行内核崩溃分析和调试非常有用。Kexec-tools提供的kexec命令利用kexec_load系统调用将捕获内核加载到内存中。
Kexec命令用-l来加载捕获内核,并通过-e来启动:
Kexec通过-p命令加载能够在内核crash时启动的捕获内核,并通过触发panic来启动:
内核启动参数
为了让kdump正常工作,内核启动时需要通过GRUB等引导程序给内核添加启动参数,这些参数主要涉及到为kdump保留的内存大小(crashkernel)和其他可能需要的配置。参数格式如下:
格式 1:crashkernel=Y[@X],其中Y代表为捕获内核预留的内存空间大小(以MB为单位),而@X是可选的,表示保留内存区域的起始位置(同样以MB为单位)。例如,crashkernel=512M,代表为捕获内核预留512M内存空间;crashkernel=64M@16M,代表预留64M空间,且在物理内存16M的位置。
格式 2: crashkernel=range1:size1[,range2:size2,…][@offset],这个格式允许根据系统的总内存大小来动态地决定为kdump预留的内存量。比如:crashkernel=512M-2G:64M,2G-:128M:
-如果RAM小于512M,不需要为kdump预留内存;
-如果 RAM 大小介于 512M 和 2G 之间(不含),为kdump预留 64M内存;
-如果 RAM 大小大于 2G,为kdump预留 128M内存;
当系统启动后,可以通过查看/proc/iomem文件并结合grep命令来检索Crash kernel项占用的内存大小。比如设置crashkernel=512M。
关于Linux内核中Crash kernel的具体配置参数,可以参考内核源代码目录下的Documentation/kdump/kdump.txt文档。
Kdump 服务程序
通过系统服务systemctl start kdump来启动kdump服务,其本质上是通过/usr/bin/kdumpctl 工具调用kexec加载捕获内核:
Kdump服务:
Kdumpctl是kdump服务的控制工具,用于管理kdump的启动、停止和配置。Kdumpctl首次启动需要生成一个特定的initramfs镜像文件(initramfs-xxxxkdump.img),这个文件在捕获内核启动后提供基本的文件系统、必要的驱动程序以及kdump-capture服务,用于将vmcore文件转储到指定位置。这些功能由kexec-tools软件包提供。
/usr/bin/kdumpctl start 启动load_kdump:
在当前系统kexec完整命令:
系统重启转储流程
在内核启动kdump触发panic之后,系统会快速重新启动,并加载kexec预先配置的内核以及initrd。前面了解到kexec会有--initrd参数,该参数是指定一个initramfs文件,通常带有kdump后缀,说明其具有和kdump相关性。我们通过lsinitrd工具来查看。
上述内容为系统中kdump相关配置的grep查询结果。其中,kdump-capture.service是一个在initramfs环境中启动的systemd服务单元文件,它负责在kdump过程中执行关键步骤,它依赖于在initramfs生成过程中添加的适当脚本和配置来执行内存转储。该文件在/usr/lib/dracut/modules.d/99kdumpbase目录下,由kexec-tools工具提供。kdump-capture.service文件的核心是指定了在服务启动时应该执行的命令,通常通过ExecStart指令设置为执行某个脚本:
ExecStart=/bin/kdump.sh.
该脚本会在kdump-lib-initramfs.sh脚本中调用dump_fs函数。
/bin/kdump.sh.:
/usr/lib/kdump/kdump-lib-initramfs.sh:dump_fs函数(以下内容为部分截选)。
由此可知,系统重启之后,通过kdump-capture服务,使用makedumpfile工具将/proc/vmcore文件保存到本地系统中。
makedumpfile 工具
操作系统触发kdump并进入 “捕获内核” 后,第一个内核(称为 “崩溃内核” )的内存映像可以在/proc/vmcore中获取,而第二个内核(称为 “kdump 内核” 或 “捕获内核” )正在运行。makedumpfile通过压缩转储数据或通过排除对分析内存错误没有任何帮助的页面,生成一个小的DUMPFILE文件。这个文件仅保留crash工具用来分析和调试所必须的页面。
makedumpfile在将vmcore复制到DUMPFILE时可以排除以下类型的页面,用户可以选择排除哪种类型的页面。
- 填充为零的页面
- 没有私有标志的缓存页面(非私有缓存)
- 有私有标志的缓存页面(私有缓存)
- 用户进程数据页面
- 空闲页面
makedumpfile提供了两种DUMPFILE格式(ELF格式和kdump压缩格式)。默认情况下,makedumpfile生成的是kdump压缩格式的DUMPFILE。Kdump压缩格式仅可用crash实用程序读取,由于支持压缩,因此其大小可能比ELF格式小。ELF格式可用GDB和crash实用程序读取。如果用户希望使用GDB,必须明确指定DUMPFILE格式为ELF格式。
makedumpfile可以将vmcore文件按照不同的压缩格式进行压缩,这种情况下只有crash功能能够解析。makedumpfile有参数-c,-l,-p分别对应不同的压缩方式:-c使用zlib,-l 使用lzo,默认情况下使用-l参数。
在默认情况下生成的vmcore文件格式如下:
以下为通过修改/etc/kdump.conf配置将core_collector makedumpfile -l --message-level 1 -d 31修改为core_collector makedumpfile -E --message-level 1 -d 31后生成的ELF格式的vmcore文件:
*开发者可以自行修改/etc/kdump.conf配置调整makedumpfile参数。修改后删除kdump版本的initramfs,重新启动kdump服务即可。
/proc/vmcore 和 /proc/kcore
正常启动的内核没有创建 /proc/vmcore文件,只有在crash kernel启动的时候才会创建,可以通过一定的手段进入到crash kernel中,让系统不重启:
第一步:进行修改/usr/bin/kdumpctl中代码:
第二步:执行kexec -p /boot/vmlinuz-5.10.0-60.48.0.76.oe2203.x86_64 --initrd=/boot/initramfs-5.10.0-60.48.0.76.oe2203.x86_64.img --command-line="root=/dev/mapper/openeuler-root"
第三步 :echo c > /proc/sysrq-trigger触发crash,让系统快速重启进入crashkernel。
注意:如果使用正常initrd,通过以上描述的方式将不会执行kdump-capture服务。而是启动了kdump服务,由于此时使用的是crash kernel,会创建./proc/vmcore文件,如果不注释reboot则会保存vmcore且重启。
从上述信息我们可以发现/proc/vmcore文件是ELF文件格式,这种格式是内核为之前的normal kernel创建的文件格式。其大小1.6G,是normal kernel启动时内存的大小。当前crash kernel启动后通过free命令发现是429M。大小和我们之前设置内核启动参数 “crashkernel=512M” 相近。
ELF 类型 4/ET_CORE:表示是elf文件格式的第四种类型。
其它三种格式:.o文件(ET_REL)、.so文件(ET_DYN)、static文件(ET_EXEC)
ET_CORE:通过crash调试就能恢复到故障现场。
我们利用makedumpfile工具将其保存下来:
/proc/vmcore文件只有捕获内核启动的时候才会创建,和vmcore类似,/proc/kcore是一个动态的内核文件,包含了系统运行中内核的所有数据(内核当前状态的映像),以ELF core file格式存储,与大多数/proc/目录下的文件不同的是:kcore显示了一个大小,该值以字节为单位。它由内核在fs/proc/kcore.c中创建,并允许从用户空间读取所有内核虚拟内存空间,通过ls -l展示它的大小是一个非常大数字(在64位系统上128T),但是它根本不占用任何磁盘空间:
与/proc中的所有其他文件一样,它的内容是由内核在读取文件时动态生成的,并且只能以root权限读取。我们可以通过makedumpfile -l --message-level 31 -d 31 /proc/kcore /tmp/kcore将其转储出来,利用crash工具进行调试。其本质和vmcore一样,在内部具有ELF核心转储文件的格式(ELF类型4/ET_CORE)。这种格式上的一致性确保了它与系统崩溃时自动生成的单个进程核心文件(core dump)在结构上保持一致,便于使用相同的工具集进行分析。然而,与进程级别的核心文件不同,makedumpfile生成的转储文件并非旨在捕获某个特定进程在崩溃瞬间的静态状态,而是旨在提供整个系统内存状态的实时快照。
/proc/kcore将当前系统的物理内存空间模拟成一个ELF核心转储(core dump)文件的格式,通过特定的工具和技术,如使用gdb(GNU调试器)结合一些特定的调试技巧和内核调试模块,以类似于调试程序的方式,来查看和分析系统的当前状态。
在拥有/proc/kcore文件以及当前版本的、包含调试信息的vmlinux内核映像的情况下,可以使用gdb(或crash)来实时检查和分析内核中任何数据结构的当前状态。
调试 vmcore 文件
生成的vmcore文件可以通过crash工具或者gdb进行调试。一般情况下我们使用crash工具来调试。Crash命令使用 :
方式crash [OPTION]... NAMELIST MEMORY-IMAGE[@ADDRESS] (dumpfile form)
上述NAMELIST代表未压缩的内核vmlinux文件,如果使用的是官方的rpm包,需要安装kernel-debuginfo软件包,直接安装的内核是压缩过并且不带调试信息。Openeuler系统可以在yum配置文件中打打开debuginfo仓库,执行yum install kernel-debuginfo安装。如果是自己编译的内核则位于源码编译目录下的vmlinux文件。
执行crash /usr/lib/debug/lib/modules/5.10.0-60.48.0.76.oe2203.x86_64/vmlinux vmcore进行调试。
本期内容为大家详细介绍了kdump基本知识。通过kdump,Linux系统管理员和开发者可以获得强大的工具来诊断和解决系统稳定性问题,从而提高系统的可靠性和安全性。下期内容我们将继续深入探索kdump,欢迎大家关注。
欢迎大家关注OurBMC社区,了解更多BMC技术干货。
OurBMC社区官方网站:
https://www.ourbmc.cn/