快路径:批量释放页表
unmap_region / exit_mmap
→ tlb_remove_table()
把页表指针攒进 mmu_table_batch
batch 里有什么
struct mmu_table_batch
table[] 指针数组
nr 记录表数量
flush 时交给 call_rcu
为什么要批量
减少逐表同步
共享一次宽限期
快路径追求吞吐
代价是 batch 分配
批量成功时
batch 分配成功,页表延迟到 RCU callback 释放
fast path 不在这里同步等 walker
batch 页从哪来
*batch == NULL
__get_free_page(GFP_NOWAIT)
不能睡眠,不能等内存
分配失败
GFP_NOWAIT 返回 NULL
tlb_table_invalidate()
tlb_remove_table_one()
立即退回单页释放
单页释放
不走 batch
仍要与 walker 同步
!CONFIG_PT_RECLAIM
这条回退有同步成本
这是慢路径
分配失败后,保证释放仍有进展
允许付出同步成本,但不能丢正确性
旧回退的同步
tlb_remove_table_sync_one()
→ smp_call_function(..., wait = 1)
先让所有 CPU 响应,再释放
IPI 广播
tlb_remove_table_smp_sync
handler 只负责收中断
wait = 1 等全部完成
每个 CPU 都被打断
同步之后
__tlb_remove_table(table)
释放单张页表
正确性由同步保证
广播已经发生
有效,但一刀切
哪怕只有一个进程在 unmap
所有 CPU 都要停一下
场景:只有一个 unmap
单个进程取消映射
只需要释放一张页表
同步范围本可以很小
实际广播范围
IPI 到每个 CPU
与 unmap 的进程数无关
范围由广播实现决定
小操作变成全局事件
被伤害的是 RT
IPI 打断其他 CPU
实时任务出现延迟
报告指向 RT 工作负载
不是理论担忧
问题不在同步
同步是必要的
没必要让所有 CPU 参与
要防的是谁
lockless page-table walker
例如 GUP-fast
读页表时不拿锁
walker 的读侧临界区
local_irq_disable()
IPI 打断不了这段
这本身是 RCU 读侧
walker 退出前,页表不能放
RCU 宽限期覆盖
synchronize_rcu()
等待所有旧读侧结束
包括禁中断的 walker
等到了才继续释放
关键等价
IPI 等 walker 退出
RCU 也等 walker 退出
新 helper
tlb_remove_table_sync_rcu()
→ synchronize_rcu()
只在慢路径使用
回退路径替换
__tlb_remove_table_one()
sync_one() → sync_rcu()
!CONFIG_PT_RECLAIM
只改这一处调用
为什么可以睡
unmap_region / exit_mmap
进程上下文
只持 mmap_lock
慢路径等宽限期可接受
不是所有分支
CONFIG_PT_RECLAIM 分支仍走 call_rcu
本改动只碰批量分配失败的回退
旧 helper 保留
tlb_remove_table_sync_one()
没有删除
还有其他调用者
还有谁在用
khugepaged
pmdp_collapse_flush 之后
tlb_finish_mmu
fully_unshared_tables
为什么不一起换
这些不是慢路径
不能随意睡宽限期
可能需要定向 IPI
转换要另做方案
改动范围
只替换批量分配失败的回退
其他路径维持旧同步
机制上的收益
回退不再发 IPI
其他 CPU 不被打断
RT 不被广播干扰
正确性
synchronize_rcu 等旧读侧
没有 walker 在跑
与 IPI 同等保证
不是用弱化同步换性能
适用范围
慢路径、进程上下文
非慢路径仍用 sync_one
没有全局替换
旧同步保留
边界:没有量化 benchmark
作者未提供延迟/吞吐数据
不写数字,只讲机制
空格
播放/暂停
←
→
逐动作
R
重播
⚠
1x