kmemleak 扫描的长跑
大内存 debug 内核
扫描一跑就是很久
cond_resched()
用来防 soft lockup
CONFIG_PREEMPTION 内核上,它是空操作
抢占不必等这个让出点,它不必真的让出 CPU
而且它从来不是 RCU-tasks 的静止状态
让出 CPU ≠ 向 RCU-tasks 上报
RCU-tasks 没有读侧加锁原语
grace period 只能等任务自己走到静止状态
自愿上下文切换
执行用户态代码
进 idle
主动上报
做到任意一个,GP 就不必再等这个任务
被抢占
不算静止状态
所以空转的 cond_resched() 帮不上忙
kmemleak 不上报的传导链
扫描循环
不切换、不上报
holdout 链表
任务被挂上
grace period
被拖住不结束
BPF map 释放
等这个 grace period
122 s
等待方被卡住的时长
BPF struct_ops map 的释放走 synchronize_rcu_mult()
被卡 122 秒,触发 hung task 告警
等待方跟着遭殃
扫描路径上 7 个 cond_resched() 让出点
全部换成 cond_resched_tasks_rcu_qs()
让出与上报合成一次调用
每次让出都顺带上报一次静止状态
不再以「真的发生了调度」为前提
soft lockup 防护不受影响
调度语义保持原样,只是补上了 RCU-tasks 上报
cond_resched_tasks_rcu_qs()
rcu_tasks_qs()
清当前任务的 holdout 标记
声明 GP 不必再等自己
cond_resched()
保持原语义
非 PREEMPTION 配置下仍按需让出
前半段上报,后半段管调度
cond_resched() 是不是空操作,不再影响判定
几处原本就是先放锁再让出、让出完再拿锁
换上的原语同样落在无锁窗口里
安全性与原有调度点一致
7 个让出点分布
· scan_large_block()
· scan_object()(2 处)
· scan_gray_list()
· kmemleak_cond_resched()
· kmemleak_scan_task_stacks()
· kmemleak_scan() 主循环
主循环的让出节奏
每 64 个 PFN 让出一次,每次都上报
scan_object() 有两处,其余函数各一处
合计 7 个让出点,覆盖扫描主路径与辅助函数
① GP 不再被拖住
kmemleak 扫描不再
拖延 grace period
消除 rcu_tasks stall 告警
② 等待方不再被连带
synchronize_rcu_mult()
不再被卡
消除 122 秒级 hung task
③ 防护保持原样
soft lockup 防护不变
每轮让出只多
一次标记读取
作者未提供性能数据,收益由机制推出
上报与调度解耦之后,cond_resched() 空转不再拖住 GP
把静止状态上报从调度里解耦
让出不必以发生调度为前提,GP 才能及时结束
空格
播放/暂停
←
→
逐动作
R
重播
⚠
1x