Add Linux-compatible /proc/self/smaps emulation - #259
Conversation
jserv
left a comment
There was a problem hiding this comment.
Run make indent before committing.
Thanks for the review. I’ve addressed all other review comments as well, including the dynamic-array and string-builder initialization/aliasing issues and the |
jserv
left a comment
There was a problem hiding this comment.
After responding to @cubic-dev-ai , squash commits and enforce rules described by https://cbea.ms/git-commit/ .
Sure, it's getting complicated when it comes to fork-safe. I'm working on it and trying to implement related book keepings. |
Generate Linux-shaped /proc/self/smaps and /proc/<pid>/smaps snapshots from tracked guest VMAs so Redis can complete its ARM64 COW safety check under elfuse. Add growable VMA/string infrastructure and fork-aware accounting with parser regression coverage.
Keep static-analysis checks and the smaps test matrix green after adding the new procfs emulation coverage.
Apply review feedback to the smaps emulation and its regression tests.
Grow formatted string storage safely and silence the Infer warning exposed by the smaps changes.
Avoid collisions when concurrent shared-memory tests create temporary names.
Keep concurrent shared-memory fixture setup consistent with repository formatting conventions.
Append live and shadow VMAs, then sort and merge once. This keeps fragmented maps and smaps snapshots from quadratic insertion work.
Apply repository formatting conventions to proc VMA snapshot calls.
Track whether each guest VMA existed at the fork snapshot so post-fork mappings are excluded from the synthetic Shared_Dirty compatibility signal. Propagate the metadata through fork IPC and memory-region transformations, and add a regression test for post-fork mappings.
Preserve VMA lineage across fork-split mappings and keep synthetic smaps accounting consistent with per-VMA fork state. Add file-backed mremap regression coverage and wire the tests into the build and documentation.
6309119 to
0fcc8f7
Compare
Apply consistent line wrapping in the memory syscall implementation and its mremap regression test without changing behavior.
|
I guess there are still corner cases and ways to improve the fork-safe memory statistics. However it's getting too complicated, maybe we can stop digging deeper and start reviewing at this point. Please take another look when you have a chance, Thanks. @jserv @Max042004 |
jserv
left a comment
There was a problem hiding this comment.
Correctness pass over the smaps emulation. Three findings inline. The new dynamic-array and string-builder utilities are careful (overflow-guarded growth, realloc-NULL handled, NUL kept), and the fork IPC carries the new VMA fields via the existing whole-region memcpy with the MAGIC bump, so no serialization gap there.
Two items left out of line, for the record:
-
mem.c:3770 (MAP_SHARED mremap): possible write-loss when the source is a MAP_SHARED file mapping with no live overlay. The aligned/overlay case is fine, since tearing the overlay down flushes dirty pages back to the file; the concern is only the non-overlay fallback, and it looks pre-existing rather than introduced here. Unresolved either way. Worth a targeted test (dirty a misaligned MAP_SHARED file mapping, mremap it, assert the file reflects the writes) before any change.
-
next_vma_id not serialized across fork: the child keeps next_vma_id == 0 while inherited regions carry large ids. Not a correctness bug, allocate_vma_id linear-scans live regions and never hands back an in-use id, so collisions cannot happen; the only cost is O(nregions) work per allocation in a fork child and a field documented as "last allocated" that is silently wrong there. Optional: set it to max(region.vma_id)+1 in the child where inherited_at_fork is stamped.
| { | ||
| split_regions_at_boundary(g, start); | ||
| split_regions_at_boundary(g, end); | ||
| int split_err = split_regions_at_boundary(g, start); |
There was a problem hiding this comment.
capture_region_snapshots is not failure-atomic. split_regions_at_boundary(start) commits its split in place (memmove + nregions++, plus a dup'd backing fd, lines 490-504); if the following split at end then fails with ENOMEM (region table full) or a dup failure, this returns the error with the start split already committed. The caller aborts the syscall, but the region table is left carrying a spurious boundary at start and holding one extra dup'd fd. This is not corruption (the two halves are metadata-equivalent) and not a leak (the fd is owned by the new region), but the operation reports failure after having mutated state, and the ignored guest_region_remove() return downstream at mem.c:3470 is only safe because these boundaries were pre-split here. Preflight/reserve both boundary splits before committing either, or roll back the start split when the end split fails.
Yes, that is exactly the direction of my current research. Beyond addressing corner cases in fork-safe memory statistics, the broader goal is to consolidate a kernel-less approach that provides a Linux system call compatibility layer while rigorously validating memory safety and futex correctness. The challenge is not only functional compatibility but also ensuring that the concurrency semantics remain equivalent to those expected by Linux applications. |
|
Thanks, let me check the comments. |
Preserve fork lineage and smaps consistency when restored regions receive new allocations. Flush shared-file contents before mremap removes source mappings. Make region-boundary preparation transactional so allocation or descriptor failures leave metadata unchanged. Add regressions for repeated post-fork allocations and misaligned moves. Cover PROT_NONE smaps output as well. Related: sysprog21#259
a8072f2 to
c4efc5e
Compare
|
I defer to @Max042004 and @henrybear327 for confirmation. |
Keep synthesized Pss_Dirty consistent with fork-inherited Shared_Dirty, and avoid flushing writable aliases when moving a read-only MAP_SHARED snapshot. Add regressions for both cases.
Keep failed reservation addresses visible to callers when munmap fails. This lets MAP_FAILED cleanup release still-live mappings instead of leaking them.
90e0745 to
76a80bd
Compare
Thank you for all your help. |
Fixes #258
Summary
Running
redis-serverunder elfuse currently fails during Redis's ARM64 copy-on-write safety check because Redis reads/proc/self/smaps, which elfuse does not provide with Linux-compatible contents. Redis treats the failed check as unsafe and exits to protect background saves.This PR adds synthetic
smapssupport so Redis can inspect guest VMAs and complete startup under elfuse.Implementation
/proc/self/smapsand/proc/<pid>/smapsfrom the tracked guest VMA snapshot.VmFlags.Shared_Dirtycompatibility signal for writable private anonymous mappings in fork children./proc/self/maps.smaps_rollupremain out of scope.Testing
make test-dynamic-array-host test-string-builder-host— passed.git diff --check— passed.test-proc-smapcompilation was attempted, but the local environment does not haveaarch64-linux-gnu-gcc.Compatibility notes
The synthetic values are derived from elfuse's tracked guest VMAs and fork state. Fields requiring host kernel page accounting are emitted as stable compatibility values and should not be interpreted as precise memory profiling data.
Summary by cubic
Adds Linux-compatible
/proc/self/smapsand/proc/<pid>/smapssoredis-serverpasses its ARM64 COW safety check and starts under elfuse. Smaps is fork-aware with stable VMA lineage, bounded snapshots, and safermremap/mmapfailure handling.New Features
VmFlags) for self and PIDs; share VMA collection with/proc/self/maps; build snapshots via append → sort+merge; cap by guest limits.inherited_at_forkand stablevma_id; propagate through fork IPC and memory ops; keepShared_Dirty/Pss_Dirtyconsistent and exclude post-fork mappings.dynamic-arrayandstring-builderutilities with host tests; add a generic smaps parser and regressions for fork tracking and EMFILEmremap.Bug Fixes
mremap: preserve VMA lineage after fork/restore; flush shared-file contents only when needed; avoid flushing writable aliases for read-onlyMAP_SHARED; roll back region splits on failure; coverPROT_NONE.mmapreservations soMAP_FAILEDcleanup can release still-live mappings./dev/shmfixture names to avoid cross-job collisions; fix string-builder capacity growth; keep CI/static analysis and the smaps test matrix green.Written for commit 76a80bd. Summary will update on new commits.