linux kdump_使用Kdump检查Linux内核崩溃

linux kdump

Kdump是获取崩溃的Linux内核转储的一种方法,但是要找到说明其用法和内部结构的文档可能会很困难。 在本文中,我将研究kdump使用的基础知识,并研究kdump / kexec内核实现的内部。

Kexec是Linux内核到内核的引导加载程序,可帮助从第一个内核的上下文引导第二个内核。 Kexec关闭第一个内核,绕过BIOS或固件阶段,然后跳转到第二个内核。 因此,在没有BIOS阶段的情况下,重新引导变得更快。

Kdump可以与kexec应用程序一起使用-例如,当第一个内核崩溃时引导第二个内核时,第二个内核用于复制第一个内核的内存转储,可以使用gdb和崩溃等工具分析该转储。确定恐慌的原因。 (在本文中,我将使用术语“ 第一内核 ”表示当前正在运行的内核,使用“ 第二内核”表示使用kexec运行的内核,并在当前内核出现紧急情况时捕获用于内核运行的内核。)

kexec机制在内核以及用户空间中具有组件。 内核为kexec重启功能提供了很少的系统调用。 一个名为kexec-tools的用户空间工具使用这些调用,并提供一个可执行文件来加载和引导第二个内核。 有时,发行版还会在kexec-tools之上添加包装器,这有助于捕获并保存各种转储目标配置的转储。 在本文中,我将使用名称distro-kexec-tools来避免上游kexec-tools和特定于发行版的kexec-tools代码之间的混淆。 我的示例将使用Fedora Linux发行版。

Fedora kexec工具

dnf install kexec- tools在Fedora机器上安装fedora-kexec-tools。 可以在安装fedora-kexec-tools之后执行systemctl start kdump来启动kdump服务。 启动此服务时,它将创建一个根文件系统(initramfs),该文件系统包含用于装载目标以保存vmcore的资源,以及一个将vmcore复制/转储到目标的命令。 然后,此服务将内核和initramfs加载到崩溃内核区域内的适当位置,以便可以在内核崩溃时执行它们。

Fedora包装器提供了两个用户配置文件:

  1. /etc/kdump.conf指定配置参数,其修改要求重新构造initramfs。 例如,如果将转储目标从本地磁盘更改为安装NFS的磁盘,则捕获内核将需要加载与NFS相关的内核模块。
  2. / etc / sysconfig / kdump指定不需要修改initramfs的配置参数。 例如,如果只需要修改传递给捕获内核的命令行参数,则无需重建initramfs。

如果在启动kdump服务后内核出现紧急情况,则将执行捕获内核,该内核将进一步从initramfs执行vmcore保存过程,然后重新启动到稳定的内核。

kexec工具

kexec-tools源代码的编译提供了一个称为kexec的可执行文件。 相同的可执行文件可用于加载和执行第二个内核,或加载捕获内核,可在内核出现紧急情况时执行。

加载第二个内核的典型命令:


# kexec -l kernel.img --initrd=initramfs-image.img –reuse-cmdline

--reuse-command line表示使用与第一个内核相同的命令行。 使用--initrd传递initramfs。 -l表示您正在加载第二个内核,该内核可以由kexec应用程序本身( kexec -e )执行。 使用-l加载的内核无法在内核崩溃时执行。 您必须传递-p而不是-l来加载可在内核崩溃时执行的捕获内核。

加载捕获内核的典型命令:


# kexec -p kernel.img --initrd=initramfs-image.img –reuse-cmdline

echo c> / pros / sysrq-trigger可用于崩溃内核以进行测试。 有关kexec-tools提供的选项的详细信息,请参见man kexec 。 在转到关注内部实现的下一部分之前,请观看以下kexec_dump演示:

Kdump:端到端流程

图1显示了流程图。 在第一个内核启动期间,必须为捕获内核保留Crashkernel内存。 您可以在内核命令行中传递crashkernel = Y @ X ,其中@X是可选的。 crashkernel = 256M可用于大多数x86_64系统; 但是,为崩溃内核选择合适的内存量取决于许多因素,例如内核大小和initramfs,以及initramfs中包含的模块和应用程序的运行时内存要求。 有关传递崩溃内核参数的更多方法,请参见内核参数文档

pratyush_f1.png

您可以将内核和initramfs映像传递到kexec可执行文件,如本节的典型命令( kexec-tools )所示。 捕获内核可以与第一个内核相同或不同。 通常,保持不变。 Initramfs是可选的; 例如,当内核使用CONFIG_INITRAMFS_SOURCE编译时,则不需要它。 通常,您保留与第一个initramfs不同的捕获initramfs,因为自动执行捕获initramfs中的vmcore副本会更好。 当执行kexec时 ,它还会加载elfcorehdr数据和炼狱可执行文件。 elfcorehdr具有有关系统RAM存储器组织的信息,炼狱是在捕获内核执行并验证第二阶段二进制文件/数据具有正确的SHA之前执行的二进制文件。 炼狱也可以设为可选。

