内核崩溃现场错误记录机制分析

对于包括openEuler在内的Linux Kernel,在发生内核崩溃等严重错误或硬件故障场景,开发人员通常需要通过内核报错日志来进行定位问题。默认的调试信息会通过串口打印输出,但对于更多数场景下无法保证接入串口或串口服务器,在此场景下缺乏有效的故障现场信息而难以定位。

该场景下有什么机制能提供定位能力?如何根据自身场景进行各机制的选择和配置。

2 个赞

下面根据个人对于系统“临终遗言”的经验进行一些分享,欢迎各位专家协助参与讨论。
首先直接上结论:1) 重量级:Kdump ;2) 轻量级:pstore;

[WIP] 先开个坑,这里先写思路,大晚上凭印象写的,慢慢整理修订更新,预计周末更新 ,可以踢我催更。:blush:

Kdump 通过kexec启动crashkernel来记录故障现场,生成类似Coredump的vmcore文件,可通过crashkernel转储到硬盘、网络存储中。通过crash工具可调试vmcore文件,操作类似gdb调试Coredump。
社区SIG也发布了kdump讲解:01-Kdump的工作原理与操作_哔哩哔哩_bilibili

Kdump的优势

  1. 记录非常齐全,每个Core的每个栈帧都能清晰记录,内核的全局变量、内存快照亦能记录。

Kdump的劣势是

  1. 依赖kexec功能,linux早期版本只有x86支持。
  2. crash kernel中硬件状态未知,存储、网卡驱动可能初始化失败导致无法转储。
  3. 慢,大概10s+,不过快慢是相对的。在嵌入式场景由于外部看门狗电路的存在,通常需要在秒级完成处理。
  4. 大,需要存储中额外保存crashkernel+initramfs,对于基于Flash嵌入式设备存储容量非常不友好。

Pstore
Pstore是一个内核崩溃转储框架,可只记录关键信息。提供不同的前端(记哪些,如dmesg、pmsg、console、ftrace)和不同的后端(记到哪,如ramoops、mtdoops、blk等)选项能力,可根据场景进行选择。
前端选择:根据需要,一般dmesg就够了,研发调试的话可以选用ftrace
后端选择:

  1. ramoops 以内存为后端设备,若CPU SOC支持保留内存(热复位不丢失),则该为最优选项,记录又快(写内存的开销),容量又大(MB级别轻松驾驭),不过需要重启后手动(写启机脚本)转储到硬盘等持久化存储中。
  2. mtdoops 对于嵌入式设备通常用Flash(norflash、nandflash)作为持久化存储设备,可以通过该后端直接写入预留的MTD分区位置。
    注意这里有两个自研优化点:1、Flash器件特性需要Block先擦后写,比较慢,时间敏感的场景可以启机先擦完,崩溃时直接写。2、panic故障时,会需在中断上下文(IRQ/NMI)中处理,需支持控制器同步写MTD能力。
    另外,kmsg_dump的时候会有一个dump reason属性,例如PANIC/OOPS/EMERG,对于sysrq触发的典型场景,PANIC/OOPS/EMERG都会触发记录一遍,但内容大部分是重复的,造成空间浪费,可以mask掉一些reason,或者合并记录。
  3. blk 这个后端支持直接记录到硬盘中
    但现在仍存在一个问题:不支持中断上下文中记录,原因是gendisk那套是异步IO,各个存储器件驱动(SSD、emmc等)也需要中断来完成IO请求。当硬件故障或系统BUG触发在中断上下文panic则无能为力了。
  4. erst 这个是ACPI协议规定的APEI功能里的一个能力,通常用于记录硬件故障信息,ACPI没有强制规定记录的内容,我们可以用来记录OS Kernel崩溃日志,一般保存在BIOS的Norflash里。
    这个要看下BIOS APEI支持的actions,有部分BIOS不支持erst能力。另外实测部分商用BIOS有BUG特定场景会功能失效(晚点整理下)。
    另外,kmsg_bytes(CONFIG_PSTORE_DEFAULT_KMSG_BYTES)这个配置的实现写的有问题,实际会比配的多出一个dump_size,见pstore_dump函数while (total < kmsg_bytes)循环。
4 个赞

写的很好 :rainbow: