1. 内存要求
首先查看CPU架构uname -m
,然后参考链接Section 7.8.1, “Memory requirements for kdump“
CPU架构 | 可用内存 | Crash预留内存 |
---|---|---|
AMD64 和 Intel 64 (x86_64) | 2 GB + | 161 MB + 64 MB 每 1 TB |
64-bit ARM 架构 (arm64) | 2 GB + | 512 MB |
1.1. 估计kdump大小
$ sudo makedumpfile -f --mem-usage /proc/kcore
TYPE PAGES EXCLUDABLE DESCRIPTION
----------------------------------------------------------------------
ZERO 28670 yes Pages filled with zero
NON_PRI_CACHE 875525 yes Cache pages without private flag
PRI_CACHE 159 yes Cache pages with private flag
USER 311449 yes User process pages
FREE 2479751 yes Free pages
KERN_DATA 386929 no Dumpable kernel data
page size: 4096
Total pages on system: 4082483
Total size on system: 16721850368 Byte
2. 安装kdump
2.1. yum安装kdump
$ sudo yum install kexec-tools
$ rpm -qa kexec-tools
kexec-tools-2.0.20-46.el8_4.2.x86_64
如果需要图形配置工具,请执行:
$ sudo yum install system-config-kdump
2.2. 源码安装kdump
源码链接:
- http://kernel.org/pub/linux/utils/kernel/kexec/kexec-tools.tar.gz
- http://www.kernel.org/pub/scm/utils/kernel/kexec/kexec-tools.git
tar xvpzf kexec-tools.tar.gz
cd kexec-tools-VERSION
./configure
make
make install
3. 配置kdump
3.1. 内核编译配置需求
参见链接:System kernel config options
CONFIG_KEXEC=y or CONFIG_KEXEC_FILE=y
CONFIG_KEXEC_CORE=y
CONFIG_CRASH_CORE=y
CONFIG_SYSFS=y
CONFIG_DEBUG_INFO=Y
CONFIG_CRASH_DUMP=y
CONFIG_PROC_VMCORE=y
CONFIG_HIGHMEM64G=y
CONFIG_RELOCATABLE=y
3.2. 配置kdump命令行
配置系统的boot loader配置文件crashkernel=
,依照上面说的需要预留的内存大小,进行设置,如:
crashkernel=128M
语法为:
crashkernel=<range1>:<size1>[,<range2>:<size2>,...][@offset]
range=start-[end]
所以这个参数也可以定义为动态参数:
crashkernel=512M-2G:64M,2G-:128M
或者:
crashkernel=128M@16M
上面的参数,在文件/etc/grub2-efi.cfg
(不同系统,这个文件可能有差异)。
先查看当前的内核命令行:
$ cat /proc/cmdline
BOOT_IMAGE=(hd0,gpt2)/vmlinuz-4.18.0-30501.10.2.el8.x86_64 root=/dev/mapper/cl-root ro crashkernel=auto resume=/dev/mapper/cl-swap rd.lvm.lv=cl/root rd.lvm.lv=cl/swap rhgb quiet
打开文件/etc/grub2-efi.cfg
$ sudo vim /etc/grub2-efi.cfg
在其中一行找到:
if [ -z "${kernelopts}" ]; then
set kernelopts="root=/dev/mapper/cl-root ro crashkernel=auto resume=/dev/mapper/cl-swap rd.lvm.lv=cl/root rd.lvm.lv=cl/swap rhgb quiet "
fi
我们要做的,就是在变量kernelopts
中添加crashkernel=
参数:
if [ -z "${kernelopts}" ]; then
set kernelopts="root=/dev/mapper/cl-root ro crashkernel=auto resume=/dev/mapper/cl-swap rd.lvm.lv=cl/root rd.lvm.lv=cl/swap rhgb quiet crashkernel=128M"
fi
3.3. 配置kdump类型
当内核crash时候,产生的coredump文件可以存在一个文件系统的文件中,也可以发送到网络文件系统NFS,或者SSH协议中。当然只能选择其中之一:
- 文件系统;
- NFS
- SSH
3.3.1. vmcore保存到本地文件系统
编辑文件/etc/kdump.conf
,
path /var/crash
说明,vmcore会保存在路径/var/crash
下。你可以修改这个路径到任意路径,如:
path /usr/local/cores
如果vmcore存在了/var/crash/var/crash
中,那么/etc/kdump.conf
文件可能为:
grep -v ^# etc/kdump.conf | grep -v ^$
ext4 /dev/mapper/vg00-varcrashvol
path /var/crash
core_collector makedumpfile -c --message-level 1 -d 31
这种情况把path /var/crash
改为path /
即可。
3.3.2. vmcore保存到nfs
略,参见CHAPTER 7. KERNEL CRASH DUMP GUIDE。
3.3.3. vmcore保存到ssh
略,参见CHAPTER 7. KERNEL CRASH DUMP GUIDE。
3.4. 配置core收集器
为了减小coredump文件大小,kdump与虚拟定义一个外部的应用压缩数据,当前,唯一的collector是 makedumpfile
。
为了使能core收集器,需要把/etc/kdump.conf
中原有的:
core_collector makedumpfile -l --message-level 7 -d 31
--message-level
指定了信息收集的级别,1为只打印process indicator 日志信息,默认值为7,具体见下表:
Message | progress common error debug report
Level | indicator message message message message
---------+------------------------------------------------------
0 |
1 | X
2 | X
4 | X
* 7 | X X X
8 | X
16 | X
31 | X X X X X
-d 指定了kdump的过滤级别,具体见下表:
| cache cache
Dump | zero without with user free
Level | page private private data page
-------+---------------------------------------
0 |
1 | X
2 | X
4 | X X
8 | X
16 | X
31 | X X X X X
31表示过滤掉以上五种全部信息,这样kdump生成的速度就会更快,生成的vmcore文件也会较小。如果此处使用值0 ,表示不过滤任何信息,在kdump生成时,会记录主机当前的所有信息。这就是为什么在kdump生成时,有些主机只有几十M大小生成,有些主机确有几十 G大小的原因。更多用法可以查看makedumpfile命令的帮助文档。
注释掉原有的(或者直接使用原有的也可以):
# core_collector makedumpfile -l --message-level 7 -d 31
为了使能dump文件压缩,使用选项-l
:
core_collector makedumpfile -l
为了移除特定的page,使用-d value
参数,例如,为了移除零页和空闲页,可以使用:
core_collector makedumpfile -d 17 -c
详情请参考makedumpfile(8)
手册。
3.5. 配置默认动作
kdump将直接保存coredump到特定的类型中(上面已经提到:本地文件系统,NFS,SSH)。
默认情况下,kdump将重启系统:
default reboot
我把它设置为:
default dump_to_rootfs
在文件/etc/kdump.conf
中有注释:
# default <reboot | halt | poweroff | shell | dump_to_rootfs>
# - Same as the "failure_action" directive above, but this directive
# is obsolete and will be removed in the future.
#
他们的含义如下:
dump_to_rootfs
: 尝试将核心转储保存到根文件系统。此选项与网络目标结合使用时特别有用:如果网络目标不可访问,此选项将配置 kdump 以在本地保存核心转储。系统随后重新启动。reboot
: 重新启动系统,在此过程中丢失核心转储。halt
: 停止系统,在此过程中丢失核心转储。poweroff
: 关闭系统电源,在此过程中丢失核心转储。shell
: 从 initramfs 中运行 shell 会话,允许用户手动记录核心转储。
参见链接:支持的默认操作
3.6. 使能kdump服务
查看当前kdump服务状态:
$ systemctl status kdump
● kdump.service - Crash recovery kernel arming
Loaded: loaded (/usr/lib/systemd/system/kdump.service; enabled; vendor preset: enabled)
Active: active (exited) since Mon 2021-10-11 09:09:14 CST; 1 day 10h ago
Main PID: 2281 (code=exited, status=0/SUCCESS)
Tasks: 0 (limit: 99096)
Memory: 0B
CGroup: /system.slice/kdump.service
如果没有启动,手动启动kdump:
$ sudo systemctl start kdump.service
设置开机自启:
$ sudo systemctl enable kdump.service
3.7. kdump涉及的sysctl 配置
在配置kdump时,对sysctl.conf 内的一些配置也进行了调整。这里也列举下,可以根据具体的情况酌情进行修改。
kernel.sysrq=1
kernel.unknown_nmi_panic=1
kernel.softlockup_panic=1
-
kernel.sysrq=1,如果通过/proc文件配置 ,上面的配置等价于echo 1 > /proc/sys/kernel/sysrq ,打开sysrq键的功能以后,有终端访问权限的用户将会拥有一些特别的功能。如果系统出现挂起的情况或在诊断一些和内核相关,
使用这些组合键能即时打印出内核的信息。因此,除非是要调试,解决问题,一般情况下,不要打开此功能。如果一定要打开,请确保你的终端访问的安全性。具体可以参看百度百科上给出的解释。 -
kernel.unknown_nmi_panic=1 ,如果系统已经是处在Hang的状态的话,那么可以使用NMI按钮来触发Kdump。开启这个选项可以:echo 1 > /proc/sys/kernel/unknown_nmi_panic 需要注意的是,启用这个特性的话,是不能够同时启用NMI_WATCHDOG的!否则系统会Panic!
-
kernel.softlockup_panic=1,其对应的是/proc/sys/kernel/softlockup_panic的值,值为1可以让内核在死锁或者死循环的时候可以宕机重启。如果你的机器中安装了kdump,在重启之后,你会得到一份内核的core文件,这时从core文件中查找问题就方便很多了,而且再也不用手动重启机器了。如果你的内核是标准内核的话,可以通过修改/proc/sys/kernel/softlockup_thresh来修改超时的阈值,如果是CentOS内核的话,对应的文件是/proc/sys/kernel/watchdog_thresh。
除此之外,一些站点上还会建议修改开启oops painc的功能,这个也具体根据实际需要修改吧。
3.8. 在图形界面下配置kdump
略,参考:Basic Setting。
4. 加载Dump-capture Kernel
参考链接:Load the Dump-capture Kernel
在启动系统内核后,dump-capture内核需要加载。根据不同的架构,可以选择加载vmlinux
或者压缩的bzImage/vmlinuz
的dump-capture内核。
架构 | 选项 |
---|---|
i386/x86_64 | 如果内核可重定向,选择bzImage/vmlinuz |
如果内核不可重定向,选择vmlinuz | |
ppc64 | vmlinux |
s390x | image 或 bzImage |
ia64 | vmlinux 或 vmlinuz.gz |
arm | zImage |
arm64 | vmlinux 或 Image |
- 如果使用非压缩的vmlinux image,使用下面的命令行加载dump-capture 内核:
kexec -p <dump-capture-kernel-vmlinux-image> \
--initrd=<initrd-for-dump-capture-kernel> --args-linux \
--append="root=<root-dev> <arch-specific-options>"
- 如果使用压缩的bzImage/vmlinuz,使用下面的命令行加载dump-capture 内核:
kexec -p <dump-capture-kernel-bzImage> \
--initrd=<initrd-for-dump-capture-kernel> \
--append="root=<root-dev> <arch-specific-options>"
- 如果使用压缩的zImage,使用下面的命令行加载dump-capture 内核:
kexec --type zImage -p <dump-capture-kernel-bzImage> \
--initrd=<initrd-for-dump-capture-kernel> \
--dtb=<dtb-for-dump-capture-kernel> \
--append="root=<root-dev> <arch-specific-options>"
- 如果使用非压缩的Image,使用下面的命令行加载dump-capture 内核:
kexec -p <dump-capture-kernel-Image> \
--initrd=<initrd-for-dump-capture-kernel> \
--append="root=<root-dev> <arch-specific-options>"
注意:
--args-linux
在ia64中不需要。
下面是一些架构特有的参数:
架构 | 选项参数 |
---|---|
i386, x86_64, ia64 | “1 irqpoll nr_cpus=1 reset_devices” |
ppc64 | “1 maxcpus=1 noirqdistrib reset_devices” |
s390x | “1 nr_cpus=1 cgroup_disable=memory” |
arm | “1 maxcpus=1 reset_devices” |
arm64 | “1 nr_cpus=1 reset_devices” |
加载dump-capture内核的注意事项:
-
默认情况下,ELF 标头以
ELF64
格式存储,以支持超过 4GB 内存的系统。在 i386 上,kexec 会自动检查物理 RAM 大小是否超过 4 GB 限制,如果没有,则使用 ELF32。因此,在非 PAE 系统上,始终使用 ELF32。--elf32-core-headers
选项可用于强制生成 ELF32 标头。这是必要的,因为 GDB 当前无法在 32 位系统上打开带有 ELF64 标头的 vmcore 文件。
-
“
irqpoll
”引导参数减少了由于转储捕获内核中的共享中断导致的驱动程序初始化失败。 -
您必须以与 mount 命令输出中的根设备名称对应的格式指定 。
-
引导参数“1”将转储捕获内核引导至单用户模式,无需联网。如果您想要联网,请使用“3”。
-
我们通常不必为了捕获转储而启动 SMP 内核。因此,通常构建 UP 转储捕获内核或在加载转储捕获内核时指定 maxcpus=1 选项很有用。请注意,尽管 maxcpus 始终有效,但如果当前 ARCH(例如 x86)支持,您最好将其替换为 nr_cpus 以节省内存。
-
如果您打算使用多线程程序,您应该在转储捕获内核中启用多 CPU 支持,例如 makedumpfile 的并行转储功能。否则,多线程程序可能会有很大的性能下降。要启用多 CPU 支持,您应该启动 SMP 转储捕获内核并在加载时指定
maxcpus/nr_cpus
、disable_cpu_apicid=[X]
选项。 -
对于 s390x,有两种 kdump 模式: 如果使用 elfcorehdr= kernel 参数指定了 ELF 标头,则 kdump 内核将使用它,就像在所有其他架构上一样。如果未指定 elfcorehdr= 内核参数,则 s390x kdump 内核会动态创建标头。第二种模式的优点是对于 CPU 和内存热插拔,kdump 不必使用 kexec_load() 重新加载。
-
对于具有许多附加设备的 s390x 系统,应该将“cio_ignore”内核参数用于 kdump 内核,以防止为与 kdump 无关的设备分配内核内存。这同样适用于使用 SCSI/FCP 设备的系统。在这种情况下,在将 FCP 设备设置为在线之前,应将“allow_lun_scan”zfcp 模块参数设置为零。
5. 内核驱动kdump黑名单
在文件/etc/sysconfig/kdump
的KDUMP_COMMANDLINE_APPEND=
参数中添加:
KDUMP_COMMANDLINE_APPEND="irqpoll nr_cpus=1 reset_devices cgroup_disable=memory mce=off numa=off udev.children-max=2 pani c=10 rootflags=nofail acpi_no_memhotplug transparent_hugepage=never nokaslr novmcoredd hest_disable"
并且知名下面其中之一:
rd.driver.blacklist=<modules>
modprobe.blacklist=<modules>
步骤如下:
- 选择一个需要加入黑名单的模块:
$ lsmod
Module Size Used by
macvtap 16384 0
macvlan 28672 1 macvtap
tap 28672 1 macvtap
loadavg_proc_show 16384 0
binfmt_misc 20480 1
xt_CHECKSUM 16384 1
[...]
- 更新文件
/etc/sysconfig/kdump
的KDUMP_COMMANDLINE_APPEND=
参数:
KDUMP_COMMANDLINE_APPEND="rd.driver.blacklist=fuse irqpoll nr_cpus=1 reset_devices cgroup_disable=memory mce=off numa=off udev.children-max=2 panic=10 rootflags=nofail acpi_no_memhotplug transparent_hugepage=never nokaslr novmcoredd hest_disa ble"
当然,也可以改为:
KDUMP_COMMANDLINE_APPEND="modprobe.blacklist=fuse irqpoll nr_cpus=1 reset_devices cgroup_disable=memory mce=off numa=off udev.children-max=2 panic=10 rootflags=nofail acpi_no_memhotplug transparent_hugepage=never nokaslr novmcoredd hest_disa ble"
- 重启kdump服务:
$ sudo systemctl restart kdump
重启需要好几秒。
6. 测试kdump
6.1. kdump Panic
下面的命令将导致内核奔溃crash,不要用于生产环境。
下面的命令将导致内核奔溃crash,不要用于生产环境。
下面的命令将导致内核奔溃crash,不要用于生产环境。
查看kdump是否激活:
$ sudo systemctl is-active kdump
active
然后执行下面两行指令:
$ su
# echo 1 > /proc/sys/kernel/sysrq
# echo c > /proc/sysrq-trigger
上面的两条指令,导致内核crash,文件address-YYYY-MM-DD-HH:MM:SS/vmcore
将被拷贝到上面配置文件/etc/kdump.conf
指定的文件路径path /var/crash
中。
6.2. 写dump文件
在dump-capture内核启动之后,写出dump文件:
cp /proc/vmcore <dump-file>
你也可以使用makedumpfile
工具指定特定的过滤规则:
makedumpfile -l --message-level 1 -d 31 /proc/vmcore <dump-file>
6.3. gdb分析
分析之前,你应该重启系统。使用gdb调试:
gdb vmlinux <dump-file>
6.4. crash分析
也可以使用crash工具进行分析,链接如下:
例:
crash /usr/lib/modules/4.18.0-30501.10.2.el8.x86_64/vmlinuz vmcore
7. 参考链接
7.1. 文章
- CHAPTER 7. KERNEL CRASH DUMP GUIDE
- Section 7.8.1, “Memory requirements for kdump“
- CHAPTER 3. LISTING OF KERNEL PARAMETERS AND VALUES
- Linux Documentation for Kdump - The kexec-based Crash Dumping Solution
- http://horms.net/projects/kexec/
- https://crash-utility.github.io/
- centos配置kdump捕获内核崩溃
- 5分钟搞懂kexec工作原理
7.2. 源码
- http://kernel.org/pub/linux/utils/kernel/kexec/kexec-tools.tar.gz
- http://www.kernel.org/pub/scm/utils/kernel/kexec/kexec-tools.git
- https://github.com/crash-utility/crash
8. 附录
8.1. kexec工作原理
kexec可从当前正在运行的内核直接跳转到新内核,kexec整体思路如下
- 新的kernel镜像和initrd镜像连续存储在内存中,initrd的位置记录在boot_params中
- 切换到新内核就是跳转到新的kernel镜像所在内存位置,CPU执行其entry的代码即可,新的内核通过boot_params记录的initrd位置完成根文件系统内容的加载
8.2. kdump执行流程
8.3. crash分析
略。
crash /usr/lib/modules/4.18.0-30501.10.2.el8.x86_64/vmlinuz vmcore