尧图精选

tlb switch_mm_irqs_off

🕒 发布时间:2026/10/2 20:47:50 📁 来源:尧图网络
switch_mm_irqs_off是 x86 架构中进程地址空间切换的最终执行者。它是switch_mm在中断关闭IRQs off上下文中的变体也是现代内核中真正干活的函数。核心职责加载新页表并协调 TLB 与缓解措施当调度器决定运行一个新任务时context_switch会调用switch_mm_irqs_off。它需要完成三件大事加载新地址空间的页表到 CR3决定并执行必要的 TLB 刷新协调投机执行缓解措施IBPB、L1D 刷新核心执行流程根据内核源码其逻辑可概括为以下几个关键阶段1. 快速路径同一地址空间if (next real_prev) { /* 同一个 mm通常直接返回无需切换 CR3 */ ... return; }如果next和当前加载的mm相同例如同一进程内的线程切换函数会走快速路径仅更新 LDT 等少量状态避免昂贵的 CR3 重载和 TLB 刷新。2. 为新 mm 选择 ASID 并决定是否刷新new_asid choose_new_asid(next, next_tlb_gen, need_flush);这是 PCID/ASID 机制的核心choose_new_asid遍历当前 CPU 的 6 个 ASID 槽位判断next是否在缓存中。如果命中且tlb_gen最新则need_flush false可以复用 TLB 条目否则需要分配新槽位并刷新。3. 执行 CR3 加载if (need_flush) { this_cpu_write(cpu_tlbstate.ctxs[new_asid].ctx_id, next-context.ctx_id); this_cpu_write(cpu_tlbstate.ctxs[new_asid].tlb_gen, next_tlb_gen); load_new_mm_cr3(next-pgd, new_asid, lam, true); trace_tlb_flush(TLB_FLUSH_ON_TASK_SWITCH, TLB_FLUSH_ALL); } else { load_new_mm_cr3(next-pgd, new_asid, lam, false); trace_tlb_flush(TLB_FLUSH_ON_TASK_SWITCH, 0); }load_new_mm_cr3负责构建包含 PCID 的 CR3 值并写入硬件。如果need_flush为真还会更新ctxs[]槽位的元数据。4. 更新mm_cpumask并协调缓解措施/* 将当前 CPU 加入新 mm 的掩码 */ cpumask_set_cpu(cpu, mm_cpumask(next)); /* 条件化执行 IBPB / L1D 刷新 */ cond_mitigation(next);cond_mitigation是你在之前分析过的函数负责根据任务标志执行 IBPB 和 L1D 刷新。5. 清理旧 mm 的掩码if (real_prev ! init_mm) cpumask_clear_cpu(cpu, mm_cpumask(real_prev));与switch_mm的关系在较新的内核中switch_mm通常是一个简单的包装函数void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk) { unsigned long flags; local_irq_save(flags); switch_mm_irqs_off(prev, next, tsk); local_irq_restore(flags); }switch_mm负责保存中断状态并调用switch_mm_irqs_off而后者在中断已关闭的上下文中执行实际的切换逻辑。这种拆分允许调度器在已经关闭中断的情况下直接调用switch_mm_irqs_off避免不必要的开关中断开销。性能关键路径switch_mm_irqs_off是内核中最频繁执行的性能关键路径之一。每次进程切换都会经过它因此代码中充斥着likely()/unlikely()分支提示、静态键static keys和 Per-CPU 缓存以最小化开销。l1d_flush_evaluate、cond_mitigation、cr4_update_pce_mm等函数都是在这个路径上被调用的。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →