
use_global_asid是 x86 架构中为满足条件的多线程进程分配全局 ASID 的加锁入口函数。它由consider_global_asid调用负责在并发环境下安全地完成“检查-分配-标记”的完整流程。核心作用安全地分配并标记全局 ASID这个函数的核心目标是为一个已经满足“活跃 CPU 数”阈值的进程分配一个全局 ASID并将其记录到mm-context中使该进程在所有 CPU 上使用相同的 PCID从而能够利用 AMD INVLPGB 等硬件辅助的广播 TLB 失效机制。代码逻辑解析static void use_global_asid(struct mm_struct *mm) { guard(raw_spinlock_irqsave)(global_asid_lock); /* This process is already using broadcast TLB invalidation. */ if (READ_ONCE(mm-context.global_asid)) return; /* The last global ASID was consumed while waiting for the lock. */ if (!READ_ONCE(global_asid_available)) { VM_WARN_ONCE(1, Ran out of global ASIDs\n); return; } /* * The transition from IPI TLB flushing, with a dynamic ASID, * and broadcast TLB flushing, using a global ASID, uses memory * ordering for synchronization. * * This code sets asid_transition first, before assigning the * global ASID. */ WRITE_ONCE(mm-context.asid_transition, true); WRITE_ONCE(mm-context.global_asid, get_global_asid()); }关键步骤获取全局锁guard(raw_spinlock_irqsave)(global_asid_lock)确保同一时刻只有一个 CPU 在修改全局 ASID 分配状态。重复检查如果mm-context.global_asid已经非零说明该进程已经拥有全局 ASID可能在等锁期间被其他线程分配了直接返回。可用性检查如果global_asid_available为 0说明全局 ASID 空间已耗尽发出警告并返回。这是consider_global_asid中检查的“双重保险”。设置转换标志先将mm-context.asid_transition设为true。这个顺序至关重要——它确保后续的 TLB 刷新代码在观察到global_asid非零时也能看到asid_transition为真从而正确处理从动态 ASID 到全局 ASID 的过渡。分配并记录 ASID调用get_global_asid()获取一个全局 ASID并写入mm-context.global_asid。从此刻起该进程在所有 CPU 上都会使用这个统一的 PCID。调用关系与设计意图consider_global_asid() // 定期检查条件满足时触发 └── use_global_asid() // ← 你问的函数加锁分配 └── get_global_asid() // 实际从位图分配consider_global_asid通过(current-pid 0x1f) ! (jiffies 0x1f)的采样机制每隔一段时间才检查一次避免频繁的锁竞争和 CPU 掩码遍历。一旦条件满足use_global_asid就负责在锁保护下完成最终的分配。已知问题与修复搜索结果记录了一个重要的边界计算 bugglobal_asid_available的初始值被设为MAX_ASID_AVAILABLE - TLB_NR_DYN_ASIDS - 1这少算了一个 ASID。由于位图大小是MAX_ASID_AVAILABLE有效范围[TLB_NR_DYN_ASIDS, MAX_ASID_AVAILABLE-1]的实际大小应该是MAX_ASID_AVAILABLE - TLB_NR_DYN_ASIDS。这个修复确保了 ASID 空间的完整利用。此外READ_ONCE在持有global_asid_lock时被一些开发者认为是不必要的因为所有修改都在锁保护下进行。但这些标记作为一种防御性编程习惯被保留了下来。