tlb choose_new_asid
choose_new_asid是 x86 架构 TLB 管理中的核心决策函数它的任务是在进程切换时为即将运行的地址空间next选择一个合适的 ASID 槽位并决定是否需要刷新 TLB。核心职责当调度器决定切换到新的mm_struct时switch_mm_irqs_off会调用choose_new_asid它需要回答两个问题用哪个 ASID 槽位需要刷新 TLB 吗决策逻辑函数的决策流程清晰且分层1. 无 PCID 支持!static_cpu_has(X86_FEATURE_PCID)直接返回 ASID0并强制刷新 TLB。此时硬件不支持 PCID无法做任何缓存优化。2. 检查“全局 ASID”如果next是一个需要全局 ASID的特殊mm例如init_mm或某些内核线程直接返回该全局 ASID且不需要刷新。全局 ASID 的 TLB 条目被所有进程共享不存在隔离问题。3. 缓存命中查找遍历当前 CPU 的 6 个 ASID 槽位ctxs[0..5]比较每个槽位的ctx_id是否等于next-context.ctx_id。命中找到该mm对应的槽位。此时需要判断是否需要刷新如果槽位记录的tlb_gen小于next_tlb_gen即该mm的页表自上次在此 CPU 上运行后发生过变更则必须刷新否则可以复用 TLB 条目避免刷新。未命中next不在当前 CPU 的缓存中。4. 缓存未命中分配新槽位通过this_cpu_add_return(cpu_tlbstate.next_asid, 1) - 1原子地获取下一个槽位编号。如果编号超出TLB_NR_DYN_ASIDS6则回绕到 0。此时必然需要刷新 TLB因为新槽位可能残留着其他地址空间的陈旧条目。调用关系choose_new_asid的调用者非常集中switch_mm_irqs_off() └── choose_new_asid() // 在 real_prev ! next 的分支中在switch_mm_irqs_off中当real_prev ! next即真正发生了地址空间切换时会调用choose_new_asid获取new_asid和need_flush然后根据need_flush决定使用write_cr3刷新还是write_cr3配合CR3_NOFLUSH不刷新。返回值语义情况ASIDneed_flush含义无 PCID0true硬件不支持强制刷新全局 ASID全局值false共享映射无需刷新缓存命中tlb_gen 最新命中槽位false复用 TLB零开销缓存命中tlb_gen 落后命中槽位true需要刷新以更新陈旧条目缓存未命中分配新槽位新槽位true必须刷新以清除残留缓存命中且tlb_gen最新是性能最优的路径既复用了 ASID 槽位又完全避免了 TLB 刷新这正是 Linux “浅缓存”策略的核心收益。代码演进2025 年 4 月Borislav Petkov 提交了一个清理补丁将choose_new_asid的输出参数u16 *new_asid和bool *need_flush改为返回值结构体struct new_asid。这个结构体只有两个位域asid:16和need_flush:1可以放入单个 32 位寄存器既提升了代码可读性也帮助编译器生成了更优的代码tlb.o的 text 段从 9341 字节减小到 9213 字节。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →