Skip to content

mm: 建立 TLB shootdown 发起方的 IRQ/锁契约并修复 COW 缺页调用点 #2546

Open

Description

@sparkzky

背景

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 fix(kernel): preserve user-return work and retire stopped TLB targets #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 违规记录/上报)单独实现,使用一致的内存安全快照与安全上报上下文。

关联

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions