nmi_watchdog:Softlockup 与 hardlockup 检测机制



什么是 lockup
lockup 就是某段内核代码占着CPU不放, lockup 严重时导致整个系统失去响应。lockup 有两个特点:
只有内核代码才能引起 lockup,因为用户代码是可被抢占的,不可能形成lockup(只有一个例外: SCHED_FIFO 优先级为99的实时进程也是不可抢占的);
内核代码必须处于禁止抢占状态,因为 Linux 是抢占式内核,只有某些特定代码区才禁止抢占,只有这些区域才能形成lockup。
lockup分为soft lockup和hard lockup。如果 lockup 时没屏蔽中断 soft,否则hard。
NMI watchdog
Softlockup 是一种会引发系统在内核态中一直循环超过20秒(详见下面“实现”小节)导致 其他任务没有机会得到运行的BUG。一旦检测到 ’softlockup’ 发生,默认情况下系统会打印当前堆栈跟踪信息并进入锁定状态。也可配置使其在检测到 ’softlockup’ 后进入 panic  状态;通过sysctl命令设置“kernel.softlockup_panic”、使用内核启动参数 “softlockup_panic”(详见Documentation/admin-guide/kernel-parameters.rst)以及使 能内核编译选项“BOOTPARAM_SOFTLOCKUP_PANIC”都可实现这种配置。
参考:https://access.redhat.com/articles/371803
典型内核日志:
Aug 13 17:42:32 hostname kernel: BUG: soft lockup - CPU#1 stuck for 10s! [kswapd1:982]Aug 13 17:42:32 hostname kernel: CPU 1:Aug 13 17:42:32 hostname kernel: Modules linked in: mptctl mptbase sg ipmi_si(U) ipmi_devintf(U) ipmi_msghandler(U) nfsd exportfs auth_rpcgss autofs4 nfs fscache nfs_acl hidp l2cap bluetooth lockd sunrpc bonding ipv6 xfrm_nalgo crypto_api dm_multipath scsi_dh video hwmon backlight sbs i2c_ec i2c_core button battery asus_acpi acpi_memhotplug ac parport_pc lp parport shpchp hpilo bnx2(U) serio_raw pcspkr dm_raid45 dm_message dm_region_hash dm_mem_cache dm_snapshot dm_zero dm_mirror dm_log dm_mod usb_storage cciss(U) sd_mod scsi_mod ext3 jbd uhci_hcd ohci_hcd ehci_hcdAug 13 17:42:32 hostname kernel: Pid: 982, comm: kswapd1 Tainted: G 2.6.18-164.el5 #1Aug 13 17:42:32 hostname kernel: RIP: 0010:[<ffffffff80064bcc>] [<ffffffff80064bcc>] .text.lock.spinlock+0x2/0x30Aug 13 17:42:32 hostname kernel: RSP: 0018:ffff81101f63fd38 EFLAGS: 00000282Aug 13 17:42:32 hostname kernel: RAX: ffff81101f63fd50 RBX: 0000000000000000 RCX: 000000000076d3baAug 13 17:42:32 hostname kernel: RDX: 0000000000000000 RSI: 00000000000000d0 RDI: ffffffff88442e30Aug 13 17:42:32 hostname kernel: RBP: ffffffff800c9241 R08: 0000000000193dbf R09: ffff81068a77cbb0Aug 13 17:42:32 hostname kernel: R10: 0000000000000064 R11: 0000000000000282 R12: ffff810820001f80Aug 13 17:42:32 hostname kernel: R13: ffffffff800480be R14: 000000000000000e R15: 0000000000000002Aug 13 17:42:32 hostname kernel: FS: 0000000000000000(0000) GS:ffff81101ff81a40(0000) knlGS:0000000000000000Aug 13 17:42:32 hostname kernel: CS: 0010 DS: 0018 ES: 0018 CR0: 000000008005003bAug 13 17:42:32 hostname kernel: CR2: 00000000076fc460 CR3: 0000000000201000 CR4: 00000000000006e0Aug 13 17:42:32 hostname kernel:Aug 13 17:42:32 hostname kernel: Call Trace:Aug 13 17:42:32 hostname kernel: [<ffffffff8840933a>] :nfs:nfs_access_cache_shrinker+0x2d/0x1daAug 13 17:42:32 hostname kernel: [<ffffffff8003f349>] shrink_slab+0x60/0x153Aug 13 17:42:32 hostname kernel: [<ffffffff80057db5>] kswapd+0x343/0x46cAug 13 17:42:32 hostname kernel: [<ffffffff8009f6c1>] autoremove_wake_function+0x0/0x2eAug 13 17:42:32 hostname kernel: [<ffffffff80057a72>] kswapd+0x0/0x46cAug 13 17:42:32 hostname kernel: [<ffffffff8009f4a9>] keventd_create_kthread+0x0/0xc4Aug 13 17:42:32 hostname kernel: [<ffffffff8003298b>] kthread+0xfe/0x132Aug 13 17:42:32 hostname kernel: [<ffffffff8009c33e>] request_module+0x0/0x14dAug 13 17:42:32 hostname kernel: [<ffffffff8005dfb1>] child_rip+0xa/0x11Aug 13 17:42:32 hostname kernel: [<ffffffff8009f4a9>] keventd_create_kthread+0x0/0xc4Aug 13 17:42:32 hostname kernel: [<ffffffff8003288d>] kthread+0x0/0x132Aug 13 17:42:32 hostname kernel: [<ffffffff8005dfa7>] child_rip+0x0/0x11
softlockup_panic
当检测到软锁定时,控制内核是否 panic。
取值
说明
0
内核在软锁定时不 panic
1 内核在软锁定时 panic

