Kernel Crash kdump 使用指南

Kernel Crash kdump 使用指南

荣涛
2021年10月12日

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

源码链接:

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协议中。当然只能选择其中之一:

  1. 文件系统;
  2. NFS
  3. 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
ppc64vmlinux
s390ximagebzImage
ia64vmlinuxvmlinuz.gz
armzImage
arm64vmlinuxImage
  • 如果使用非压缩的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 限制,如果没有,则使用 E​​LF32。因此,在非 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_cpusdisable_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/kdumpKDUMP_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>

步骤如下:

  1. 选择一个需要加入黑名单的模块:
$ 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
[...]
  1. 更新文件/etc/sysconfig/kdumpKDUMP_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"
  1. 重启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. 文章

7.2. 源码

8. 附录

8.1. kexec工作原理

参考:5分钟搞懂kexec工作原理

kexec可从当前正在运行的内核直接跳转到新内核,kexec整体思路如下

  1. 新的kernel镜像和initrd镜像连续存储在内存中,initrd的位置记录在boot_params中
  2. 切换到新内核就是跳转到新的kernel镜像所在内存位置,CPU执行其entry的代码即可,新的内核通过boot_params记录的initrd位置完成根文件系统内容的加载

8.2. kdump执行流程

参考:centos配置kdump捕获内核崩溃

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

8.3. crash分析

略。

crash /usr/lib/modules/4.18.0-30501.10.2.el8.x86_64/vmlinuz vmcore

Copyright (C) CESTC Com.
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值