0/107 已展开

LLM 分析

DEPT(DEPendency Tracker):运行时死锁检测框架 v19

系列概况

  • 标题:[PATCH v19 00/40] DEPT(DEPendency Tracker)
  • 作者:Byungchul Park <byungchul@sk.com>
  • 版本:v19,共 40 个 patch;thread 共 108 封邮件
  • 修改文件:核心 kernel/dependency/{dept.c, dept_proc.c, dept_internal.h, dept_object.h, Makefile};头文件 include/linux/{dept.h, dept_sdt.h, dept_ldt.h, sched.h, hardirq.h, irqflags.h, irq-entry-common.h, lockdep.h, lockdep_types.h, mutex.h, rtmutex.h, rwlock_types.h, rwsem.h, seqlock.h, spinlock_types_raw.h, srcu.h, swait.h, wait.h, wait_bit.h, completion.h, pagemap.h, page-flags.h, mm_types.h, percpu-rwsem.h, local_lock_internal.h};调用点 kernel/{workqueue.c, cpu.c, sched/completion.c, locking/lockdep.c}drivers/dma-buf/dma-fence.cmm/filemap.c;文档 Documentation/dev-tools/dept.rst
  • 代码统计:单 patch 增量 3~116 行
  • Message-ID:20260706061928.66713-1-byungchul@sk.com
  • 完整性:cover letter 含背景/动机/FAQ/Changes from v17/v18/致谢;thread 含 syzbot、sashiko-bot 与 Matthew Wilcox、David Hildenbrand、NeilBrown、Miguel Ojeda、Yunseong Kim、Byungchul Park 的多轮讨论

补丁目的

lockdep 二十年只跟踪锁获取顺序,对 folio lock、wait_for_completion()/complete()、DMA fence、RCU、一般 waitqueue 等跨上下文同步的"事件可达性"无感。DEPT 把死锁重新表述为"事件依赖环":在每个 context区分 [S] 起点、[W] 等待点、[E] 事件,扫描 [S]..[E] 之间所有 [W],若 [W] 的唤醒依赖于别处的事件则建立有向边;DFS 检测到环即报告死锁。

旧流程的问题

context X    context Y    context Z
mutex_lock A
folio_lock B
            folio_lock B  <- DEADLOCK
            mutex_lock A  <- DEADLOCK
folio_unlock B
            folio_unlock B
mutex_unlock A
            mutex_unlock A

lockdep 看不到"释放事件发生在另一个上下文",更看不到"事件 A 触发的前提是 context X 在 wait W 上被唤醒"。

新流程

 [S] start event context
 \
 [W] wait for another event
              \
 [E] event occurs

每个 context 内对每个 event context 收集 [W],按 wgen 匹配等待者,建立依赖图。最简用法:

struct dept_map my_wait;
sdt_map_init(&my_wait);   /* init */
sdt_wait(&my_wait);       /* potential wait */
sdt_event(&my_wait);      /* wakeup */

锁类原语走 ldt_lock/ldt_rlock/ldt_wlock/ldt_unlocklock_acquire_*,用 LDT_EVT_{L,R,W,RW,ALL} 区分。

Patch 概览

  1. dept: implement DEPT:dept.h 核心 + struct dept_task 嵌入 task_struct。
  2. sdt 高层 API(single event dependency tracker)。
  3. ldt 高层 API(lock dependency tracker)。
  4. 与 lockdep/IRQ tracing 联动,给 spin/mutex/rwlock/seqcount/percpu-rwsem/srcu/rtmutex 注入 dmap。
  5. procfs dept_deps / dept_stats
  6. 区分 process/SIRQ/HIRQ 三类 context(cur_cxt())。
  7. workqueue worker 独立 cxt_id。
  8. 对象池耗尽时 irq_work + workqueue + vmalloc 异步补给。
  9. 合并同类连续 wait。
    10–14. sdt_might_sleep_{start,end} 接到 completion/swait/waitqueue/hashed-waitqueue/dma fence。
  10. DEPT_AGGRESSIVE_TIMEOUT_WAIT Kconfig。
    16–20. timeout 区分应用到 wait_for_completion/swait/waitqueue/hashed-waitqueue/dma fence。
  11. dept_ext_wgen(每对象仅 4 字节)。
  12. 用 ext_wgen 跟踪 PG_locked。
  13. 在报告里打印 staged wait 的栈。
  14. lockdep __lockdep_enabled 感知 lockdep_off()
  15. Documentation/dev-tools/dept.rst
  16. cpu/hotplug AP 线程改用 try-lock。
  17. mmu notifier invalidation 注入 dept map。
  18. 每个 dma fence caller 独立 dept_key。
  19. 兼容 lockdep_set_lock_cmp_fn
  20. debug_locks_off() 同步停掉 DEPT。
  21. 每个 wait_for_completion caller 独立 dept_key。
  22. init_completion_dmap() 新 API。
  23. local_irq_*() 无条件调用 dept_hardirqs_off
  24. 修 RCU 子类 key 冲突。
  25. page usage subclass API。
  26. 用 dept 跟踪 PG_writeback。
  27. SUNRPC rpc_xprtrcu_head 调到第一个字段(Jeff Layton Reviewed-by)。
  28. DEPT + 大页条件下放大 PERCPU_DYNAMIC_SIZE_SHIFT。
  29. rust completion __rust_helper
  30. 基础 unit test。

