ubuntu内核转储分析------kdump和crash的下载和使用
内存转储机制
需要用到的工具
kexec
kexec是一个快速启动机制,允许通过已经运行的内核的上下文启动一个Linux内核,不需要经过BIOS。BIOS可能会消耗很多时间,特别是带有
众多数量的外设的大型服务器。这种办法可以为经常启动机器的开发者节省很多时间。Kexec是实现kdump机制的关键,它包括2个组成部分:
一是内核空间的系统调用kexec_load,负责在生产内核(production kernel 或 first kernel)启动时将捕获内核(capture kernel或sencond kernel)
加载到指定地址。
二是用户空间的工具kexec-tools,他将捕获内核的地址传递给生产内核,从而在系统崩溃的时候能够找到捕获内核的地址并运行。
没有kexec就没有kdump。先有kexec实现了在一个内核中可以启动另一个内核,才让kdump有了用武之地。
kdump
kdump是一种在linux内核崩溃时获取内存转储的方法,它的主要原理是为系统配置两个内核,其中用于运行正常业务的内核称为生产内核 ,而在内核崩溃时用于转储信息的内核被称为捕获内核(crash kernel)。最初系统通过生产内核启动,并在启动过程中为捕获内核保留其运行所需的内存。当系统启动完成后,它将通过应用层服务,将捕获内核镜像加载到其对应的保留内存中。此后,生产内核就可像其它系统一样,正常地处理相关的业务。
若内核在运行中发生崩溃,且已设置了捕获内核,则生产内核则会首先准备好转储文件,然后启动捕获内核。捕获内核启动以后,将会生成转储文件vmcore。
crash
当 linux 系统内核发生崩溃的时候,生成了转储文件 vmcore。而后通过分析该 vmcore 文件就可以诊断出内核崩溃的原因,从而进行操作系统的代码改进。而 crash 就是一个被广泛使用的内核崩溃转储文件分析工具。
安装kdump
bash
sudo apt install linux-crashdump
修改kexec-tools
|------------------------| Configuring kexec-tools |-------------------------------------|
| |
| |
| If you choose this option, a system reboot will trigger a restart into a |
| kernel loaded by kexec instead of going through the full system boot |
| loader process. |
| |
| Should kexec-tools handle reboots (sysvinit only)? |
| |
| |
| |
|------------------------------------------------------------------------------------------------|
安装成功后,将会在/etc/init.d中多了几个文件
kdump-tools
kexec
kexec-load
如果选择了No,也可以手动启动
bash
sudo dpkg-reconfigure kexec-tools
这将修改/etc/init.d/kexec中的LOAD_KEXEC ,LOAD_KEXEC=true
确认kdump-tool是否启用
bash
sudo kdump-config show
如果未安装kdump,将会提示
kdump-config: command not found
如果安装了kdump-config, 将会提示:
- /etc/default/kdump-tools: USE_KDUMP is not set or zero
- no crashkernel= parameter in the kernel cmdline
dpkg-query: package 'kdump-tools' is not installed and no information is available
修改USER_KDUMP
这个参数默认是0,有文章说可以通过下面命令修改/etc/default/kdump-tools 文件中的 USE_KDUMP 参数为 1,表示启用了这个功能。
bash
sudo dpkg-reconfigure kdump-tools
经过实测(包括重启)并没有什么效果,不清楚是什么原因。因此只能手动修改该参数
bash
sudo vim /etc/default/kdump-tools
USE_KDUMP=1
配置以后再次执行
bash
sudo kdump-config show
将不会提示 * /etc/default/kdump-tools: USE_KDUMP is not set or zero
修改crashkernel
如果存在/etc/default/grub.d/kdump-tools.cfg这个文件,执行
bash
sudo vi /etc/default/grub.d/kdump-tools.cfg
否则,执行
bash
sudo vi /etc/default/grub
将GRUB_CMDLINE_LINUX_DEFAULT=""
中的参数修改为
GRUB_CMDLINE_LINUX_DEFAULT="$GRUB_CMDLINE_LINUX_DEFAULT crashkernel=384M-:512M"
这个参数的格式是crashkernel=[总内存范围]:[保留内存大小]
[总内存范围]
可以是一个具体的内存大小,也可以是一个范围。例如,384M-表示总内存大小在384M以上。
[保留内存大小]
则是你想要保留的内存大小。这部分内存将在系统启动时被预留出来,用于在系统崩溃时保存内核转储。
所以384M-:512M这个参数的意思是,对于总内存大小在384M以上的系统,保留512M的内存用于内核转储。
更新grub配置
bash
sudo update-grub
重启系统以使配置生效
bash
sudo reboot
手动触发内核崩溃,生成转储文件
第一步:
bash
sudo sh -c "echo 1 > /proc/sys/kernel/sysrq"
第二步:
bash
sudo sh -c "echo c > /proc/sysrq-trigger"
这里不直接使用sudo echo x > /proc/xxx/xxx/xxx
的原因是使用它会报错Permission denied,是因为重定向符号 ">" 也是 bash 的命令。sudo 只是让 echo 命令具有了 root 权限,但是没有让 ">" 命令也具有root 权限,所以 bash 会认为这个命令没有写入信息的权限。
其中echo 1 > /proc/sys/kernel/sysrq
和echo c > /proc/sysrq-trigger
是用来触发SysRq功能的命令。SysRq功能是一种种魔术系统请求键,可以让用户向内核发送一些特殊的命令,以获取或控制系统的信息或状态。
echo 1 > /proc/sys/kernel/sysrq
向sysrq文件中写入1是为了开启SysRq功能(写入0是关闭SysRq功能),但是这需要内核支持(CONFIG_MAGIC_SYSRQ选项),它会让内核响应用户输入的任何操作,只要内核没有挂掉。此功能只是临时开启,重启后SysRq会自动关闭。如果想让此功能一直生效,在/etc/sysctl.conf
里面设置kernel.sysrq
的值为1. 重新启动以后,此功能将会自动打开。
echo c > /proc/sysrq-trigger
是用来触发故意让系统统崩溃(crash)命令的命令,它会让内核立即即崩溃,并且不会管你有没有数据没有写回回磁盘,也不卸载载磁盘,而是完完全全地关机。
执行后,等待系统重启,在/var/crush中会生成几个文件,
root@ubuntu10:/var/crash# tree .
.
├── 202401021909
│ ├── dmesg.202401021909
│ └── dump.202401021909
├── kexec_cmd
└── linux-image-3.13.0-24-generic-202401021909.crash
其中
- kexec_cmd是默认就有的
- dmesg.202401021909:这个文件是系统内核崩溃时的内核日志,它记录了内核崩溃的原因和上下文信息,可以用来分析内核崩溃的原因和过程。
- dump.202401021909:这个文件是系统内核崩溃时的内核内存转储文件,它包含了内核崩溃时的内存状态,可以用来分析内核崩溃的现场和数据。
- linux-image-3.13.0-24-generic-202401021909.crash:这个文件是系统内核崩溃时,使用apport命令来生成的崩溃报告文件,它包含了系统内核的版本和配置信息,以及内核崩溃的时间和环境信息,可以用来报告和追踪内核崩溃的问题。
补充知识一:sysrq的参数
- b - 即时重新启动系统
- o - 即时关机
- s - 即时同步所有挂载的文件系统
- u - 即时重新挂载所有的文件系统为只读
- p - 导出当前CPU寄存器信息和标志位的信息
- t - 导出线程状态信息
- m - 导出关于内存分配的信息
- c - 故意让系统统崩溃(在使用netdump或diskdump的时候有用)
- e - 杀死所有进程除了init使用SIGTERM
- i - 杀死所有进程除了init使用SIGKILL
当一个sysrq命令被触发,内核将会打印信息到内核的环形缓冲并输出到系统控制台。此信息一般也会通过syslog输出到/var/log/messages
或/var/log/syslog
。有时候,可能系统已无法响应,syslogd可能无法记录此信息。在这种情况下,建议你设置一个串口终端来收集这个信息。
补充知识二:CONFIG_XXX参数一般不需要修改
有的文章linux内核调试(四)内核转储kdump说,在安装kdump后,需要修改这几个参数,来支持kexec
CONFIG_KEXEC=y
CONFIG_SYSFS=y
CONFIG_DEBUG_KERNEL=y
CONFIG_CRASH_DUMP=y
CONFIG_PROC_VMCORE=y
CONFIG_DEBUG_INFO=y
这些针对的是高阶用户的,实际上除了CONFIG_DEBUG_INFO外,其他几个参数默认都是y,可以通过下面的命令查看。
bash
sudo vim /usr/src/linux-headers-$(uname -r)/.config
据说CONFIG_DEBUG_INFO开启后,会使得编译出的内核和模块文件的大小大大增加,所以一般也不需要选。
设置内核崩溃系统自动重启
打开sysctl.conf文件:
bash
sudo vim /etc/sysctl.conf
在文件末尾添加以下行以配置内核崩溃后自动重启:
kernel.panic = 10
这将设置系统在内核崩溃后等待10秒后自动重启。您可以根据需要调整等待时间。
运行以下命令以使更改生效:
bash
sudo sysctl -p
使用crash调试
查看是否存在vmlinux
bash
ls //usr/lib/debug/boot
下载namelist:
namelist是一个包含了内核调试符号的vmlinux内核镜像文件
内核调试符号是指包含了调试信息的内核镜像文件,它可以帮助开发者或者分析者定位内核的错误或者性能问题。
添加一个新的源到/etc/apt/sources.list.d
bash
echo "deb http://ddebs.ubuntu.com $(lsb_release -cs)-updates main restricted universe multiverse
deb http://ddebs.ubuntu.com $(lsb_release -cs)-security main restricted universe multiverse
deb http://ddebs.ubuntu.com $(lsb_release -cs)-proposed main restricted universe multiverse" | \
sudo tee -a /etc/apt/sources.list.d/ddebs.list
执行更新源
bash
sudo apt update
如果报错The following signatures couldn't be verified because the public key is not available: NO_PUBKEY C8CAB6595FDFF622
添加软件源公钥
bash
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys C8CAB6595FDFF622
这里的keys后面的值,填写报错信息里面信息里面NO_PUBKEY
后的值
再次执行
bash
sudo apt update
下载vmlinux
bash
sudo apt-get install linux-image-$(uname -r)-dbgsym
再次执行
bash
ls /usr/lib/debug/boot
就能看到下载好的文件
下载指定的vmlinux内核镜像如果上面的方法行不通,还有其他两种方法,参见Ubuntu安装上的vmlinux在哪里?
使用crash命令查看内核转储文件
命令格式
bash
crash [options] namelist [dumpfile] [modpath]
其中
- namelist是一个包含了内核调试符号的内核镜像文件
- dumpfile是一个内核崩溃数据文件或者实时系统的设备名
- modpath是一个包含了内核模块的目录
例如:
bash
crash /usr/lib/debug/boot/vmlinux-3.13.0-24-generic /var/crash/202401021909/dump.202401021909