Reading the design — MAP_PRIVATE mmap of memory.bin as the CoW primitive, then optionally userfaultfd (v0.3 scaffolding per docs/design/userfaultfd.md) for live branching. The current code lands on MemoryBackend::File as default and MemoryBackend::Userfault is bail-only (crates/forkd-vmm/src/lib.rs:1035-1040).
Two related questions for the design discussion:
-
What's holding you back from defaulting Userfault for spawn, not just BRANCH? The prewarm flag (prewarm_scratch_dir) is explicitly there to compensate for the cold-cache penalty of MAP_PRIVATE — which userfaultfd dodges entirely because pages are served on demand. If the handler is implemented, would there be any reason to keep File as the default at all?
-
Why a per-child uffd handler socket rather than a daemon-wide one? The Userfault { handler_sock: PathBuf } shape in MemoryBackend (lib.rs:284-289) implies one socket per child. A single handler with a routing layer could amortize the metadata bookkeeping across all children of a tag — particularly relevant for the 100-children fanout numbers in the README. I'd expect the design doc to address this trade-off but couldn't find it.
I'm asking because I'm thinking about contributing to the uffd path for v0.3 and want to make sure I don't go in the wrong direction.
Reading the design —
MAP_PRIVATEmmap ofmemory.binas the CoW primitive, then optionallyuserfaultfd(v0.3 scaffolding perdocs/design/userfaultfd.md) for live branching. The current code lands onMemoryBackend::Fileas default andMemoryBackend::Userfaultis bail-only (crates/forkd-vmm/src/lib.rs:1035-1040).Two related questions for the design discussion:
What's holding you back from defaulting Userfault for spawn, not just BRANCH? The prewarm flag (
prewarm_scratch_dir) is explicitly there to compensate for the cold-cache penalty of MAP_PRIVATE — which userfaultfd dodges entirely because pages are served on demand. If the handler is implemented, would there be any reason to keep File as the default at all?Why a per-child uffd handler socket rather than a daemon-wide one? The
Userfault { handler_sock: PathBuf }shape inMemoryBackend(lib.rs:284-289) implies one socket per child. A single handler with a routing layer could amortize the metadata bookkeeping across all children of a tag — particularly relevant for the 100-children fanout numbers in the README. I'd expect the design doc to address this trade-off but couldn't find it.I'm asking because I'm thinking about contributing to the uffd path for v0.3 and want to make sure I don't go in the wrong direction.