当第一个内核崩溃时,它会执行最少的必要退出过程,如果存在则切换到炼狱。 炼狱验证加载的二进制文件的SHA256,如果正确,则将控制权传递给捕获内核。 捕获内核根据从elfcorehdr接收到的系统RAM信息创建vmcore。 因此,捕获内核启动后,您将在/ proc / vmcore中看到第一个内核的转储。 现在,根据您使用的initramfs,您可以分析转储,将其复制到任何磁盘,或者可以有自动复制,然后重新启动到稳定的内核。

内核系统调用

内核提供了两个系统调用,即kexec_load()kexec_file_load() ,当执行kexec -l时可用于加载第二个内核。 它还为reboot()系统调用提供了一个额外的标志,可以使用kexec -e引导它进入第二个内核。

kexec_load()kexec_load()系统调用会加载一个新内核,稍后可通过reboot()执行该内核。 其原型定义如下:


long kexec_load(unsigned long entry, unsigned long nr_segments,
struct kexec_segment *segments, unsigned long flags);

用户空间需要传递用于不同组件(例如内核,initramfs等)的段。因此, kexec可执行文件有助于准备这些段。 kexec_segment的结构如下所示:


struct kexec_segment {
	void *buf;
	/* Buffer in user space */
	size_t bufsz;
	/* Buffer length in user space */
	void *mem;
	/* Physical address of kernel */
	size_t memsz;
	/* Physical address length */
};

当使用LINUX_REBOOT_CMD_KEXEC调用reboot()时 ,它将引导到kexec_load()加载的内核中。 如果将标志KEXEC_ON_CRASH传递给kexec_load() ,则将不会通过reboot(LINUX_REBOOT_CMD_KEXEC)执行加载的内核。 而是在内核崩溃时执行。 必须将CONFIG_KEXEC定义为使用kexec,并且应为kdump定义CONFIG_CRASH_DUMP

kexec_file_load() :作为用户,您仅将两个参数(即内核和initramfs)传递给kexec可执行文件。 然后, kexec从sysfs或其他内核信息源读取数据并创建所有段。 因此, kexec_file_load()简化了用户空间,您仅在其中传递内核和initramfs的文件描述符。 所有段准备工作的其余部分都由内核本身完成。 应该启用CONFIG_KEXEC_FILE以使用此系统调用。 其原型如下:


long kexec_file_load(int kernel_fd, int initrd_fd, unsigned long
cmdline_len, const char __user * cmdline_ptr, unsigned long
flags);

请注意, kexec_file_load()也接受命令行,而kexec_load()不接受。 内核具有不同的体系结构特定的方式来接受命令行。 因此,在使用kexec_load()的情况下, kexec-tools会将命令行通过段之一(如dtbELF引导说明等) 传递

当前,仅x86和PowerPC支持kexec_file_load()

内核崩溃时会发生什么

当第一个内核崩溃时,在将控制权传递给炼狱或捕获内核之前,它会执行以下操作:

  • 准备CPU寄存器(请参阅内核代码中的crash_setup_regs() );
  • 更新vmcoreinfo注释(请参阅crash_save_vmcoreinfo() );
  • 关闭非崩溃的CPU并保存准备好的寄存器(请参见machine_crash_shutdown()crash_save_cpu() );
  • 您可能还需要在此处禁用中断控制器;
  • 最后,它执行kexec重启(请参阅machine_kexec() ),该重启将kexec段加载/刷新到内存,并将控制权交给入口段的执行。 入口段可以是炼狱或下一个内核的起始地址。

ELF程序头

kdump中涉及的大多数转储核心都是ELF格式。 因此,了解ELF程序标头很重要,尤其是在您要查找vmcore准备问题时。 每个ELF文件都有一个程序头,该头是:

  • 由系统加载程序读取,
  • 描述了程序应如何加载到内存中,
  • 可以使用Objdump -p elf_file查找程序头。

vmcore的ELF程序标头示例:


# objdump -p vmcore
vmcore:
file format elf64-littleaarch64
Program Header:
NOTE off 0x0000000000010000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**0 filesz
0x00000000000013e8 memsz 0x00000000000013e8 flags ---
LOAD off 0x0000000000020000 vaddr 0xffff000008080000 paddr 0x0000004000280000 align 2**0 filesz
0x0000000001460000 memsz 0x0000000001460000 flags rwx
LOAD off 0x0000000001480000 vaddr 0xffff800000200000 paddr 0x0000004000200000 align 2**0 filesz
0x000000007fc00000 memsz 0x000000007fc00000 flags rwx
LOAD off 0x0000000081080000 vaddr 0xffff8000ffe00000 paddr 0x00000040ffe00000 align 2**0 filesz
0x00000002fa7a0000 memsz 0x00000002fa7a0000 flags rwx
LOAD off 0x000000037b820000 vaddr 0xffff8003fa9e0000 paddr 0x00000043fa9e0000 align 2**0 filesz
0x0000000004fc0000 memsz 0x0000000004fc0000 flags rwx
LOAD off 0x00000003807e0000 vaddr 0xffff8003ff9b0000 paddr 0x00000043ff9b0000 align 2**0 filesz
0x0000000000010000 memsz 0x0000000000010000 flags rwx
LOAD off 0x00000003807f0000 vaddr 0xffff8003ff9f0000 paddr 0x00000043ff9f0000 align 2**0 filesz
0x0000000000610000 memsz 0x0000000000610000 flags rwx

