很多人第一次看到 lockdep 报告,会觉得它太长。里面有锁名、持锁栈、依赖链、irq 状态和一堆历史路径,看起来像噪音。

但 lockdep 的价值恰恰在这里。它不是简单告诉你“这里错了”,而是在告诉你内核观察到了一张可能导致死锁的锁关系地图。

不要只看最后一行

lockdep 报告最后通常会指出一次可疑加锁,但真正重要的是整条依赖链。

需要看清楚:

  • 当前正在申请哪把锁
  • 当前已经持有哪些锁
  • 过去观察到过什么相反顺序
  • 这些路径分别来自哪些上下文
  • 是否涉及 hardirq、softirq 或 reclaim

死锁问题不是“某把锁坏了”,而是“锁顺序在不同路径中不一致”。

锁顺序比锁本身更重要

如果路径 A 是:

lock X -> lock Y

路径 B 是:

lock Y -> lock X

那么即使两条路径单独看都合理,组合起来也可能死锁。lockdep 的核心能力,就是把这些跨路径关系记录下来。

因此修复时不要只在告警点加条件判断。应该先确定全局锁顺序,然后让所有路径遵守同一个顺序。

上下文会改变锁的含义

同一把锁在不同上下文中风险不同。

需要特别注意:

  • 普通进程上下文持锁后是否会睡眠
  • softirq 中是否会拿同一把锁
  • hardirq 是否可能打断当前持锁路径
  • reclaim 路径是否可能回调到同一子系统
  • timer/workqueue 是否和 remove 路径交叉

很多死锁不是两个线程直接互等,而是上下文切换后出现的隐含路径。

lockdep 报告要保留完整

调试锁问题时,不要只复制最后几行。完整报告包含历史依赖链,缺失后很难判断真实关系。

最好同时保留:

  • 完整 dmesg
  • 内核 config
  • tainted 状态
  • 触发操作
  • 是否可复现
  • 相关模块版本

如果报告来自压力测试,还要记录并发规模和触发频率。

结尾

lockdep 的报告看起来吵,但它提供的是非常稀有的信息:内核实际观察到的锁依赖。

把它当作锁关系地图,而不是单点告警,才能真正看懂它在提醒什么。