sched discussion
[PATCH v19 00/40] DEPT(DEPendency Tracker)
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.c、mm/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_unlock 加 lock_acquire_*,用 LDT_EVT_{L,R,W,RW,ALL} 区分。
Patch 概览
dept: implement DEPT:dept.h 核心 + struct dept_task 嵌入 task_struct。sdt高层 API(single event dependency tracker)。ldt高层 API(lock dependency tracker)。- 与 lockdep/IRQ tracing 联动,给 spin/mutex/rwlock/seqcount/percpu-rwsem/srcu/rtmutex 注入 dmap。
- procfs
dept_deps/dept_stats。 - 区分 process/SIRQ/HIRQ 三类 context(
cur_cxt())。 - workqueue worker 独立 cxt_id。
- 对象池耗尽时 irq_work + workqueue + vmalloc 异步补给。
- 合并同类连续 wait。
10–14.sdt_might_sleep_{start,end}接到 completion/swait/waitqueue/hashed-waitqueue/dma fence。 DEPT_AGGRESSIVE_TIMEOUT_WAITKconfig。
16–20. timeout 区分应用到 wait_for_completion/swait/waitqueue/hashed-waitqueue/dma fence。dept_ext_wgen(每对象仅 4 字节)。- 用 ext_wgen 跟踪 PG_locked。
- 在报告里打印 staged wait 的栈。
- lockdep
__lockdep_enabled感知lockdep_off()。 Documentation/dev-tools/dept.rst。- cpu/hotplug AP 线程改用 try-lock。
- mmu notifier invalidation 注入 dept map。
- 每个 dma fence caller 独立 dept_key。
- 兼容
lockdep_set_lock_cmp_fn。 debug_locks_off()同步停掉 DEPT。- 每个 wait_for_completion caller 独立 dept_key。
init_completion_dmap()新 API。local_irq_*()无条件调用dept_hardirqs_off。- 修 RCU 子类 key 冲突。
- page usage subclass API。
- 用 dept 跟踪 PG_writeback。
- SUNRPC
rpc_xprt把rcu_head调到第一个字段(Jeff Layton Reviewed-by)。 - DEPT + 大页条件下放大 PERCPU_DYNAMIC_SIZE_SHIFT。
- rust completion
__rust_helper。 - 基础 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_up 经 dept_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)/ 本地 lpool;from_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:风险与注意点
- thread 中 30+ 条 bot reply(sashiko-bot/syzbot)正文为空,只能从标题与 patch 元数据推断;主流意见集中在 David Hildenbrand、NeilBrown、Matthew Wilcox 的若干长回复。
- 假阳性仍是最大风险:作者明确承认"comprehensive annotation requires subsystem maintainer expertise";v19 主动砍掉 recover events tracking,相关环路是否再现需观察。
- PG_locked 跟踪采用"假设
folio_lock()总走 wait 路径"的乐观模型(patch 22 注释),fast path 下瞬时持锁也会进入依赖图,存在轻微噪声。 - hot path 上
arch_spinlock_t+dept_pool_spin+ 关本地 IRQ 的开销不容忽视,需要回归与 perf 评估。 dept_map_copy与lockdep_copy_map双轨拷贝使每个锁描述符更大;patch 35 page usage subclass、27/28/31 的 unique key 持续增加结构性成本。- 协作依赖:DEPT 与 lockdep 共存,每个 acquire/release 点都要展开两套 wrapper;后续需明确谁在子系统中加注释、谁负责回归。
版本变化
v18 → v19 关键改动:
- rebase 到 v7.0;
- patch 37(SUNRPC: relocate
struct rcu_head)获 Jeff Layton Reviewed-by; - 文档与注释继续精修(Bagas Sanjaya、Yunseong Kim 反馈);
- patch 39 为
rust_helper_wait_for_completion()新增__rust_helper(Dirk Behme 反馈); - 移除"recover events tracking"以降低初始 review burden,维护转移 out-of-tree;
- 去除函数声明中的
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 控制强度。