(production kernel):产品或者线上服务器当前运行的内核。
(capture kernel):系统崩溃时,使用kexec启动的内核,该内核用于捕获生产内核当前内存中的运行状态和数据信息。
当系统崩溃时,kdump利用kexec启动第二个内核,这个内核驻留在宿主系统内存保留区中,而且宿主内核无法访问它。第二个内核会捕获到崩溃内核的内存上下文并保存到dump文件中(vmcore)。
Kdump的核心实现基于Kexec(Kernel execution),kexec类似于Linux的exec系统调用。
Kexec可以快速启动一个新的内核(捕获内核),它会跳过BIOS或者Bootloader等引导程序的初始化阶段,这个特性可以让系统崩溃时快速切换到捕获内核,这样生产内核的内存就得到保留,Kdump的工作流程如下图所示:
捕获内核启动后,会像一般内核一样,去运行为它创建的ramdisk上的init程序。捕获内核ramdisk中的init脚本就可以通过通常的文件读写和网络来实现各种策略了。而各种转储机制就是在init中实现的。
为了在生产内核崩溃时能顺利启动捕获内核,捕获内核以及它的ramdisk是事先放到生产内核的内存中的(保留内存)。
在rhel/centos7.x系统上,kdump服务默认已经安装并且启用了。
但是有些时候,比如自定义安装系统时,可能kdump就不一定被安装及启用。
可以查看系统是否已经安装:
若没有安装,则可以执行命令安装
上文提到,要生成内核崩溃转储文件,需要预留内存空间给kdump服务,具体需要预留多大空间,主要有两方面因素:
- 取决于系统硬件架构,可以使用uname -m命令查看。
- 取决于系统总的内存大小。
在大多数系统中,kdump服务默认下会自动评估需要预留的内存大小,前提是系统总大小要满足一定条件。
上面那个页面点击进去之后,可看到:
默认自动分配了160M(根据我当前主存4GB来确定的),也可以勾选"Manul",然后手动修改预留给kdump服务的内存大小,不建议改太大,因为预留的这部分内存系统不能再使用了,意味着系统可用内存变小。
在centos7/RHEL7上,默认已经安装及配置了kdump服务,可以查看系统启动参数:
其中,说明系统自动分配预留给kdump内存大小。
修改系统启动参数中crashkernel参数,在/boot/grub2/grub.cfg文件中,找到menuentry中当前内核启动参数那行:
如果没有crashkernel参数,则在该行参数中加入:
修改完后,重启系统会生效。
注:在rhel6.x 5.x上配置文件路径可能会有所不同,找到grub.conf文件修改即可。
内核crash转储文件可以存储在本地磁盘上,也可以使用nfs或者ssh协议通过网络发送到其它地方。
/etc/kdump.conf配置文件可以配置很多选项,比如配置dump转储文件存放位置、是否压缩dump文件数据、当kdump失败后的行为等待。详细可以查看该文件注释:
移到最下面,可以看到默认配置:
可以看到,vmcore默认路径是在,可以修改该路径,之后重启kdump服务生效
使用如下命令简单快速测试:
如果Kdump配置正确,上述命令会让系统快速重启并且启动捕获内核进行转储,转储完成后会自动切换为生产内核,待系统重启完成后,登录系统,可以查看到 /var/crash目录下,已经有vmcore dump文件生成,文件可以查看到崩溃时系统日志信息:
Crash是一个用于分析内核转储文件的工具,和Kdump配套使用。Kdump会在内存中保留一块区域,这个区域用于存放捕获内核,生产内核运行过程中崩溃时,Kdump通过Kexec机制自动启动捕获内核,对生产内核的完整信息(CPU寄存器、栈帧数据等)进行保存,生产内核重启后,使用Crash工具来分析这个转储的文件。
使用crash工具分析vmcore,需要:
- crash工具
- 崩溃转储文件(vmcore)
- 发生崩溃的内核映像文件(vmlinux),包含调试内核所需调试信息
一般系统在安装后在/boot目录下,也有个内核映像文件,vmlinuxz开头的文件,但是它是压缩过后的,无法完成调试工作,如下图:
所以我们需要下载带有完整调试信息的内核映像文件(编译时带-g选项),内核调试信息包kernel-debuginfo有两个:
- kernel-debuginfo
- kernel-debuginfo-common
对于centos系统,可以在上下载到各发行版本所需的调试包。
对于centos7.x,安装对应内核版本的内核调试包,执行如下即可:
注意:如果系统为centos6.x,则将后面的7改成6即可。
对于oracle linux系统,可以在上下载内核调试包
下载完后,安装内核调试包:
安装完成后,可以在安装的文件中找到vmlinux内核映像文件:
若没有安装过crash,则执行以下命令安装:
分析vmcore文件,执行命令:
其中下面这些信息,就是导致系统崩溃的直接原因及进程相关信息:
help命令用于在线查看crash命令的帮助,在crash命令行中输入help命令可以查看crash支持的所有子命令。
help命令不仅可以查看crash支持的命令,还可以查看某个子命令的帮助说明,如查看bt命令的帮助说明。
bt命令查看一个进程的内核栈的函数调用关系,包括所有异常栈的信息,常用参数如下。
- -f:显示每一栈帧里的数据。
- -l:显示文件名和行号。
- -t:显示栈中所有的文本符号。
- pid:显示指定pid的进程的内核栈的函数调用信息。
上图可以看到,bt命令将系统崩溃瞬间正在运行的进程内核栈信息全部显示出来。当前进程的id是31407,task_struct数据结构的地址是0xffff961ff63cb180,当前进程运行在CPU2上,当前进程的运行命令是bash。后面的栈帧列出了该进程在内核态的调用关系,执行顺序是自下而上。
mod命令不仅可以用来显示当前系统加载的内核模块信息,还可以用来加载某个内核模块的符号信息和调试信息等,常用参数如下。
- -s:加载某个内核模块的符号信息。
- -S:从某个指定目录加载所有内核模块的符号信息,默认目录是/lib/modules/<release>目录查找并加载内核模块的符号信息。
- -d:删除某个内核模块的符号信息。
dis命令用来输出反汇编结果,常用参数如下。
- -l:显示反汇编和对应源代码的行号。
- -r:(反向)显示从例程开始到指定地址(包括指定地址)的所有指令。
- -s:显示对应的源代码。
如输出sysrq_handle_crash+22的反汇编结果。
dis -l (function+offset) 10 反汇编出指令所在代码开始,10行代码
这里能看出执行movb $0x1,0x0时系统崩溃。
rd命令用来读取内存地址中的值,常用参数如下。
- -a:显示ASCII。
- -d:显示十进制。
- -p:读取物理地址。
- -s:显示符号。
- -32:显示32位宽的值。
- -64:显示64位宽的值。
struct命令用于显示内核中数据结构的定义或者具体的值,常用的参数如下。
- struct_name:数据结构的名称。
- .member:数据结构的某个成员。
- -o:显示成员在数据结构中的偏移量。
以下命令用于显示task_struct数据结构的定义。
irq命令用于显示中断的相关信息,常用参数如下。
- index:显示某个指定IRQ的信息。
- -a:显示中断的亲和性。
- -b:显示中断的下半部信息。
- -s:显示系统中断信息。
vm命令用于显示进程地址空间的相关信息,常用参数如下。
- -p:显示虚拟地址和物理地址。
- -m:显示mm_struct数据结构。
- -v:显示进程中所有vma(vm_area_struct)数据结构的值。
- -R:搜索特定字符串或者数值。
kmem命令用来显示系统内存信息,常用参数如下。
- -g:显示page数据结构里flagsde标志位。
- -i:显示系统内存使用情况。
- -p:显示每个页面的使用情况。
- -s:显示slab使用情况。
- -v:显示vmalloc使用情况。
- -z:显示没个zone使用情况。
- -V:显示系统vm_stat情况。
task命令用于显示进程的task_struct数据结构和thread_info数据结构的内容。以下命令用于显示task_struct数据结构信息,其中-x表示以十六进制显示。
sym命令用于解析内核符号信息,常用选项如下所示。
- -l:显示所有符号信息。
- -m:显示某个内核模块的所有符号信息。
- -q:查询符号信息。
list命令用来遍历链表,并且可以输出链表成员的值,常用的参数如下。
- -h:指定链表头的地址。
- -s:用来输出链表成员的值。
如果我们确定是某个内核模块导致的问题,可以反汇编出该模块的源代码:
然后vim查看my_lkm.S文件,查看对应的源码
主机 I/O 请求没有正常结束导致系统重启
版权声明:
本文来源网络,所有图片文章版权属于原作者,如有侵权,联系删除。
本文网址:https://www.mushiming.com/mjsbk/10466.html