tlb finish_asid_transition

发布时间:2026/10/2 13:53:44
tlb finish_asid_transition
finish_asid_transition是 AMD 广播 TLB 失效Broadcast TLB Invalidation补丁集中的关键同步函数。它的核心任务是在完成一次广播 TLB 刷新后确认所有正在运行该进程的 CPU 都已经切换到了新的全局 ASID然后清除“ASID 过渡中”标志。核心作用确认过渡完成当内核为某个多线程进程分配全局 ASID 后该进程进入一个过渡期部分 CPU 可能还在使用旧的本地 ASID而另一部分 CPU 已经加载了新的全局 ASID。在这个过渡期内所有 TLB 刷新都必须走广播路径而非基于 IPI 的精确刷新以确保仍在用旧 ASID 的 CPU 也能被正确刷新。finish_asid_transition负责在过渡期结束时“收尾”遍历mm_cpumask中的所有 CPU确认它们都在使用全局 ASID然后清除mm-context.asid_transition标志宣告过渡完成。代码逻辑解析static void finish_asid_transition(struct flush_tlb_info *info) { struct mm_struct *mm info-mm; int bc_asid mm_global_asid(mm); int cpu; if (!READ_ONCE(mm-context.asid_transition)) return; for_each_cpu(cpu, mm_cpumask(mm)) { /* * The remote CPU is context switching. Wait for that to * finish, to catch the unlikely case of it switching to * the target mm with an out of date ASID. */ while (READ_ONCE(per_cpu(cpu_tlbstate.loaded_mm, cpu)) LOADED_MM_SWITCHING) cpu_relax(); if (READ_ONCE(per_cpu(cpu_tlbstate.loaded_mm, cpu)) ! mm) continue; /* * If at least one CPU is not using the global ASID yet, * send a TLB flush IPI. The IPI should cause stragglers * to transition soon. */ if (READ_ONCE(per_cpu(cpu_tlbstate.loaded_mm_asid, cpu)) ! bc_asid) { flush_tlb_multi(mm_cpumask(info-mm), info); return; } } /* All the CPUs running this process are using the global ASID. */ WRITE_ONCE(mm-context.asid_transition, false); }关键步骤快速退出如果asid_transition已经为 false说明过渡早已完成直接返回。遍历 CPU对于mm_cpumask中的每个 CPU检查它当前加载的 ASID 是否为全局 ASIDbc_asid。等待上下文切换完成如果某个 CPU 正处于上下文切换中loaded_mm LOADED_MM_SWITCHING函数会自旋等待。这是为了防止一种罕见但危险的竞态CPU 正在切换到这个进程但使用的是过期的 ASID。等待切换完成后再判断它最终加载的是哪个 ASID。发现“掉队者”如果某个正在运行该进程的 CPU 仍在使用非全局 ASID函数会发送一次 TLB 刷新 IPIflush_tlb_multi然后直接返回不清除asid_transition标志。注释解释说“IPI 应该会让掉队者很快完成过渡。”下一次广播 TLB 刷新时finish_asid_transition会再次被调用重新检查。清除标志只有当所有 CPU 都使用全局 ASID 时才通过WRITE_ONCE将asid_transition置为 false宣告过渡正式完成。调用关系与设计意图broadcast_tlb_flush() └── finish_asid_transition() // 在广播刷新完成后调用finish_asid_transition由broadcast_tlb_flush调用后者在处理flush_tlb_mm_range时如果进程拥有全局 ASID就走广播路径。这个函数的“返回而不清标志”设计非常巧妙它把过渡完成的确认与正常的 TLB 刷新流程解耦。过渡的完成不依赖于某一次特定的刷新操作而是通过“检查-发送 IPI-再次检查”的循环逐步收敛。如果某次检查发现有 CPU 未跟上就发 IPI 推它一把然后等下一次广播刷新时再检查。这种设计避免了在 TLB 刷新路径中引入复杂的等待或同步逻辑同时保证了最终一致性。