Softlockup 检测器和 Hardlockup 检测器 (又名 nmi_watchdog)

Linux 内核可以充当看门狗,以检测软锁定和硬锁定。

“软锁定 (softlockup)” 定义为导致内核在内核模式下循环超过 20 秒(有关详细信息,请参阅下面的“实现”),而没有给其他任务运行机会的错误。检测到时会显示当前堆栈跟踪,默认情况下,系统将保持锁定状态。或者,可以将内核配置为 panic;为此提供了 sysctl “kernel.softlockup_panic”、内核参数 “softlockup_panic”(有关详细信息,请参阅“内核的命令行参数”)和一个编译选项 “BOOTPARAM_SOFTLOCKUP_PANIC”。

“硬锁定 (hardlockup)” 定义为导致 CPU 在内核模式下循环超过 10 秒(有关详细信息,请参阅下面的“实现”),而没有让其他中断有机会运行的错误。与软锁定的情况类似,检测到时会显示当前堆栈跟踪,并且系统将保持锁定状态,除非更改了默认行为,这可以通过 sysctl “hardlockup_panic”、编译时旋钮 “BOOTPARAM_HARDLOCKUP_PANIC” 和内核参数 “nmi_watchdog” 来完成(有关详细信息,请参阅“内核的命令行参数”)。

panic 选项可以与 panic_timeout 结合使用(此超时通过名称令人困惑的 “kernel.panic” sysctl 设置),以使系统在指定的时间后自动重启。

实现

软锁定和硬锁定检测器分别构建在 hrtimer 和 perf 子系统之上。 这样做的直接结果是,原则上,它们应在存在这些子系统的任何体系结构中工作。

一个周期性的 hrtimer 运行以生成中断并启动看门狗作业。 每 “watchdog_thresh”(编译时初始化为 10,可通过同名 sysctl 配置)秒生成一个 NMI perf 事件,以检查硬锁定。 如果系统中任何 CPU 在该时间内未收到任何 hrtimer 中断,则“硬锁定检测器”(NMI perf 事件的处理程序)将生成内核警告或调用 panic,具体取决于配置。

看门狗作业在一个停止调度的线程中运行,该线程在每次调度时更新时间戳。 如果该时间戳在 2*watchdog_thresh 秒(软锁定阈值)内未更新,则“软锁定检测器”(在 hrtimer 回调函数中编码)会将有用的调试信息转储到系统日志,之后,如果指示这样做,它将调用 panic,否则将恢复执行其他内核代码。

hrtimer 的周期为 2*watchdog_thresh/5,这意味着它有两到三次机会在硬锁定检测器启动之前生成中断。

如上所述,提供了一个内核旋钮,允许管理员配置 hrtimer 和 perf 事件的周期。 特定环境的正确值是在对锁定的快速响应和检测开销之间的权衡。

默认情况下,看门狗在所有在线核心上运行。 但是,在配置了 NO_HZ_FULL 的内核上,默认情况下,看门狗仅在内务处理核心上运行,而不在 “nohz_full” 启动参数中指定的核心上运行。 如果我们允许看门狗默认在 “nohz_full” 核心上运行,我们将必须运行定时器滴答来激活调度程序,这将阻止 “nohz_full” 功能保护这些核心上的用户代码免受内核的影响。 当然,默认情况下在 nohz_full 核心上禁用它意味着当这些核心进入内核时,默认情况下我们将无法检测到它们是否锁定。 但是,允许看门狗继续在内务处理(非无滴答)核心上运行意味着我们将继续在这些核心上正确检测到锁定。

在任何一种情况下,都可以通过 kernel.watchdog_cpumask sysctl 调整从运行看门狗中排除的核心集。 对于 nohz_full 核心,这对于调试内核似乎挂在 nohz_full 核心上的情况可能很有用。