☰
tlb get_flush_tlb_info
2026/10/3 12:41:45 网站建设 项目流程

get_flush_tlb_info是 x86 架构 TLB 刷新机制中用于获取并初始化一个flush_tlb_info结构体的辅助函数。它的核心职责是:为即将进行的 TLB 刷新操作“预订”一块存储空间,并把刷新范围、目标mm、步长等参数填充进去。

核心作用:准备刷新“任务单”

在旧版内核中,flush_tlb_info是一个Per-CPU 变量,每个 CPU 只有一个实例。get_flush_tlb_info的任务就是从这个 Per-CPU 实例中“借出”它,并填充参数。

static struct flush_tlb_info *get_flush_tlb_info(struct mm_struct *mm, unsigned long start, unsigned long end, unsigned int stride_shift, bool freed_tables, u64 new_tlb_gen) { struct flush_tlb_info *info = this_cpu_ptr(&flush_tlb_info); ... info->start = start; info->end = end; info->mm = mm; info->stride_shift = stride_shift; info->freed_tables = freed_tables; info->new_tlb_gen = new_tlb_gen; info->initiating_cpu = smp_processor_id(); return info; }

关键字段填充:

  • start/end:刷新的虚拟地址范围。如果end == TLB_FLUSH_ALL,表示全量刷新。

  • mm:目标地址空间。如果为NULL,表示内核空间的刷新,需要广播到所有 CPU。

  • stride_shift:步长位移,用于区分 4KB(PAGE_SHIFT)和 2MB(PMD_SHIFT)页面。

  • new_tlb_gen:TLB 世代号,用于远程 CPU 判断是否需要跳过刷新。

  • initiating_cpu:发起刷新的 CPU 编号。

并发保护机制

由于 Per-CPU 的flush_tlb_info是唯一实例,如果多个路径同时尝试获取它,就会导致数据竞争。因此,旧版内核要求所有 TLB 刷新路径全程禁用抢占,并通过一个调试计数器来检测重入:

#ifdef CONFIG_DEBUG_VM BUG_ON(this_cpu_inc_return(flush_tlb_info_idx) != 1); #endif

如果flush_tlb_info_idx的返回值不是 1,说明发生了重入(例如中断处理程序或机器检查异常中又发起了 TLB 刷新),内核会直接BUG()。

2026 年的重大演进:移回栈上

这个函数在 2026 年经历了一次重要重构,原因正是 Per-CPU 实例带来的副作用。

问题:TLB 刷新需要向远程 CPU 发送 IPI 并同步等待它们完成。当 CPU 数量多或目标 CPU 关闭中断时,这个等待过程可能长达数十毫秒。在此期间,发起刷新的 CPU必须保持抢占禁用,否则另一个任务可能在这个 CPU 上运行,并再次调用get_flush_tlb_info,覆盖掉正在使用的 Per-CPU 数据。这严重影响了实时性能(调度延迟)。

解决方案:将flush_tlb_info移回调用者的栈上,改为由调用者自己声明一个局部变量,然后通过get_flush_tlb_info(&info, ...)来初始化它。

// 新版调用方式 struct flush_tlb_info info; get_flush_tlb_info(&info, NULL, start, end, PAGE_SHIFT, false, TLB_GENERATION_INVALID);

收益:

  1. 允许在等待 IPI 期间启用抢占:因为每个调用者都有自己的info,不存在共享数据被覆盖的风险。

  2. 性能几乎没有损失:基准测试显示,栈上对齐版本与 Per-CPU 版本的延迟差异在测试噪声范围内(约 2.53 微秒/操作)。

  3. 移除flush_tlb_info_idx:不再需要重入检测计数器,代码更简洁。

调用关系

get_flush_tlb_info的调用者非常集中,主要是 TLB 刷新的几个入口:

调用者刷新类型
flush_tlb_mm_range()用户地址空间范围刷新
flush_tlb_kernel_range()内核地址空间范围刷新
arch_tlbbatch_flush()批量刷新(如munmap后)

这些函数在获取并填充info后,会调用flush_tlb_multi()或flush_tlb_func()来执行实际的刷新操作。

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

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

立即咨询