## 背景 `flush_tlb_mm_range()` / `flush_tlb_kernel_range()` 通过 `FLUSH_TLB_GLOBAL_LOCK` + 每目标 CPU 的 CSD 槽同步等待所有目标核 ack。该协议要求发起方: - 已关闭抢占(`SpinLock` 自带 `preempt_disable`),且 - **中断保持开启**,从而在等待期间仍能响应其它 CPU 发来的 `FlushTLB` IPI。 旧实现用「临时打开中断再恢复」的 hack 掩盖了违反该契约的调用方。删除 hack 后,IRQ-off 调用方会带来两个问题: 1. 该 CPU 等待 ack 时无法响应其它 CPU 的 shootdown;若两个 IRQ-off CPU 互相等待,即永久死锁。 2. IRQ-off 调用方在 `FLUSH_TLB_GLOBAL_LOCK` 上自旋时,无法响应持锁者的 IPI,持锁者又在等它 ack,同样死锁。 ## 已观测证据 - PR #2511 的 Dunitest 在 `FuseExtended.ReadOnlyAtomicTruncateRejectsRunningExecutableBeforeOpen` 处 120s 无输出(run 39886826054)。 - 同一内核在本地跑 `DUNITEST_PATTERN=fuse` 时,诊断记录到 16 次 IRQ-off shootdown,全部来自 COW 缺页路径 `kernel/src/mm/fault.rs:1223/1240`(`do_wp_page()` 持 `page_table_edit` 后同步 flush)。 - 该测试本身在无竞态时 46ms 通过,说明是时序相关的死锁而非确定性失败。 ## 需要完成 - [ ] 明确并文档化发起方契约:`irq_enabled && preempt_disabled`,禁止在 IRQ-off 临界区发起同步 shootdown。 - [ ] 修复 COW 缺页路径:在进入 `page_table_edit()`/同步 shootdown 前确保中断已开启,或改为退出 IRQ-off 区后 gather + flush;必须保留同步失效与页表页生命周期保证。 - [ ] 审计所有 `flush_tlb_*` 调用方(fault、munmap、mprotect、mremap、exec、uprobe、fuse、remote access)。 - [ ] CPU 生命周期:目标过滤必须包含 `Dying`(仍可能访问内存),只允许在目标 `Dead` 后停止等待。 - [ ] 增加并发发起者与 CPU shutdown 竞争的回归测试(两 CPU 同时 COW fault + shootdown)。 - [ ] 可观测性(IRQ-off 违规记录/上报)单独实现,使用一致的内存安全快照与安全上报上下文。 ## 关联 - PR #2511 - 诊断代码将拆分为独立变更。
Activity
fix(mm,proc): enforce the TLB shootdown IRQ contract and fix IRQ-off …