在此示例中,有一个注释部分,其余为加载部分。 注释部分包含有关CPU注释的信息,加载部分包含有关复制的系统RAM组件的信息。

Vmcore以elfcorehdr开头 ,其结构与ELF程序标头相同。 请参见图2中的elfcorehdr表示:

pratyush_f2.png

kexec-tools读取/ sys / devices / system / cpu / cpu%d / crash_notes并为CPU PT_NOTE准备标头。 同样,它读取/ sys / kernel / vmcoreinfo并为vmcoreinfo PT_NOTE准备头,并从/ proc / iomem读取系统RAM值并准备内存PT_LOAD头。 当捕获内核接收到elfcorehdr时 ,它将从标头中提到的地址追加数据并准备vmcore。

崩溃提示

崩溃注解是每个CPU的区域,用于在系统崩溃时存储CPU状态。 它具有有关当前PID和CPU寄存器的信息。

vmcoreinfo

此注释部分包含各种内核调试信息,例如结构大小,符号值,页面大小等。这些值由捕获内核解析并嵌入到/ proc / vmcore中vmcoreinfo主要由makedumpfile应用程序使用。 Linux内核中的include / linux / kexec.h具有定义新vmcoreinfo的宏。 一些示例宏如下所示:

  • VMCOREINFO_PAGESIZE()
  • VMCOREINFO_SYMBOL()
  • VMCOREINFO_SIZE()
  • VMCOREINFO_STRUCT_SIZE()

makedumpfile

vmcore中的许多信息(例如空闲页面)都没有用。 Makedumpfile是一个排除不必要页面的应用程序,例如:

  • 充满零的页面,
  • 缓存没有私有标志的页面(非私有缓存);
  • 缓存带有私有标志的页面(私有缓存);
  • 用户过程数据页面;
  • 免费页面。

另外,makedumpfile在复制时会压缩/ proc / vmcore数据。 它还可以从转储中删除敏感的符号信息; 但是,它首先需要内核的调试信息。 此调试信息来自VMLINUXvmcoreinfo ,其输出可以是ELF格式或kdump压缩格式。

典型用法:


# makedumpfile -l --message-level 1 -d 31 /proc/vmcore makedumpfilecore

有关详细信息,请参见man makedumpfile

调试kdump问题

新的kdump用户可能遇到的问题:

Kexec -p kernel_image没有成功

  • 检查是否分配了崩溃内存。
  • cat / sys / kernel / kexec_crash_size不应为零。
  • 猫/ proc / iomem | grep“崩溃内核”应具有分配的范围。
  • 如果未分配,则在命令行中传递适当的crashkernel =参数。
  • 如果未显示任何内容,则在kexec命令中传递-d并与kexec-tools邮件列表共享调试输出。

从第一个内核发出最后一条消息后,控制台上看不到任何内容(例如“再见”)

  • 检查kexec -l kernel_image后跟kexec -e是否有效。
  • 可能缺少特定于体系结构或计算机的选项。
  • 炼狱SHA验证可能失败。 如果您的体系结构不支持炼狱中的控制台,则很难调试。
  • 可能第二个内核提前崩溃了。
  • 将您的系统的Earlycon / earlyprintk选项传递到第二个内核命令行。
  • 与kexec-tools邮件列表共享第一个和捕获内核的dmesg日志。

资源资源

fedora-kexec工具
  • 仓库: git://pkgs.fedoraproject.org/kexec-tools
  • 邮件列表: kexec@lists.fedoraproject.org
  • 描述:Specs文件和脚本提供了用户友好的命令/服务,以便可以在不同的用户场景中自动执行kexec-tools
kexec工具
  • 仓库:git://git.kernel.org/pub/scm/utils/kernel/kexec/kexec-tools.git
  • 邮件列表: kexec@lists.infradead.org
  • 说明:使用内核系统调用并提供用户命令kexec
Linux内核
  • 仓库: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
  • 邮件列表: kexec@lists.infradead.org
  • 说明:实现kexec_load()kexec_file_load()reboot()系统调用以及特定于体系结构的代码,例如machine_kexec()machine_crash_shutdown()等。
Makedump文件
  • 仓库: git://git.code.sf.net/p/makedumpfile/code
  • 邮件列表: kexec@lists.infradead.org
  • 说明:从转储文件中压缩和过滤不必要的组件。

2017年6月20日在LinuxCon ContainerCon CloudOpen中国上的Pratyush Anand的KDUMP:使用和内部知识讲座中了解更多信息。

翻译自: https://opensource.com/article/17/6/kdump-usage-and-internals

linux kdump

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值