关键实现

dept_request_event(m, ewg): next_wgen(); WRITE_ONCE(*wg_p, wg);
dept_wait(m): read *wg_p; record into dept_wait;
do_event(m):                  match wgen; build dependency edge;

__schedule() 之前 dept_stage_wait() 暂存 wait,进入调度时由 dept_request_event_wait_commit() 提交;try_to_wake_updept_ttwu_stage_wait() 找回等待者上下文。

timeout = timeoutval > 0 && timeoutval < MAX_SCHEDULE_TIMEOUT;
#if !defined(CONFIG_DEPT_AGGRESSIVE_TIMEOUT_WAIT)
    if (timeout)
        return;
#endif

is_timeout_wait_circle() 检测若环上全是 timeout wait 则降级为 "NOT A DEADLOCK BUT A CIRCULAR DEPENDENCY"。

内存层采用三段对象池:静态 spool / 后备 rpool(vmalloc)/ 本地 lpoolfrom_pool()arch_spin_lock 保护跨 CPU 借用,obj_nr==0 时把 rpool 升格为新 spool 并触发 request_rpool_refill()。PG_locked 这类不能放完整 map 的对象使用 dept_ext_wgen 仅占 4 字节。

整体关系:

+-------------------+ +-------------------+
|   sdt_* (high)   |----->|   dept_*  (core)  |
+-------------------+      +-------------------+
        |                          |
        v                          v
+--------------------+    +---------------------+
| ldt_* (lock API)  |    |  struct dept_task |
+--------------------+    |  ecxt_held, wait_hist|
        |                 |  cxt_id[], stack |
        v                 +---------------------+
+-------------------+ |
| lockdep (existing)|<-------------+
+-------------------+

类比

把 DEPT 想象成"城市交通调度中心":每辆车是 process/IRQ/worker,[S] 出发取外卖,[W] 等红灯,[E] 外卖到手。lockdep 是路口摄像头,只看"先左转还是先直行";DEPT 调度中心记录"哪辆车要等另一辆车的外卖",地图上画出"外卖互为前提"的环。一旦 A 等 B、B 等 C、C 等 A,就是堵死。timeout wait 相当于"等 30 分钟就取消",调度中心把这种"等得起"的环标注为 "CIRCULAR DEPENDENCY, NOT A DEADLOCK"。另一个类比是"论文查重":lockdep 抓"引用相同文献的链路",DEPT 抓"结论互为前提的论证链"。

Highlight:风险与注意点

  1. thread 中 30+ 条 bot reply(sashiko-bot/syzbot)正文为空,只能从标题与 patch 元数据推断;主流意见集中在 David Hildenbrand、NeilBrown、Matthew Wilcox 的若干长回复。
  2. 假阳性仍是最大风险:作者明确承认"comprehensive annotation requires subsystem maintainer expertise";v19 主动砍掉 recover events tracking,相关环路是否再现需观察。
  3. PG_locked 跟踪采用"假设 folio_lock() 总走 wait 路径"的乐观模型(patch 22 注释),fast path 下瞬时持锁也会进入依赖图,存在轻微噪声。
  4. hot path 上 arch_spinlock_t + dept_pool_spin + 关本地 IRQ 的开销不容忽视,需要回归与 perf 评估。
  5. dept_map_copylockdep_copy_map 双轨拷贝使每个锁描述符更大;patch 35 page usage subclass、27/28/31 的 unique key 持续增加结构性成本。
  6. 协作依赖:DEPT 与 lockdep 共存,每个 acquire/release 点都要展开两套 wrapper;后续需明确谁在子系统中加注释、谁负责回归。

版本变化

v18 → v19 关键改动:

  1. rebase 到 v7.0;
  2. patch 37(SUNRPC: relocate struct rcu_head)获 Jeff Layton Reviewed-by;
  3. 文档与注释继续精修(Bagas Sanjaya、Yunseong Kim 反馈);
  4. patch 39 为 rust_helper_wait_for_completion() 新增 __rust_helper(Dirk Behme 反馈);
  5. 移除"recover events tracking"以降低初始 review burden,维护转移 out-of-tree;
  6. 去除函数声明中的 extern(Petr Pavlu 反馈)。

后续讨论要点:Matthew Wilcox 在 patch 22 提出注释粒度疑问,作者解释 folio/page 分支区别;Miguel Ojeda 对 patch 39 回复,作者跟进;David Hildenbrand 与 NeilBrown 在 8/20–8/30 期间展开多轮设计讨论,关注 DEPT 与 lockdep 的边界、子系统注解拆分、生产环境开销、是否应拆分提交。

一句话总结

DEPT v19 把"事件依赖"作为一等公民引入内核,把 lockdep 看不到的 folio/completion/dma fence/RCU/waitqueue 等跨原语死锁统一抽象为 wait/event 依赖环,与 lockdep 并存并通过 Kconfig 控制强度。