Add Linux-compatible /proc/self/smaps emulation

Merged
SU
3mo ago
+5716-449

Fixes #258

Summary

Running redis-server under 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 smaps support so Redis can inspect guest VMAs and complete startup under elfuse.

Implementation

  • Generate /proc/self/smaps and /proc/<pid>/smaps from the tracked guest VMA snapshot.
  • Emit Linux-shaped VMA headers and the standard smaps fields, including VmFlags.
  • Preserve fork-aware COW information with a coarse Shared_Dirty compatibility signal for writable private anonymous mappings in fork children.
  • Share VMA collection and formatting logic with /proc/self/maps.
  • Replace the fixed maps-entry/output limits with checked growable array and string-builder utilities.
  • Add parser and regression coverage for smaps layout, field completeness, fork behavior, and larger VMA snapshots.
  • Document the synthetic smaps semantics and intentional limitations; exact host page residency and smaps_rollup remain out of scope.

Testing

  • make test-dynamic-array-host test-string-builder-host — passed.
  • git diff --check — passed.
  • Guest test-proc-smap compilation was attempted, but the local environment does not have aarch64-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/smaps and /proc/<pid>/smaps so redis-server passes its ARM64 COW safety check and starts under elfuse. Also standardizes FD-limit handling and adds descriptor-exhaustion regressions to make check.

  • New Features

    • Emit Linux-shaped smaps (headers, standard fields, VmFlags) for self and PIDs; reuse /proc/self/maps VMA collection; append then sort+merge once; cap by guest limits.
    • Track per-VMA fork state and stable vma_id; keep Shared_Dirty/Pss_Dirty consistent and exclude post-fork mappings; propagate via fork IPC and memory ops.
    • Add dynamic-array and string-builder utilities with host tests; add a smaps parser and fork/mremap regressions.
    • Introduce elfuse-limits.h for shared FD limits (FD_TABLE_SIZE, HOST_FD_RESERVE, HOST_NOFILE_MIN); test runners derive limits via tests/test-config.sh; tests/manifest.txt supports host_nofile=elfuse-minimum.
  • Bug Fixes

    • Harden fork-aware smaps and mremap: preserve VMA lineage across fork/restore; make region splits/moves transactional; flush shared files before removes; avoid flushing writable aliases for read-only MAP_SHARED; cover PROT_NONE.
    • Harden mmap/mremap failure paths: reserve FDs before teardown; keep EMFILE failures side-effect free; preserve smaps accounting and errno; preserve failed mmap reservation addresses; add descriptor- and table-exhaustion regressions; run the EMFILE regression in make check.
    • Use unique /dev/shm fixture names to avoid collisions in concurrent test runs.