排查soft lockup最直接的入口,非dmesg莫属。执行dmesg | grep -i "soft lockup",能快速定位日志;而dmesg -T | grep -A5 -B2 "soft lockup",则可显示带时间戳和Call Trace的上下文。这里面的关键字段包括CPU编号、卡住线程名(像[kworker/1:2])以及调用栈起点。

直接看 dmesg 里的 soft lockup 报告
软锁定(soft lockup)触发后,内核会立即往 ring buffer 写入带时间戳和调用栈的日志,dmesg 是最直接的入口。别等系统卡死再查,只要出现过,它就还在缓冲区里:
dmesg | grep -i "soft lockup"—— 快速定位最近几条dmesg -T | grep -A5 -B2 "soft lockup"—— 加上人类可读时间,并显示上下文(比如紧邻的Call Trace)- 典型输出里关键字段:
CPU#1表示哪个核卡住、[kworker/1:2]是卡住的线程名、末尾的Call Trace:是函数调用链起点
注意:默认 dmesg 缓冲区可能被新日志覆盖,高频软锁时建议搭配 journalctl -k -f 实时监听内核日志流。
启用 lockdep 后看 /proc/lockdep_chains
lockdep 不是“事后分析”,而是运行时动态建模锁依赖关系。它只在配置了 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,也不需要重启,适合在疑似软锁但尚未触发 watchdog 的阶段提前干预。
lslocks 只能看用户态文件锁,别误用它查内核死锁
lslocks 显示的是 flock()、fcntl(F_SETLK) 这类 POSIX 文件锁,属于 VFS 层,跟内核自旋锁、互斥锁完全无关。它对排查软锁/硬锁毫无帮助:
- 执行
lslocks只会列出类似/var/lock/subsys/network这样的路径和持有进程 PID - 即使输出里有多个进程争同一把锁,那也只是应用层死锁(如 shell 脚本竞争),不是内核卡死原因
- 真要查内核锁状态,必须依赖
/proc/lockdep*、perf或bpftrace跟踪内核函数入口
容易忽略的一点:很多运维第一反应是 lslocks 或 lsof | grep LOCK,结果浪费半小时——先确认问题发生在哪一层,再选工具。