很多人第一次看到 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 的报告看起来吵,但它提供的是非常稀有的信息:内核实际观察到的锁依赖。
把它当作锁关系地图,而不是单点告警,才能真正看懂它在提醒什么。
评论