Skip to content

Fault handler rebase - #89

Merged
fwsGonzo merged 9 commits into
masterfrom
fault_handler-rebase
Jul 29, 2026
Merged

Fault handler rebase#89
fwsGonzo merged 9 commits into
masterfrom
fault_handler-rebase

Conversation

@fwsGonzo

Copy link
Copy Markdown
Member

No description provided.

fwsGonzo and others added 9 commits July 29, 2026 08:48
PR #88 fixed reset_keep_all_work_memory resolving the master's copy-back
source through main_memory().safely_at(vaddr), which is only correct for
identity-mapped memory. File-backed mmap regions live at MMAP_PHYS_BASE
(32GB), so any recorded page backed there was restored from an unrelated
identity-mapped page -- in practice zeros -- and the fork came back from
reset with silently wrong contents. It shipped without a test.

The test maps a 4MB pattern file into a master, forks, writes to the
mapping, resets with reset_keep_all_work_memory and requires the pattern
back. It fails on the parent of #88 (reads 0x00, expected 0x5A) and
passes on #88.

mmap_backed_area only installs MMAP_PHYS_BASE-backed memory for the part
of the range that is 2MB-aligned and 2MB-sized; a smaller mapping falls
back to preadv into ordinary identity-mapped memory, where the bug does
not reproduce and the test would pass for the wrong reason. Hence the 4MB
file, the 2MB-aligned base, and the explicit page-table check that the
leaf really does resolve above MMAP_PHYS_BASE.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ter's live root

PR #88 correctly changed fork_reset to resolve the master's copy-back
source through the page tables, but it walks from main_memory().page_tables.
For a master with working memory that is the banked PML4 the master itself
executes on, whose entries have been redirected to bank pages holding
writes the master made *after* prepare_copy_on_write().

setup_cow_mode() deliberately roots forks at physbase + PT_ADDR to exclude
exactly those pages ("we use the fixed PT_ADDR directly in order to avoid
duplicating the memory banked page tables"). So a fork never sees the
master's post-prepare writes -- but after #88 a reset_keep_all_work_memory
reset did, restoring a state no fresh fork and no full reset produces.

Observable as "Fork w/working memory sanity checks" in tests/unit/fork.cpp:
after the master runs get_value() once, a fresh fork and a full reset both
see value == 0, while a keep-work-memory reset saw 1.

Pass the baseline root explicitly. readable_page_at() takes an optional
root (0 = memory.page_tables, unchanged for every other caller). #88's
actual fix is untouched: mmap regions are installed in the PT_ADDR-rooted
tables too, since that is the only view forks ever get.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@fwsGonzo
fwsGonzo merged commit afdcd83 into master Jul 29, 2026
4 checks passed
@perbu

perbu commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator

Post-merge notes from reading the diff (fast-agent will pick this up on the next rebase):

  1. reorder_snapshot_memory overflow path can corrupt the snapshot. Pages that don't fit after realignment are dropped with only a printf. Bank flattening means total movable bytes can exceed the original main-memory footprint, so it's reachable. And since branch (page-table) pages are placed last, overflow drops page tables first: translation.at(memory.page_tables) throws uncaught, or rewired entries dangle. The "unfaulted pages are the ones most likely trimmed" assumption doesn't hold with that ordering. Suggest hard-failing instead of warning.

  2. The load_snapshot_state madvise change affects all snapshot loads, not just reordered ones. MADV_RANDOM unbounded → MADV_SEQUENTIAL capped at a hard-coded 32 MiB. Snapshots with a hot set above that (our Python images) now leave the tail to random demand-faults — could regress non-reordered cold loads. Worth making the cap opt-in or per-MachineOptions.

  3. memory_reordered is saved/loaded but never consulted. Reordering breaks the vaddr==paddr identity mapping and moves the page tables off PT_ADDR, so a reordered snapshot used as a CoW master breaks fork_reset's baseline-root walk (59d6d1b). Fine if reordered snapshots are load-and-run only, but that constraint is implicit — a comment or an assert in prepare_copy_on_write would help.

  4. Minor: RetryException derives from MachineException, so any broad catch during a profiling run silently eats retries; and readable_page_at doesn't handle PDE64_PRESENTABLE, so host-side guest reads throw while profiling is active.

@fwsGonzo

Copy link
Copy Markdown
Member Author

Thanks, I forgot to run a review on it. These changes are from the before-times, and I found them in an old branch in a submodule on this machine. It was important to get them in before they got lost again!

I'll make a review as well and fix the issues already found

@perbu
perbu deleted the fault_handler-rebase branch July 30, 2026 07:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants