最近在回顾kdump内核崩溃转储技术,刚好可以整理下相关知识点,系统性地讲解下Kdump的部署过程以及原理。
kdump内核崩溃转储技术在处理linux内核遇到宕机等异常问题中,可以将其崩溃瞬间的内存映像(包括函数栈,内存,CPU等信息)都保留下来,方便开发者分析故障原因。类似于应用层的coredump机制。
部署Kdump过程需要了解几个知识点:
需要使能以下几个config参数并编译:
- 在"Processor type and features.“下使能"kexec system call”。 CONFIG_KEXEC=y
- 在"Filesystem" -> “Pseudo filesystems.“下使能"sysfs file system support”。 CONFIG_SYSFS=y
- 在"Kernel hacking.“下使能"Compile the kernel with debug info” 。 CONFIG_DEBUG_INFO=y
- 在"Processor type and features"下使能"kernel crash dumps”。 CONFIG_CRASH_DUMP=y
- 在"Filesystems" -> “Pseudo filesystems"下使能”/proc/vmcore support"。 CONFIG_PROC_VMCORE=y
kudmp机制实现的核心就是kexec,kexec可以将第二内核(捕获内核)装载到指定内存,当在第一内核崩溃瞬间,切换到第二内核(捕获内核)运行。
Kexec 来自于“kexec-tools”组件,编译 kexec-tools 工具包以得到 kexec工具(centos可以下载kexec-tools包直接安装)。内核要开启kexec,需要按如上描述开启CONFIG_KEXEC 选项
kexec命令调用语法如下:
kexec -l < kernel-image > --initrd=< initramfsxxx.img > --append="< command-line-options >"
如:如果想要启动镜像 /boot/bzImage, /proc/cmdline 的内容是 “root=/dev/hda1” ,那么装载内核的命令将是:
kexec -l /boot/bzImage -append=“root=/dev/hda1” (即告知kexec入口)
- kernel-image: 是您想要重新启动后的内核文件。
- initramfsxxx.img:捕获内核的根文件系统
- command-line-options: 需要传递到捕获内核的命令行cmdline参数。通常传递 /proc/cmdline 的内容参数即可。
kexec -e 系统自动切换到捕获内核运行(需要上述指定捕获内核入口)
kexec -p < kernel-image > --initrd=< initramfsxxx.img > --append="< command-line-options >"
上述可知:kexec 需要捕获内核的文件,根文件系统文件。当发生内核崩溃时,会将第一内核的内存映像保存在/proc/vmcore
1、 crashkernel
为了开机每次自动适配捕获内核,在第一内核的cmdline下指定捕获内核的内存空间,即添加参数:crashkernel
crashkernel的内存选择可以参考:Documentation\kdump\ kdump.txt文件。当然,也可以直接用crashkernel=auto,系统自动分配。
While the “crashkernel=size[@offset]
- if the RAM is smaller than 512M, then don’t reserve anything (this is the “rescue” case)
- if the RAM size is between 512M and 2G (exclusive), then reserve 64M
- if the RAM size is larger than 2G, then reserve 128M
2、 initramfsxxx.img
initramfsxxx.img根文件系统文件,在切换到捕获内核里启动,我们可以对initramfsxxx.img里的内容人为做一些修改,比如启动时候需要挂载分区、运行一些程序或安装一些驱动。
如centos里,kdump服务能自动生成initramfsxxx.img,该镜像文件里有比较重要的一个kdump-initxxx.sh的脚本文件,用于对/proc/vmcore转储文件进行压缩(makedumpfile工具),以及盘分区挂载并拷贝文件到指定路径(默认拷贝到/var/log/crash下)。
当然,该img文件也可以手动通过mkinitramfs工具生成。
3、kexec -p xxx
每次启动需要执行kexec -p xxx 指定捕获内核入口。
在centos中通过kdump服务,开机自动完成了kexec设定了捕获内核的操作。如果/boot下没有捕获内核的根文件系统的镜像文件(xxxkdump.img),也将会自动生成。
centos为例,服务所在脚本里 /usr/bin/kdumpctl实际kexec装载命令如下:
/sbin/kexec -p --command-line="BOOT_IMAGE=/vmlinuz-3.10.0-123.el7.x86_64 root=UUID=79704805-e306-420b-827a-52849e1376c1 ro vconsole.keymap=us vconsole.font=latarcyrheb-sun16 rhgb quiet LANG=en_US.UTF-8 irqpoll nr_cpus=1 reset_devices cgroup_disable=memory mce=off numa=off udev.children-max=2 panic=10 rootflags=nofail acpi_no_memhotplug disable_cpu_apicid=0" --initrd=/boot/initramfs-3.10.0-123.el7.x86_64kdump.img /boot/vmlinuz-3.10.0-123.el7.x86_64
第一内核下的cmdline
cat /proc/cmdline
BOOT_IMAGE=/vmlinuz-3.10.0-123.el7.x86_64 root=UUID=79704805-e306-420b-827a-52849e1376c1 ro vconsole.keymap=us crashkernel=auto vconsole.font=latarcyrheb-sun16 rhgb quiet LANG=en_US.UTF-8
/etc/sysconfig/kdump 配置文件里,增加了捕获内核cmdline传入额外补充
KDUMP_COMMANDLINE_APPEND="irqpoll nr_cpus=1 reset_devices cgroup_disable=memory mce=off numa=off udev.children-max=2 panic=10 rootflags=nofail acpi_no_memhotplug"
通过echo c > /pros/sysrq-trigger 可触发使内核崩溃。然后生成转储文件vmcore。
当转储文件vmcore生成出来后,需要通过crash工具解析并分析,该工具依赖一个内核调试文件:vmlinux。
1、 vmlinux
这里说的的vmlinux是一个基于ELF格式的文件,它不过是可用于调试的内核映像的未压缩版本。 而zImage或bzImage是内核映像的压缩版本,通常用于引导。
kernel 映像文件 vmlinux 在编译的时候必须指定了 -g 参数,即带有调试信息,编译后才可以生成(centos里在:kernel-debuginfo–xxx.rpm内核包可找到)。
2、 crash
crash启动解析命令如下:
crash vmlinux vmcore
如果crash没有指定vmcore,则默认使用当前实时系统内存。
进入crash后,需要借助crash相关命令(命令略),可以获取第一内核宕机时的信息(如:各cpu调用栈,内存余量,进程信息等等),就可以分析出产生内核崩溃的具体原因了。