我有一个内核BUG,我不知道为什么会触发它。
[ 242.337362] kernel BUG at arch/x86/kernel/cpu/mce/core.c:1364!
[ 242.337366] invalid opcode: 0000 [#1] SMP NOPTI
这是 CentOS 8.5,x86_64 上的内核 4.18.0-348.el8.x86_64。
core.c 第 1364 行是:
nmi_exit();
(上一行在 do_machine_check()
内):
通过检查nmi_exit()
https://elixir.bootlin.com/linux/v4.18/source/include/linux/hardirq.h#L78
#define nmi_exit() \
do { \
trace_hardirq_exit(); \
rcu_nmi_exit(); \
BUG_ON(!in_nmi()); \
preempt_count_sub(NMI_OFFSET + HARDIRQ_OFFSET); \
ftrace_nmi_exit(); \
lockdep_on(); \
printk_nmi_exit(); \
} while (0)
看起来我遇到了这个BUG_ON(!in_nmi());
,但我检查了do_machine_check()
,它应该仍然是in_nmi
(自第 1255 行 nmi_enter();
),为什么触发了 BUG_ON(!in_nmi());
?
其他:
- 这里是CentOS 4.18内核源码下载:
https://vault.centos.org/8.5.2111/BaseOS/Source/SPackages/kernel-4.18.0-348.el8.src.rpm
最佳答案
I got a kernel BUG, I don't know why it was triggered?
您遇到的特定错误试图使用无效的操作码:0000 [#1] SMP NOPTI。
我将解决这个问题、原因以及解决问题的方法。首先,我将定义一些术语。
什么是不可屏蔽中断 (NMI)?
NMI 是一种硬件中断,不受操作系统(例如 CentOS 8.5)启用的任何中断屏蔽的影响。在几乎所有情况下,它都是对 non-recoverable hardware errors 的回应。 .
NMI 有哪些典型用途? 1
- 低级调试,例如早期 Apple Macintosh 的“程序员按钮”。
- 超出可纠正范围的 ECC 内存奇偶校验错误可能会导致系统停止运行。
- 迫在眉睫的厄运,例如突然断电使系统静止。
- 定期启用硬件看门狗计时器,以便在错过一个时出现 panic 。
第二个 NMI 是否可以在处理第一个 NMI 时到达?
从我记事起,Linux 就一直支持 Intel 嵌套 NMI。 Intel nested NMI support 中的漏洞2012 年令人兴奋。英特尔拥有 NMI iret flaw这要求 NMI 处理程序在处理 NMI 时避免触发页面错误或断点。
在 ARM64 和 PowerPC 中支持 nest NMI 已在 May 20th, 2020 上提交给 Linux .
为什么 BUG_ON() 会准确执行?
从 Linux 2.6 开始,BUG_ON() 是用于出现严重错误时的调试宏。如果传递给宏的值为真,Linux 内核将触发无效指令。这导致 CPU 抛出无效操作码异常。通常,如果在进程中发生这种情况,则该进程会死亡。如果这种情况发生在 NMI 期间,那就要严重得多。
BUG_ON(!in_nmi()) 转换为 BUG_ON(true)?
因此 in_nmi() 是检查当前 NMI 的当前抢占位是否设置为真。
什么是 NOPTI? 2
Linux 使用它来禁用 Meltdown(内核页表隔离)缓解措施。通常将 nopti 添加到内核引导选项以禁用。
补救措施?
如果是软件问题,我该怎么办? 最有可能
- 尝试在启用 Meltdown 的情况下启动系统(如果当前已禁用)。或者在禁用它的情况下启动(如果启用)。
- 如果可能,将 Linux 升级到 5.4.100 或更高版本。一个例子bug在英特尔 Icelake 发布前 2 年由英特尔报告。
- 迁移到 AlmaLinux 或 Rocky Linux,CentOS 8.5的精神继承者。
如果是硬件缺陷怎么办? 不太可能
- 尝试一次更换一个(与系统逻辑板兼容的配置),直到找到有缺陷的那个。
- 更换系统逻辑板和/或其他 PCIe 设备。
长话短说
此问题的一个工作理论是 NMI 是由未纠正的硬件内存错误和编码错误造成的情况,即在第二次增加增加了 preempt_counter 之前检查 BUG_ON(!in_nmi())。
在这种特殊情况下,原始发布者使用工具 einj_mem_uc 来生成模拟内存错误。这会启动 NMI。
关于c - 为什么会触发 BUG_ON(!in_nmi())?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73592210/