☰
tlb flush_tlb_func
2026/10/2 13:23:59 网站建设 项目流程

flush_tlb_func是 x86 架构 TLB 刷新(TLB Shootdown)机制中的核心 IPI 处理函数。它运行在接收到刷新请求的远程 CPU 上,负责根据请求信息执行本地 TLB 失效操作。

核心作用:远程 TLB 失效执行者

当 CPU A 修改了页表后,需要通知所有正在使用该地址空间的 CPU 刷新 TLB。它通过smp_call_function_many发送 IPI,目标 CPU 的中断处理程序会调用flush_tlb_func,在本地执行实际的 TLB 失效操作。

核心执行逻辑

根据内核源码,其逻辑可以概括为以下几个关键阶段:

1. 快速检查与惰性 TLB 处理

if (f->mm && f->mm != this_cpu_read(cpu_tlbstate.active_mm)) return;

如果请求的mm与当前 CPU 活跃的mm不匹配,说明该 CPU 不需要刷新,直接返回。随后检查当前 CPU 是否处于惰性 TLB 模式:如果是,则调用leave_mm()退出惰性模式并切换回init_mm,而不是继续使用可能过期的页表。

2. TLB 世代(tlb_gen)检查

u64 mm_tlb_gen = atomic64_read(&loaded_mm->context.tlb_gen); u64 local_tlb_gen = this_cpu_read(cpu_tlbstate.ctxs[loaded_mm_asid].tlb_gen);

内核为每个mm维护一个全局递增的 TLB 世代计数器。每个 CPU 记录自己已“追赶”到的世代。如果请求的new_tlb_gen <= local_tlb_gen,说明该 CPU 的 TLB 已经是最新的,可以跳过刷新,避免不必要的开销。

3. 执行刷新

if (f->end == TLB_FLUSH_ALL) { local_flush_tlb(); } else { for (addr = f->start; addr < f->end; addr += PAGE_SIZE) __flush_tlb_single(addr); }

根据请求范围决定刷新策略:

  • 全量刷新(end == TLB_FLUSH_ALL):调用local_flush_tlb(),通过重写 CR3 或切换 PGE 位来清空整个 TLB。

  • 范围刷新:逐页调用__flush_tlb_single(addr)(即invlpg指令),精确失效指定地址的 TLB 条目。

4. 更新本地世代

刷新完成后,将本 CPU 记录的tlb_gen更新为mm_tlb_gen,表示已经追赶上了最新的页表状态。

调用关系与上下文

flush_tlb_mm_range() / flush_tlb_kernel_range() └── native_flush_tlb_others() / flush_tlb_multi() └── smp_call_function_many(cpumask, flush_tlb_func, info, 1) └── flush_tlb_func(info) // ← 远程 CPU 的 IPI 处理

flush_tlb_func作为smp_call_function_many的回调被调用,运行在中断上下文中,因此必须满足:中断已禁用、不可重入(代码中有VM_WARN_ON(!irqs_disabled())和重入检查)。

关键优化与演进

这个函数经历过多次优化:

  • 延迟读取mm_tlb_gen:2022 年的补丁将mm_tlb_gen的读取推迟到确认需要刷新之后,避免在刷新风暴中争抢mm结构体的缓存行,在 56 核 Skylake 上带来高达24%的性能提升。

  • 跳过无意义的跟踪:2022 年的补丁确保在“不执行刷新”的路径上不调用trace_tlb_flush,保持跟踪行为一致。

  • 阈值决策集中化:2025 年的补丁将“部分刷新还是全量刷新”的决策集中到get_flush_tlb_info中,减少代码重复。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询