Linux 内核 Lockup Watchdog 深度解析:softlockup 与 hardlockup 检测原理、配置与调优

发布时间:2026/9/8 18:50:07
Linux 内核 Lockup Watchdog 深度解析:softlockup 与 hardlockup 检测原理、配置与调优 Linux 内核 Lockup Watchdog 深度解析softlockup 与 hardlockup 检测原理、配置与调优【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linuxLinux 内核自带一套看门狗机制用于自动探测两类最棘手的系统故障soft lockup内核态长时间霸占 CPU 不让出和 hard lockupCPU 长时间屏蔽中断无法响应。本文基于内核文档Documentation/admin-guide/lockup-watchdogs.rst并结合kernel/watchdog.c、kernel/watchdog_perf.c、kernel/watchdog_buddy.c等核心源码完整讲解两类锁死的定义、检测原理、watchdog_thresh阈值体系、sysctl 与内核启动参数配置、NMI/Perf 与 Buddy 两种 hardlockup 探测器的检测延迟模型以及NO_HZ_FULL场景下的看门狗核排除策略帮助你在生产系统上正确配置并快速定位 lockup 故障。什么是 softlockup 与 hardlockup内核文档对两类锁死给出了明确定义softlockup软锁死一个缺陷导致内核在内核态持续循环运行超过 20 秒默认配置下始终不给其他任务调度的机会。检测到 softlockup 时内核会打印当前栈回溯默认情况下系统会继续保持锁死状态也可以通过配置让内核直接 panic。相关的控制手段有三个sysctlkernel.softlockup_panic内核启动参数softlockup_panic详见 kernel-parameters.txt编译期配置BOOTPARAM_SOFTLOCKUP_PANIC。hardlockup硬锁死一个缺陷导致 CPU 在内核态连续循环数秒且在此期间不响应任何其他中断例如自旋锁保护下长时间禁中断且被中断本身又被禁用形成死锁。与 softlockup 类似检测到时打印栈回溯默认继续锁死但可以通过以下手段改变默认行为sysctlhardlockup_panic编译期开关BOOTPARAM_HARDLOCKUP_PANIC内核启动参数nmi_watchdog详见 kernel-parameters.txt。panic 选项可以与panic_timeout组合使用——注意该超时实际上是通过名字颇具迷惑性的kernel.panicsysctl 来设置的——从而让系统在 panic 后经过指定时间自动重启常用于无人值守设备的故障自愈场景。核心配置watchdog_thresh 阈值管理员可以通过内核提供的旋钮调整检测周期。watchdog_thresh参数默认 10 秒控制阈值。文档明确指出合适取值是快速响应锁死与检测开销之间的权衡。在源码中该变量定义于 kernel/watchdog.cint __read_mostly watchdog_thresh 10;它可以有三种方式被修改方式接口说明启动参数watchdog_threshNkernel/watchdog.c 中的__setup(watchdog_thresh, ...)运行时 sysctl/proc/sys/kernel/watchdog_thresh取值范围 0–60源码中 max 限制为 60见 kernel/watchdog.c关闭开关nowatchdog/nosoftlockup分别关闭两个/仅 softlockup 探测器见 kernel/watchdog.c修改watchdog_thresh后内核不会只改一个数字了事而是触发一次完整的探测器重配置proc_watchdog_thresh()记录新值到watchdog_thresh_next随后__lockup_detector_reconfigure(true)会停掉 hardlockup 探测器、停掉所有 CPU 的 softlockup hrtimer、更新阈值、重算采样周期再重新启动全部探测器见 kernel/watchdog.c。这样做的目的是避免 hrtimer 仍按旧周期触发、却用新阈值做判断而导致的误报。除watchdog_thresh外kernel/watchdog.c 中注册的完整 sysctl 表还包括kernel.watchdog总开关、kernel.nmi_watchdoghardlockup 探测器开关、kernel.soft_watchdogsoftlockup 探测器开关、kernel.watchdog_cpumask指定运行看门狗的 CPU 掩码、softlockup_panic/hardlockup_panic、softlockup_sys_info/hardlockup_sys_info控制锁死时额外打印哪些系统信息以及softlockup_all_cpu_backtrace/hardlockup_all_cpu_backtrace锁死时是否触发全部 CPU 回溯。其中*_sys_info掩码的位定义在 include/linux/sys_info.hSYS_INFO_TASKS(0x1)、SYS_INFO_MEM(0x2)、SYS_INFO_TIMERS(0x4)、SYS_INFO_LOCKS(0x8)、SYS_INFO_FTRACE(0x10)、SYS_INFO_PANIC_CONSOLE_REPLAY(0x20)、SYS_INFO_ALL_BT(0x40)、SYS_INFO_BLOCKED_TASKS(0x80)可按位组合例如hardlockup_sys_infotask,mem就能在锁死现场附加任务与内存信息。检测器总体架构一切围绕一个 hrtimer文档指出soft 与 hard lockup 探测器都构建在一个 hrtimer 之上此外 softlockup 探测器会定期调度一个内核作业而 hardlockup 探测器在支持的架构上可能使用 Perf/NMI 事件。这个每 CPU 的 hrtimerwatchdog_hrtimer定义于 kernel/watchdog.c承担多重职责为 softlockup 探测器调度 watchdog 作业为 hardlockup 探测器递增中断计数器即心跳heartbeat检测 softlockup在 Buddy 模式下检测 hardlockup。其触发周期为2 × watchdog_thresh / 5即默认4 秒。在 kernel/watchdog.c 中可以看到具体计算static void set_sample_period(void) { /* * convert watchdog_thresh from seconds to ns * the divide by 5 is to give hrtimer several chances (two * or three with the current relation between the soft * and hard thresholds) to increment before the * hardlockup detector generates a warning */ sample_period get_softlockup_thresh() * ((u64)NSEC_PER_SEC / NUM_SAMPLE_PERIODS); watchdog_update_hrtimer_threshold(sample_period); }其中NUM_SAMPLE_PERIODS为 5get_softlockup_thresh()返回watchdog_thresh * 2见 kernel/watchdog.c所以默认采样周期为10 * 2 / 5 4秒。除以 5 的意图是让 hrtimer 在 hardlockup 判定窗口内有多次23 次触发机会从而降低误报。Softlockup 检测器实现细节Softlockup 检测器的工作流程是watchdog 作业softlockup_fn()由 hrtimer 调度运行在 stop scheduling 线程stop machine 机制中每次被调度就更新一个时间戳watchdog_touch_ts如果该时间戳在2 × watchdog_thresh 秒softlockup 阈值内没有被更新softlockup 检测器编码在 hrtimer 回调watchdog_timer_fn()内就会向系统日志转储调试信息随后如果配置了 panic 就调用 panic否则恢复其他内核代码的执行。在 kernel/watchdog.c 中喂狗函数非常简短static int softlockup_fn(void *data) { update_touch_ts(); stop_counting_irqs(); complete(this_cpu_ptr(softlockup_completion)); return 0; }而 hrtimer 回调 watchdog_timer_fn() 是每个采样周期的核心先通过stop_one_cpu_nowait()调度softlockup_fn()完成一次喂狗然后读取watchdog_touch_ts与watchdog_report_ts判断是否锁死。判定逻辑在 is_softlockup()当now超过period_ts get_softlockup_thresh()即返回锁死持续时长。检测到 softlockup 时的日志形如源码 kernel/watchdog.cpr_emerg(BUG: soft lockup - CPU#%d stuck for %us! [%s:%d]\n, smp_processor_id(), duration, current-comm, task_pid_nr(current));随后会打印模块列表、IRQ 事件、寄存器/栈回溯show_regs()或dump_stack()置位TAINT_SOFTLOCKUP并在开启softlockup_all_cpu_backtrace时触发其他所有 CPU 的回溯。此外softlockup_panic是一个计数阈值而非简单的布尔量softlockup_panic thresh_count softlockup_panic时触发panic(softlockup: hung tasks)见 kernel/watchdog.c即允许配置连续 N 个阈值周期都锁死才 panic避免偶发抖动导致不必要的崩溃。值得注意的还有touch_softlockup_watchdog()/touch_softlockup_watchdog_sched()这两个合法喂狗接口内核中已知会长时间占用 CPU 的代码路径如某些慢速操作、调度器进入空闲状态会主动调用它们来推迟误报SOFTLOCKUP_DELAY_REPORT机制见 kernel/watchdog.c。模块开发者在写长时间禁抢占代码时也应了解这些接口以避免误触发 softlockup 告警。Hardlockup 检测器NMI/Perf 模式在支持 NMINon-Maskable Interruptperf 事件的架构上典型如 x86检测器会创建一个每 CPU 的 perf 事件周期性地产生 NMI。kernel/watchdog_perf.c 中定义的 perf 事件属性揭示了其本质——基于 unhalted CPU cycles 的固定事件static struct perf_event_attr wd_hw_attr { .type PERF_TYPE_HARDWARE, .config PERF_COUNT_HW_CPU_CYCLES, .size sizeof(struct perf_event_attr), .pinned 1, .disabled 1, };即每累计一定 CPU 周期就溢出一次通过 watchdog_overflow_callback() 最终调用watchdog_hardlockup_check()。由于基于周期计数Turbo 模式会加快 NMI 频率源码中通过watchdog_update_hrtimer_threshold()设置一个时间戳过滤取实际阈值的 4/5 作为最小 NMI 间隔来防止误报见 kernel/watchdog_perf.c。判定规则是如果某个 CPU 在watchdog_thresh窗口内没有收到任何 hrtimer 中断心跳NMI perf 事件的处理器即 hardlockup 检测器就会产生内核告警或在配置了hardlockup_panic时调用 panic。核心判定函数 is_hardlockup() 的逻辑是比较上次检查时保存的 hrtimer 中断计数与当前计数若未变化则累加hrtimer_interrupts_missed达到watchdog_hardlockup_miss_threshNMI/Perf 模式下为 1即立即判定才宣布锁死。确认锁死后watchdog_hardlockup_check() 会打印CPU%u: Watchdog detected hard LOCKUP on cpu %u打印模块列表与 IRQ 事件若锁死 CPU 就是当前执行检查的 CPU直接show_regs(regs)/dump_stack()否则调用trigger_single_cpu_backtrace(cpu)去抓取锁死 CPU 的栈这正是 NMI 检测器的独特优势——可以主动打断锁死的 CPU 取栈可选触发全部 CPU 回溯trigger_allbutcpu_cpu_backtrace若hardlockup_panic置位调用nmi_panic(regs, Hard LOCKUP)。检测延迟模型NMI 模式文档给出了 watchdog_thresh 10 假设下的最佳/最坏检测耗时。最佳情况锁死恰好发生在第一次心跳到期前检测器在下一次 NMI 检查时几乎立刻发现心跳缺失Time 100.0: cpu 1 heartbeat Time 100.1: hardlockup_check, cpu1 stores its state Time 103.9: Hard Lockup on cpu1 Time 104.0: cpu 1 heartbeat never comes Time 110.1: hardlockup_check, cpu1 checks the state again, should be the same, declares lockup Time to detection: ~6 seconds最坏情况锁死恰好发生在一次有效心跳之后、而该心跳又刚好发生在 NMI 检查之后。下一次 NMI 检查看到中断计数发生了变化因为那一次心跳于是认为 CPU 健康并重置基线锁死只能在再下一次检查时被发现Time 100.0: hardlockup_check, cpu1 stores its state Time 100.1: cpu 1 heartbeat Time 100.2: Hard Lockup on cpu1 Time 110.0: hardlockup_check, cpu1 stores its state (misses lockup as state changed) Time 120.0: hardlockup_check, cpu1 checks the state again, should be the same, declares lockup Time to detection: ~20 seconds因此 NMI 模式下的检测延迟范围大约是1.5 × watchdog_thresh 到 2 × watchdog_thresh默认 1520 秒量级最佳情况约 6 秒。Hardlockup 检测器Buddy 模式在 NMI perf 事件不可用或被关闭的架构/配置上内核可以使用 buddy hardlockup 检测器kernel/watchdog_buddy.c。该机制要求 SMP每个 CPU 被分配一个邻居buddyCPU 来监视监视 CPU 运行自己的 hrtimer与 softlockup 检测共用检查 buddy CPU 的 hrtimer 中断计数是否增长为保证及时性并避免误报buddy 系统在每个 hrtimer 间隔2 × watchdog_thresh / 5默认 4 秒都做一次检查漏中断阈值missed-interrupt threshold为3如果 buddy 的中断计数连续 3 次检查都没有变化就假定 buddy CPU 已 hardlock中断被禁用监视 CPU 随即触发 hardlockup 响应告警或 panic。源码印证了这一点。watchdog_hardlockup_probe() 在 Buddy 模式下将全局的 miss 阈值覆写为 3int __init watchdog_hardlockup_probe(void) { watchdog_hardlockup_miss_thresh 3; return 0; }该全局变量定义于 kernel/watchdog.cNMI/Perf 模式的默认值为 1即发现一次漏中断立即判定。监视关系由 watchdog_next_cpu() 基于watchdog_cpus掩码按下一个 CPU 环形监视的方式建立每个 CPU 的 hrtimer 中断到达时watchdog_hardlockup_kick()顺便对下一个 CPU 做一次 buddy 检查watchdog_buddy_check_hardlockup()。CPU 上线/下线时通过watchdog_hardlockup_touch_cpu()主动喂狗并配合smp_wmb()/smp_rmb()屏障防止新上线或下线过程中的计数空窗造成误报。检测延迟与局限Buddy 模式在默认 4 秒检查间隔watchdog_thresh 10下最佳情况锁死恰好发生在检查前约8 秒检出0s 到第 1 次检查 4s 到第 2 次 4s 到第 3 次最坏情况锁死恰好发生在检查后约12 秒检出4s 4s 4s。Buddy 检测器有两个文档明确指出的局限全 CPU 锁死如果所有 CPU 同时锁死监视 CPU 本身也冻结了buddy 检测器无法发现这一情况栈回溯能力弱与 NMI 检测器不同buddy 检测器无法直接中断锁死 CPU 去抓栈只能依赖架构特定机制如 NMI backtrace 支持尝试获取锁死 CPU 状态如果架构缺少该支持日志里可能只记录了发生了锁死而没有锁死 CPU 的调用栈。nohz_full 场景下的看门狗核排除Watchdog Core Exclusion默认情况下看门狗在所有在线核上运行。但文档特别指出在配置了NO_HZ_FULL的内核上看门狗默认只在 housekeeping 核上运行不会运行在nohz_full启动参数指定的核上。原因是如果让看门狗在nohz_full核上运行就必须在该核上运行 timer tick 来激活调度器这恰恰破坏了nohz_full让内核不干扰这些核上的用户态代码 的设计初衷。源码中这一策略在 lockup_detector_init() 中落地void __init lockup_detector_init(void) { if (tick_nohz_full_enabled()) pr_info(Disabling watchdog on nohz_full cores by default\n); cpumask_copy(watchdog_cpumask, housekeeping_cpumask(HK_TYPE_TIMER)); ... }即watchdog_cpumask初始直接取 housekeeping定时器核掩码。代价是这些nohz_full核一旦进入内核锁死默认情况下是检测不到的。补救手段无论哪种情况被排除在看门狗之外的核集合都可以通过kernel.watchdog_cpumasksysctl 调整。对调试内核疑似挂死在 nohz_full 核上的问题这是文档推荐的抓手——把问题核加回看门狗掩码即可恢复检测能力源码实现见 proc_watchdog_cpumask()写入后立即触发proc_watchdog_update()重配置。相关启动参数速查结合 kernel-parameters.txt与 lockup watchdog 直接相关的启动参数汇总如下适用前提编译时启用了对应的SOFTLOCKUP_DETECTOR/HARDLOCKUP_DETECTOR配置参数作用源码入口watchdog_threshN设置检测阈值秒sysctl 上限 60watchdog_thresh_setup()nowatchdog关闭 soft hard 两个锁死检测器nowatchdog_setup()nosoftlockup仅关闭 softlockup 检测器nosoftlockup_setup()nmi_watchdogpanic\|nopanic\|0\|1控制 hardlockup 检测器及是否 panic支持逗号分隔组合hardlockup_panic_setup()softlockup_panicNsoftlockup 连续 N 个阈值周期后 panicsoftlockup_panic_setup()运行时等价开关对应 sysctlkernel.watchdog、kernel.soft_watchdog、kernel.nmi_watchdog、kernel.softlockup_panic、kernel.hardlockup_panic。此外启用CONFIG_SYSFS时内核还会在/sys/kernel/下暴露只读计数文件softlockup_count与hardlockup_count见 kernel/watchdog.c 与 kernel/watchdog.c便于脚本化监控锁死发生次数。实践要点小结默认值即可用watchdog_thresh10时 softlockup 判定阈值为 20 秒、hrtimer 采样 4 秒、NMI 检测窗口 10 秒无需任何配置就默认启用softlockup 恒启用hardlockup 取决于架构的 NMI 支持探测失败时会打印NMI not fully supported并永久禁用见 lockup_detector_delay_init()。调大阈值可降低检测频率与开销、减少极端负载下的误报但会拉长故障暴露时间调小则相反。watchdog_thresh的 sysctl 写入会触发全量探测器重建写入行为本身是原子的持watchdog_mutex。无人值守系统建议组合softlockup_panic/hardlockup_panic或对应启动参数kernel.panic超时实现检测到锁死 → panic → 自动重启的自愈链路。信息面在复现问题时开启softlockup_sys_info/hardlockup_sys_info可取task,mem,locks,timers,ftrace等组合位定义见 include/linux/sys_info.h与*_all_cpu_backtrace能显著扩大现场信息量。架构差异优先确认目标平台走的是 NMI/Perf 还是 Buddy 路径——Buddy 路径无法检测全 CPU 锁死且抓栈能力受限虚拟机场景中注意watchdog_timer_fn()里专门处理了 guest 被宿主机暂停kvm_check_and_clear_guest_paused()的伪 softlockup 场景。隔离核环境使用nohz_full做核隔离时默认没有看门狗保护调试内核侧挂死问题时记得通过kernel.watchdog_cpumask把目标核加回。掌握以上机制后你就能在生产环境准确解读BUG: soft lockup - CPU#X stuck for Ys!与Watchdog detected hard LOCKUP on cpu X两类日志背后的检测时序并针对具体环境SMP/UP、NMI 支持情况、nohz_full 隔离做出正确的 watchdog 配置。【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询