排查 soft lockup 最直接、最高效的入口通常就是 dmesg。执行dmesg | grep -i "soft lockup",可以快速检索相关内核日志;而dmesg -T | grep -A5 -B2 "soft lockup"则能进一步查看带时间戳和 Call Trace 的上下文信息。日志中的重点字段通常包括 CPU 编号、卡住的线程名称(如 [kworker/1:2])以及调用栈起始位置,这些信息对 Linux 内核软锁定问题定位非常关键。

直接看 dmesg 里的 soft lockup 报告
当软锁定(soft lockup)发生后,Linux 内核通常会立即向 ring buffer 写入包含时间戳和调用栈的诊断日志,因此 dmesg 是查看 soft lockup 报告最直接的方法。不要等系统完全卡死后再排查,只要日志尚未被覆盖,相关记录通常还保留在缓冲区中:
dmesg | grep -i "soft lockup"—— 快速筛出最近出现的 soft lockup 日志dmesg -T | grep -A5 -B2 "soft lockup"—— 显示可读时间,并带出上下文内容(例如紧邻的Call Trace)- 典型输出中的关键字段包括:
CPU#1表示发生卡顿的 CPU 核心,[kworker/1:2]是被卡住的线程名称,而最后的Call Trace:则是函数调用链的起点
需要注意的是,默认情况下 dmesg 缓冲区可能会被后续新日志覆盖。如果 soft lockup 触发频繁,建议结合 journalctl -k -f 持续实时监听内核日志流,避免关键信息丢失。
启用 lockdep 后看 /proc/lockdep_chains
lockdep 并不是单纯的“事后分析工具”,而是 Linux 内核运行时用于动态建模锁依赖关系的重要机制。它仅在启用了 CONFIG_PROVE_LOCKING=y 的内核中可用,并且通常还需要手动开启:
- 检查是否可用:
cat /proc/sys/kernel/lockdep返回1才表示已启用 - 临时开启:
echo 1 > /proc/sys/kernel/lockdep(需要 root 权限) - 最有参考价值的报告位置:
cat /proc/lockdep_chains—— 这里会列出系统已观测到的所有锁依赖链,并标记循环依赖路径(如*** DEADLOCK ***) - 如果需要更细粒度的锁统计,可查看:
cat /proc/lock_stat,重点关注wait_time_total和hold_time_total异常偏高的锁对象名称(例如&dev->mutex)
⚠️ 生产环境中应谨慎启用:lockdep 会明显增加锁操作的性能开销,甚至可能掩盖、放大或改变原始问题表现,因此不建议在业务系统中长时间保持开启状态。
用 perf record 捕获卡点现场的调用栈
如果 dmesg 只提示“CPU#0 stuck for 22s”这类信息,却没有给出完整调用栈,或者你怀疑某个内核模块正在反复自旋,那么使用 perf 往往是更贴近真实运行现场的排查方式:
- 先确认 watchdog 是否正常工作:
cat /proc/sys/kernel/watchdog_thresh(默认 10 秒,为软锁定阈值) - 录制 30 秒热点调用栈:
perf record -a -g -e cpu-clock -- sleep 30 - 导出类似火焰图分析视角的报告:
perf report --no-children --sort comm,dso,symbol | head -n 50 - 重点关注:反复出现的内核函数(如
spin_lock、mutex_lock_slowpath),以及方括号中的模块名称(如[nvme]、[i915])
这种方法不依赖 lockdep,也无需重启系统,特别适合在疑似 soft lockup 但 watchdog 尚未正式触发之前,提前捕获异常热点并进行干预。
lslocks 只能看用户态文件锁,别误用它查内核死锁
lslocks 显示的是 flock()、fcntl(F_SETLK) 等 POSIX 文件锁信息,属于 VFS 层面的用户态锁机制,与 Linux 内核中的自旋锁、互斥锁并不是同一类概念。因此,它对排查 soft lockup、hard lockup 或内核死锁基本没有帮助:
- 执行
lslocks,通常只会看到类似/var/lock/subsys/network这样的锁文件路径,以及对应的持有进程 PID - 即便输出中显示多个进程竞争同一把锁,那通常也只是应用层面的死锁或资源争用(例如 shell 脚本互相等待),并不是导致内核卡死的直接原因
- 真正要分析内核锁状态,仍然需要依赖
/proc/lockdep*、perf,或者通过bpftrace跟踪内核函数入口和执行路径
一个常见误区是:很多运维人员遇到“死锁”第一反应会去执行 lslocks 或 lsof | grep LOCK,结果白白浪费不少时间。更稳妥的做法是先确认问题究竟发生在用户态还是内核态,再选择合适的 Linux 调试工具进行分析。