在 RHEL 7 和 8 上,softlockup_panic 的默认值是0。
#临时修改sudo sysctl -w kernel.softlockup_panic=0echo 0 > /proc/sys/kernel/softlockup_panic#永久修改echo "kernel.softlockup_panic=0" >> /etc/sysctl.conf && sudo sysctl -p
而 ’hardlockup’ 是一种会引发系统在内核态一直循环超过10秒钟(详见”实现”小节)导致其 他中断没有机会运行的缺陷。与 ’softlockup’ 情况类似,除了使用sysctl命令设置 ‘hardlockup_panic’、使能内核选项“BOOTPARAM_HARDLOCKUP_PANIC”以及使用内核参数 “nmi_watchdog”(详见:”The kernel’s command-line parameters“ - https://www.kernel.org/doc/html/v5.15/admin-guide/kernel-parameters.html)外,一旦检 测到 ’hardlockup’ 默认情况下系统打印当前堆栈跟踪信息,然后进入锁定状态。
这个 panic 选项也可以与 panic_timeout 结合使用(这个panic_timeout是通过稍具迷惑性的 sysctl命令”kernel.panic”来设置),使系统在panic指定时间后自动重启。
hardlockup_panic
当检测到硬锁定时,控制内核是否 panic。
取值 说明
0
内核在硬锁定时不会 panic
1 硬锁定中的内核 panic

实现
Softlockup 和 hardlockup 分别建立在 hrtimer (高精度定时器)和 perf 两个子系统上而实现。这也就意味着理论上任何架构只要实现了这两个子系统就支持这两种检测机制。
Hrtimer 用于周期性产生中断并唤醒watchdog线程;NMI perf事件则以”watchdog_thresh“ (编译时默认初始化为10秒,也可通过”watchdog_thresh“这个sysctl接口来进行配置修改) 为间隔周期产生以检测 hardlockups。如果一个CPU在这个时间段内没有检测到hrtimer中 断发生,’hardlockup 检测器’(即NMI perf事件处理函数)将会视系统配置而选择产生内核 警告或者直接panic。
而 watchdog 线程本质上是一个高优先级内核线程,每调度一次就对时间戳进行一次更新。如果时间戳在 2*watchdog_thresh (这个是 softlockup 的触发门限)这段时间都未更新,那么 “softlocup 检测器”(内部hrtimer定时器回调函数)会将相关的调试信息打印到系统日志中, 然后如果系统配置了进入panic流程则进入panic,否则内核继续执行。
Hrtimer 定时器的周期是2*watchdog_thresh/5,也就是说在 hardlockup 被触发前 hrtimer 有 2~3次机会产生时钟中断。
如上所述,内核相当于为系统管理员提供了一个可调节hrtimer定时器和perf事件周期长度 的调节旋钮。如何通过这个旋钮为特定使用场景配置一个合理的周期值要对lockups检测的 响应速度和lockups检测开销这二者之间进行权衡。
默认情况下所有在线cpu上都会运行一个watchdog线程。不过在内核配置了”NO_HZ_FULL“的 情况下watchdog线程默认只会运行在管家(housekeeping)cpu上,而”nohz_full“启动参数指 定的cpu上则不会有watchdog线程运行。试想,如果我们允许watchdog线程在”nohz_full“指 定的cpu上运行,这些cpu上必须得运行时钟定时器来激发watchdog线程调度;这样一来就会 使”nohz_full“保护用户程序免受内核干扰的功能失效。当然,副作用就是”nohz_full“指定 的cpu即使在内核产生了lockup问题我们也无法检测到。不过,至少我们可以允许watchdog 线程在管家(non-tickless)核上继续运行以便我们能继续正常地监测这些 cpu 上的 lockups 事件。
不论哪种情况都可以通过sysctl命令kernel.watchdog_cpumask来对没有运行watchdog线程 的cpu集合进行调节。对于nohz_full而言,如果nohz_full cpu上有异常挂住的情况,通过 这种方式打开这些cpu上的watchdog进行调试可能会有所作用。
nmi_watchdog
控制 x86 系统上的硬锁定检测器。
取值
说明
0
禁用锁定检测器
1
启用锁定检测器

硬锁定检测器会监控每个 CPU 是否有响应中断的能力.
watchdog_thresh
控制 watchdog hrtimer、NMI 事件和软/硬锁定阈值的频率。
默认阈值
软锁定阈值
10秒 2*watchdog_thresh

相关内核参数
sysctl -a --pattern watchdogkernel.nmi_watchdog = 1kernel.watchdog = 1kernel.watchdog_cpumask = 0-271kernel.watchdog_thresh = 10sysctl -a --pattern lockupkernel.hardlockup_all_cpu_backtrace = 0kernel.hardlockup_panic = 1kernel.softlockup_all_cpu_backtrace = 0kernel.softlockup_panic = 0
参考
https://www.kernel.org/doc/html/v5.15/translations/zh_CN/admin-guide/lockup-watchdogs.html
https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/kernel_administration_guide/working_with_sysctl_and_kernel_tunables#what_tunables_can_be_controlled
https://access.redhat.com/documentation/zh-cn/red_hat_enterprise_linux/9/html/managing_monitoring_and_updating_the_kernel/parameters-controlling-kernel-panic_keeping-kernel-panic-parameters-disabled-in-virtualized-environments
到顶部