Skip to content

fix(kernel): preserve user-return work and retire stopped TLB targets - #2511

Merged
fslongjin merged 2 commits into
DragonOS-Community:masterfrom
sparkzky:fix/mm-tlb-shootdown-context
Nov 3, 2026
Merged

fslongjin merged 2 commits into
DragonOS-Community:masterfrom
sparkzky:fix/mm-tlb-shootdown-context

Conversation

@sparkzky

@sparkzky sparkzky commented Oct 23, 2026 •

Copy link
Copy Markdown
Member

Faultable child-TID and rseq writes currently run in IRQ-off switch/return paths. Moving rseq work to an interruptible context also requires consuming its notification before processing: clearing it afterward can discard a migration notification published while updating the user CPU ID.

Publish child-TID work during fork and perform its best-effort write before signals/ptrace at the first user-return boundary. Remove the thread-lock check from every context switch. Consume NEED_RSEQ before enabling IRQs, and let notifications generated during the handler request another pass.

For x86 shootdowns, include Dying targets until their teardown finishes. After acquiring an irreversible Dead state, clear the CSD stack pointer before publishing completion. Keep master's IRQ-off inbound-service and lock-free claim protocol. Normal acknowledgement polling gains no state read; terminal checks reuse the existing 1024-spin slow path. Non-x86 target policy is unchanged.

Validation:

  • x86_64 default and mm_selftest+sched_selftest kernel builds; LoongArch64 build; RISC-V build/link and DragonStub installation.
  • FMT_CHECK=1 make fmt, including all-feature x86 Clippy.
  • 70 GTest executions in 2/4-vCPU feature guests, all executed with no failures or skips: user-return work, TLB, clone3, affinity, signal/fork and ptrace lifecycle.
  • 42 executed cases pass in the final 4-vCPU default guest; two feature-only fixtures explicitly skip there.
  • Negative controls restoring the rseq trailing clear and omitting CSD pointer retirement fail their respective tests; both fixes are restored.
  • New user-return suite is in whitelist and no_skip. Default ELF excludes the notification probe.

Performance: remove the per-switch thread lock and keep test probes out of production. Four-vCPU ABBA samples show no observed regression (pipe round trip 18,070.5 → 17,932 ns; fork/wait 524,324 → 512,827 ns). Two-vCPU runs include slower candidate medians and substantial variability under concurrent host workloads, including after host-CPU pinning; these results do not establish a reliable performance change.

The notification fixture exercises a real handler with deterministic migration-notification publication, not an actual CPU migration. The private CSD fixture verifies retirement/reuse, not a real CPU shutdown race. Terminal cancellation depends on Dead CPUs remaining non-restartable.

Copy link
Copy Markdown
Member

The original concern about enabling interrupts inside a caller-owned atomic section is valid. After rebasing locally and an independent subagent review, I am skipping this PR in its present form because it changes the shootdown completion contract without a safe, validated replacement:

  • !is_online_cpu() also means Dying. begin_shutdown_current_cpu() publishes Dying before running RCU teardown, so the target still performs memory accesses. Ending the synchronous wait at that point does not establish that stale translations/page-table references can safely be reclaimed. A verified terminal-state/ack protocol is needed.
  • irqoff_file_ptr and irqoff_file_len are independently published and read with Relaxed ordering. Concurrent writers/reporters can combine a pointer to a short filename with another filename's longer length. from_raw_parts and from_utf8_unchecked then have no valid bounds/UTF-8 proof. Publish a complete static Location atomically or use a coherent snapshot.
  • Recording an IRQ-off caller does not make its subsequent synchronous lock acquisition safe; the entry contract and callers need validation together. The current master already uses a ResourceMutex for page_table_edit, so the PR's claim that ordinary COW holds an IRQ-off page-table lock is outdated.

The historical integration job also stalled at ProcessVMTest.WriteToZombie for 300 seconds; this needs reproduction when validating a revised shootdown protocol. The independent review did not establish an ordinary IPI-reentrancy UAF, so I am not treating that as a confirmed finding. No local rebase was pushed and this PR was not merged. The old uprobe Dunitest assertion is already fixed by #2509.

@github-actions github-actions Bot added the test Unitest/User space test label Oct 23, 2026

@fslongjin fslongjin left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes requested. Please split the original IRQ-context/shootdown problem into an independently tracked issue and a focused PR that implements the complete root-cause fix across the initiator, callers, receiver, and CPU lifecycle. Establish and enforce the caller's interrupt/locking contract, preserve synchronous invalidation and resource-lifetime guarantees, and validate concurrent initiators and CPU shutdown races.

