`

基于kexec的崩溃转储机制

阅读更多

设计
===

    当一个内核转储发生的时候kdump使用kexec启动一个备份 的内核 。这个备份启动的内核只是使用少量的内存,并且这些内存由第一个内核提供 。这样设计保证了第一个内核启动且正在运行中的DMA不会破坏第二个内核的运行

    在内核崩溃之前所有关于核心映像的必要信息 都用ELF 格式编码并存储在保留的内存区域中。ELF头所在的物理地址 被作为命令行参数(fcorehdr= )传递给新启动的转储内核。

    在i386体系结构上,启动的时候需要使用物理内存开始的640K ,而不管操作系统内核转载在何处。因此,这个640K的区域在重新启动第二个内核的时候由kexec备份

    在第二个内核中,“前一个系统的内存”可以通过两种方式访问:

    -     第一种方式是通过/dev/oldmem 这个设备接口。一个“捕捉”设备可以使用“raw”(裸的)方式  “读”这个设备文件并写出到文件。这是关于内存的 “裸”的数据转储,同时这些分析/捕捉工具应该足够“智能”从而可以知道从哪里可以得到正确的信息。ELF文件头(通过命令行参数传递过来的elfcorehdr )可能会有帮助。

    -    第二种方式就是通过/proc/vmcore 。这个方式是将转储输出为一个ELF格式的文件,并且可以方 便使用一些文件拷贝命令(比如cp,scp等等)将信息读出来。同时,gdb可以在得到的转储文件上做一些调试(有限的)。这种方式保证了内存中的页面都以正确的途径被保存。(注意内存开始的640K被重新映射了 )


安装/设置
=======
    1)使用root用户登录系统。
    2)下载upstream  kexec-tools 用户空间包,下载地址:
           http://www.xmission.com/~ebiederm/files/kexec/kexec-tools-1.101.tar.gz.
    3)解包:
           tar xvpzf kexec-tools-1.101.tar.gz
    4)从下列地址得到最新的kdump补丁。
           http://lse.sourceforge.net/kdump/
           如果所有关于用户空间支持kdump的补丁都已经集成到了upstream kexec-tools中那么这一步可以被省略。
    5)cd到解包得到的目录:
            cd kexec-tools-1.101
    6)使用patch命令应用补丁:
             patch -p1 < /path-to-kdump-patch/kexec-tools-1.101-kdump.patch
           (注意使用正确的补丁目录和补丁文件)
    7)配置这个包,使用如下命令:
            ./configure
    8)编译包:
            make
    9)安装这个包:
            make install


下载并构建系统内核和“转储-捕捉”内核
==============================

    下载内核主版本树上的源码(从http://www.kernel.org),注意选择合适版本的内核(高于2.6.13-rc1版本)。需要编译两个内核:一个“系统内核”和一个“转储捕捉”内核 。要使这个特性得以实现并工作需要相应的编译两个内核。

遵照以下的步骤以配置内核使用合适的kexec和kdump功能:


系统内核
-------
    1)编译内核时要确认选中了“kexec system call ”选项(在“处理器类型和功能”区域)。
            CONFIG_KEXEC=y

    2)编译内核时要确认选中了“sysfs file system support ”(在“文件系统”->“伪文件系统”区域)。这通常是默认选中的。
            CONFIG_SYSFS=y  
注 意:在“Configure standard kernel features (for small systems)”没有被使能(在“General Setup”区域)时“sysfs file system support”可能出现在“Pseudo filesystems"菜单中。在这种情况下,检查.config文件以确保sysfs被打开。可以参考:
        grep 'CONFIG_SYSFS .config

    3)在“kernel hacking”区域中选中“Compile the kernel with debug info ”:
           CONFIG_DEBUG_INFO=Y
这样就可以使编译内核的时候带上调试用的符号,转储分析工具需要一个带有调试信息的vmlinux(内核文件)来调试分析转储文件。

    4)编译内核和模块并安装之。更新启动管理器(比如grub,lilo,yaboot等等)的配置文件。

    5)引导系统内核时使用引导参数:crashkernel=Y@X
注意要使用合适的X和Y的值。Y的值表示要为第二个内核保留多少内存,X的值表示保留的内存区开始的物理 地址 。例如:crashkernel=64M@16M 告诉系统内核保留64MB内存给“转储捕捉内核”使用,这64MB内存从物理地址0x01000000开始。

         在x86和x86_64平台上,使用"crashkernel=64M@16M"
        在ppc64平台上,使用"crashkernel=128M@32M"


转储捕获内核
----------

    1)在“general setup”选项下,附加“-kdump”到“Local version” 后面。

    2)在x86平台上,在“Processor type and features”选项下使能高端内存支持:
             CONFIG_HIGHMEM64G=y
        或者:
             CONFIG_HIGHMEM4G=y

    3)在x86平台上,去掉对称多处理器的支持,在“Processor type and features”:
             CONFIG_SMP=n
(如果不小心设置成了y,那么在启动转储捕获内核的时候给内核传递:maxcpus=1 这样的命令行参数,参见“Load the Dump-capture Kernel”)

    4)在ppc64平台上,去掉NUMA的同时加上EMBEDDED支持:
             CONFIG_NUMA=n
            CONFIG_EMBEDDED=y
            CONFIG_EEH=N  for 转储捕获内核

    5)加上“kernel crash dumps”支持,位置在“Processor type and features”:
             CONFIG_CRASH_DUMP=y

    6)为“Processor type and features”->“Physical address where the kernel is loaded”设置合适的值。
注意,这个选项只可能在选中了“kernel crash dumps”选项之后出现。默认值是0x1000000(16MB)。这个值应当和上面讨论到的命令行选项“crashkernel=Y@X”中的“X” 的值相对应

         在x86和x86_64平台上,使用“CONFIG_PHYSICAL_START=0x1000000”
        在ppc64平台上,当CONFIG_CRASH_DUMP被设置了那么就会自动给这个值赋值为32MB

    7)可选择的使能“/proc/vmcore support”(在“Filesystems”->“Pseudo filesystems”选项下)。
             CONFIG_PROC_VMCORE=y
            (CONFIG_PROC_VMCORE 是在打开“CONFIG_CRASH_DUMP”选项时自动打开的一个选项。)
   
    8)编译并安装内核和模块。但是:__不要__将这个内核加入到启动管理器可管理的内核列表中


载入“转储捕捉”内核
===============

    当引导系统内核时,使用如下步骤和命令载入“转储捕捉”内核:

        kexec -p <dump-capture-kernel> \
           --initrd=<initrd-for-dump-capture-kernel> --args-linux \
           --append="root=<root-dev> init 1 irqpoll"

关于装载“转储捕捉”内核的注意事项:

    * <转储捕捉内核>应当是一个vmlinux格式 的映像(即就是一个未压缩的ELF映像文件)而不能是bzImage格式。

    * 默认情况下,ELF文件头采用ELF64格式存储以支持那些拥有超过4GB内存的系统。但是可以指定“--elf32-core-headers”标志以 强制使用ELF32格式的ELF文件头。这个标志是有必要注意的,一个重要的原因就是:当前版本的GDB不能在一个32位系统上打开一个使用ELF64格 式的vmcore文件。ELF32格式的文件头不能使用在一个“没有物理地址扩展”(non-PAE)的系统上。(即是说,少于4GB内存的系统)

    * 一个“irqpoll”的启动参数可以减低由于在“转储捕获内核”中使用了“共享中断”技术而导致出现驱动初始化失败这种情况发生的概率。

    * 必须指定<root-dev>,指定的格式是和要使用根设备的名字。具体可以查看mount命令的输出。

    * “init 1”这个命令将启动“转储捕捉内核”到一个没有网络支持的单用户模式。如果你希望有网络支持,那么使用“init 3”。


内核失败
=======

    当使用上面提到的步骤成功地载入了“转储捕捉内核”之后,“系统崩溃”事件被触发之后系统将重启到“转储捕捉内核”。触发点将被放置到内核的“panic()”函数,“die()”函数,“die_nmi()”函数和sysrq(ALT+SysRq+c)处理句柄中

    如下所列的一些情况将会触发“系统崩溃事件”:

    如果一个硬锁定被探测到并且“NMI watchdog”配置了,那么系统将会重启到“转储捕捉内核”。(die_nmi())
    如果die()函数被调用,并且调用die()函数的线程恰好是pid为0或1;或者die()函数在一个中断处理上下文中被调用;或者die()函数被调用且“panic_on_oops”被设置了,那么系统都将重启到“转储捕捉内核”。
    在一个powerpc的系统上,当一个“软重启”产生,die()函数将在所有的cpu上被调用并且系统将重启动到“转储捕捉内核”。

    如果是为了测试,有三种方式可以采用:
         a)使用“ALT+SysRq+c ”组合键;
        b)使用如下命令:echo c > /proc/sysrq-trigger ;
        c)自己写一个内核模块强制产生“内核失败”;


读出转储文件
==========

    在“转储捕捉内核”启动完毕之后,使用如下命令以读出并保存“转储文件”:
            cp /proc/vmcore <dump-file>

    除此之外,也可以通过线性的访问/dev/oldmem这个设备从“转储的内存”中得到“裸数据”,参考如下命令:
            mknod /dev/oldmem c 1 12

    使用dd命令,加上适当的count参数,bs参数,跳到特定的产生dump的点。使用如下命令可以看到整个内存:
            dd if=/dev/oldmem of=oldmem.001


分析
===

    在开始分析“转储文件”之 ,应该确定重启到一个稳定的内核。

    可以使用GDB在“从/proc/vmcore拷贝得到的‘转储文件’”上做有限的分析。分析的时候需要“带有调试信息的vmlinux文件”(编译的时候带有-g选项),运行如下命令:
         gdb vmlinux <dump-file>
追踪处理器0上的任务的栈调用,显示寄存器,显示内存内容等可以工作的很好。

    注意:GDB不能分析x86平台上以ELF64格式产生的“内核转储文件”。在一个最大内存为4GB的系统上,可以通过在“转储捕捉内核”上指定“--elf32-core-headers”标志来使用ELF32格式的文件头。

    也可以使用Crash工具集来分析Kdump产生的“内核转储文件”。Crash可以在Dave Anderson的网站上找到,通过如下链接:
        http://people.redhat.com/~anderson/


下一步工作
========

    1)提供内核页面过滤机制,这样可以通过去掉内存中的空白页面有效的减小“内核转储文件”的大小,
   
    2)可重定位的内核可以有助于“崩溃转储”机制维护多个内核,并且“系统内核”就可以支持“捕捉转储”。


联系人
=====
    Vivek Goyal (vgoyal@in.ibm.com)
    Maneesh Soni (maneesh@in.ibm.com)

商标
===
    Linux是Linus Torvalds在美国或其他国家的一个商标。

分享到:
评论

相关推荐

    kexec_基于kexec的崩溃转储机制

    kexec工具一个内核转储发生的时候kdump使用kexec启动一个备份的内核。这个备份启动的内核只是使用少量的内存,并且这些内存由第一个内核提供。这样设计保证了第一个内核启动且正在运行中的DMA不会破坏第二个内核的...

    Linux内核崩溃转储机制

    ### Linux内核崩溃转储机制详解 #### 一、引言 在嵌入式系统开发过程中,内核崩溃是常见的问题之一。为了更好地诊断和解决这类问题,Linux提供了内核崩溃转储机制(Kernel Crash Dump Mechanism)。通过该机制可以...

    Kexec,Linux kernel dump

    - 这就是 Kexec 发挥作用的地方,它可以在当前内核崩溃后启动一个新的内核来收集旧内核的崩溃转储。 #### 三、Kexec 的工作原理 Kexec 技术允许在一个运行中的内核上加载另一个新的内核镜像。一旦准备好,可以...

    kexec-tools-2.0.9.tar.gz(测试可以编译通过)

    kdump是一种内核崩溃转储机制,当系统发生致命错误时,它可以捕获内核状态并保存到磁盘,便于后续的调试分析。kdump通常与kexec结合使用,当系统崩溃时,kexec会启动一个预先配置好的kdump内核来收集崩溃信息。 在...

    rockboot:用于Radxa Rock和其他基于rk3188的板的基于Kexec的引导程序

    RockBoot是用于rk3188板的基于kexec的引导程序,旨在提供一种替换内核的简单方法,而无需将其闪存到nand或用手将它们写入sd卡。 它由使用,并且已经过Radxa Rock Pro的测试,但是只要您具有有效的内核配置,就可以...

    前端开源库-kexec

    "kexec" 是一个专为Node.js设计的前端开源库,它的主要功能是能够在运行时用另一个进程替换当前的Node.js进程,这在某些场景下非常有用,比如实现进程间的平滑切换或更新服务。这个特性类似于Ruby中的`exec`函数,它...

    kexec-tools

    kdump是kexec-tools的一部分,它扩展了kexec的功能,可以在系统崩溃时捕获内存状态,并将其写入磁盘,生成一个崩溃转储文件。这对于调试和诊断内核问题非常有用,因为它提供了崩溃瞬间的系统状态记录。 5. **使用...

    linux 下的kdump 配置脚本

    - **kexec快速加载**:kdump利用kexec技术快速加载一个备用内核,该内核负责捕获崩溃内核的状态并将其写入转储文件。 - **内存转储**:崩溃内核将内存状态复制到预留的`crashkernel`空间,然后由新内核将这些数据...

    kexec-tools-2.0.15-21.el7.x86_64.rpm

    kexec-tools-2.0.15-21.el7.x86_64.rpm

    kexec工具

    这种机制跳过了常规的BIOS或UEFI引导流程,减少了启动时间,提高了系统的响应速度。kexec分为两种模式:kexec_load和kexec_crash。前者用于正常启动新内核,后者则是在系统崩溃时加载备用内核进行恢复。 二、kexec...

    Memory persistence across kexec

    Memory persistence across kexec

    linux core 收集和分析

    - **Kdump**: 当系统崩溃时,kdump 使用 kexec 加载一个“次级”内核,该内核负责收集转储数据。 ##### 11. Kdump 安装 **11.1 标准(生产)内核** 对于标准内核,安装 kdump 需要以下步骤: - **11.1.1 Under ...

    kexec-tools-2.0.20-63.el8.x86_64.rpm

    官方离线安装包,亲测可用。使用rpm -ivh [rpm完整包名] 进行安装

    Kexec Handover introduction

    Kexec Handover introduction

    kexec-tools-2.0.20-50.el8.aarch64.rpm

    官方离线安装包,亲测可用。使用rpm -ivh [rpm完整包名] 进行安装

    kexec-tools-2.0.15-51.el7_9.3.x86_64.rpm

    官方离线安装包,亲测可用。使用rpm -ivh [rpm完整包名] 进行安装

    kexec-tools-2.0.20-52.el8.aarch64.rpm

    官方离线安装包,亲测可用。使用rpm -ivh [rpm完整包名] 进行安装

    arm64加载kdump内核工具kexec

    arm64加载kdump内核工具kexec

    kexec-tools-2.0.20-56.el8.aarch64.rpm

    官方离线安装包,亲测可用。使用rpm -ivh [rpm完整包名] 进行安装

Global site tag (gtag.js) - Google Analytics