The current implementation stops waiting for CPUs that are merely Dying and constructs diagnostic strings from independently published pointer/length values. Both require correction. Diagnostic instrumentation should be a separate change with a coherent, memory-safe snapshot and a safe reporting context. Please provide before/after reproduction and adversarial tests; recording a contract violation alone does not complete the underlying bug fix.

sparkzky added a commit to sparkzky/DragonOS that referenced this pull request Oct 24, 2026
…initiators

Remove the temporary IRQ-enable/restore hack from the synchronous TLB
shootdown path. The initiator now runs with interrupts enabled (and
preemption disabled by the global flush lock), matching Linux
native_flush_tlb_multi(); the contract is documented and debug-asserted.

Callers that initiate shootdowns while writing user memory are fixed:

- exit_to_user_mode_loop: run Rseq resume with interrupts enabled. Its
  copy_to_user can fault on a COW page and must be able to shoot down;
  with IRQs disabled two initiators can deadlock on each other's IPI.
- Defer CLONE_CHILD_SETTID from the context-switch hook (IRQs disabled)
  to the return-to-user boundary, clearing the work flag after use.

CPU liveness: a Dying CPU may still execute and access page tables, so it
is a valid shootdown target; only a Dead target (which can never
acknowledge or touch memory again) ends the wait.

Refs: DragonOS-Community#2511, DragonOS-Community#2546
@sparkzky

Copy link
Copy Markdown
Member Author

已按 review 意见收敛/修正,本 PR 现在是“完整根因修复 + 契约校验”:

1. 发起方契约

  • 删除旧的“临时开中断再恢复”hack。发起同步 shootdown 现在要求 IRQs enabled + preemption disabled(FLUSH_TLB_GLOBAL_LOCK 提供 preempt disable),与 Linux native_flush_tlb_multi() 一致。
  • 在 check_shootdown_context() 中增加 debug 断言并文档化契约;不再从 IRQ-off 上下文里做 console 输出或构造诊断字符串。

2. 定位并修复所有已知的 IRQ-off 发起方
本地用 CI 镜像复现了 Dunitest 挂死(TlbShootdown.ForkCowNoStaleTlbLeak),并抓到了具体调用栈:

  • exit_to_user_mode_loop -> Rseq::handle_notify_resume -> copy_to_user:rseq 回写 CPU id 时在关中断上下文里触发 COW 缺页。现在 rseq resume 在开中断下执行。
  • switch_finish_hook -> write_one_to_user_protected:CLONE_CHILD_SETTID 在上下文切换钩子(IRQs off)里写用户内存。现在延迟到 return-to-user 边界、开中断执行,并正确清除 NEED_CHILD_TID 工作标志。
  • 修复前本地该测试记录到 16 次 IRQ-off shootdown;修复后为 0,ForkCowNoStaleTlbLeak 66ms 通过。

3. CPU 生命周期

  • target 集合包含 Dying CPU(它仍可能访问页表)。
  • 只有目标进入 Dead 才停止等待;Dying 必须继续等待其 ack。

4. 拆分

CI 已重新触发;本地用 CI 同款镜像跑 test_tlb_shootdown 通过,完整 Dunitest 正在本地复跑。

Signed-off-by: longjin <longjin@dragonos.org>
@fslongjin
fslongjin force-pushed the fix/mm-tlb-shootdown-context branch from c59aa23 to a28c1dd Compare November 3, 2026 12:51
@fslongjin fslongjin changed the title fix(mm): 删除 TLB shootdown 的临时开中断 hack,增加 liveness 与发起上下文校验 fix(kernel): preserve user-return work and retire stopped TLB targets Nov 3, 2026

Copy link
Copy Markdown
Member

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-03T13:00:18.586577Z a28c1dd Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

Signed-off-by: longjin <longjin@dragonos.org>
@fslongjin
fslongjin merged commit f1efcd1 into DragonOS-Community:master Nov 3, 2026
15 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a28c1dd948

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

normal/rlimit_data
normal/fork_mapping_holes

normal/user_return_work

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 将可选 fixture 与默认 no-skip 套件分离

在未启用 sched_selftest 的默认 x86_64 内核上,MigrationNotificationSurvivesRealResumeHandler 会因调试入口不存在而执行 GTEST_SKIP();但 runner/src/main.rs 中的 enforce_no_skip() 会将名单内二进制的任何 skip 改判为失败。因此,通过默认安装的 run_tests.sh 运行时,即使其余四项全部通过,整个 normal/user_return_work 仍会失败。应将特性专用 fixture 拆成独立二进制,仅在启用该特性的 CI 中强制禁止跳过,同时保留普通用例的默认 no-skip 约束。

Useful? React with 👍 / 👎.

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

Labels

Bug fix A bug is fixed in this pull request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants