Skip to content

LATX, fix: Release SMC backing after the last mapping disappears - #476

Open
LaurenIsACoder wants to merge 1 commit into
lat-opensource:masterfrom
LaurenIsACoder:latx-smc-backing-lifetime
Open

LATX, fix: Release SMC backing after the last mapping disappears#476
LaurenIsACoder wants to merge 1 commit into
lat-opensource:masterfrom
LaurenIsACoder:latx-smc-backing-lifetime

Conversation

@LaurenIsACoder

@LaurenIsACoder LaurenIsACoder commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Scope

Based on upstream bfe17ae7c1. Replace the append-only, process-global SMC memfd allocator with one backing file per converted host page. Close the descriptor after creating the guest and shadow mappings; the kernel retains the backing while any mapping, including a fork descendant's mapping, still owns it.

This prevents unmapped pages from retaining their contents in an ever-growing open memfd. It does not punch holes or truncate backing that a child may still use. Preparatory memfd/ftruncate/shadow-mmap failures clean up and use the existing fallback; guest MAP_FIXED failure remains fatal because the original mapping may already have been removed. Handle fd 0 and do not retry Linux close(EINTR).

The default LATX_SMC=0 is unchanged. Per-page memfd/ftruncate/close operations have an unmeasured throughput cost when this optional shared-backing mode is enabled; this is a resource-lifetime fix, not a speedup claim.

Author self-review and combined validation

The actual published diffs were reviewed individually and checked against the local candidates. Follow-up corrections were folded into their existing commits; author/sign-off metadata updates preserved the per-PR source trees. The series remains six commits across #472, #473, #474, #475 and #476.

All five branches merge without conflicts on bfe17ae7c1. The combined source tree 80aaaaf13688387640f528d1c0bccb6a800f8d6e builds and passes 33/33 lat-pr-fast tests. On that combined binary, the 500-cycle KZT unload and retained-handle checks, 520-cycle SMC/fork checks, and 512 successful TSYNC operations alongside thread creation also complete successfully. A tests-disabled configuration registers no tests.

The integration suite still reports 27 skips, including after selecting the available guest sysroot with LATX_X86_64_SYSROOT: 25 require clang and two require the x86 cross compiler. These are not passes. This author self-review does not substitute for the upstream CI matrix, maintainer review or real-application acceptance.

Validation

LoongArch64, GCC 15.3, x86_64-linux-user, LAT O1, KZT compiled in, release:

./configure --target-list=x86_64-linux-user --enable-latx --optimize-O1 \
  --extra-ldflags=-ldl --enable-kzt --enable-tests --disable-docs \
  --disable-werror --meson=meson
ninja -C build -j2 all meson-test-prereq
env -u LAT_LD_PREFIX meson test -C build --no-rebuild \
  --suite lat-pr-fast --print-errorlogs --num-processes 2
env -u LAT_LD_PREFIX meson test -C build --no-rebuild \
  --suite latx-integration --print-errorlogs --num-processes 2
  • Isolated PR branch: 25/25 lat-pr-fast passed.
  • Maintained production-body regression uses real memfd/mmap/fork for 1,024 lifecycles, alias permissions, parent-unmap/child-use, fd 0, close(EINTR) and allocation/fatal-map failure cleanup. The original allocator fails the no-retained-fd check. ASan/UBSan runs pass in debug and NDEBUG configurations.
  • Actual x86 guest code performed 520 map/execute/self-modify/unmap cycles, checking results 1 then 2 with LATX_AOT=0, LATX_KZT=0, LATX_SMC=2. The final live sample has two SMC mappings and no retained SMC descriptor; after unmap it has zero mappings. After fork and parent unmap, the child still executes result 2, writes the code and executes result 3, then exits successfully. The LATX_SMC=0 control also succeeds.
  • Integration suite: 27 skipped (exit 77) because the configured guest-building environment is unavailable (missing clang and the suite's default guest sysroot). Skips are not passes; broader guest compatibility and enabled-mode performance remain gates.

Independent of the other memory-lifetime PRs. No installed runtime replacement or application restart.

The process-global SMC memfd grows monotonically and retains backing for
pages whose guest and shadow mappings have already disappeared. Truncating
that file would also damage mappings still owned by fork descendants.

Use one backing file per converted host page and close its descriptor after
creating the guest and shadow mappings. The kernel retains the backing
until its last mapping disappears, including mappings inherited by a child.
Clean up preparatory failures and use the existing fallback; a failed guest
MAP_FIXED remains fatal because the original mapping may already be gone.
Handle fd 0 and do not retry Linux close(EINTR).

Add real memfd/mmap/fork regressions for aliasing, child ownership and
failure cleanup. The old allocator fails the retained-descriptor check;
the fixed branch passed 25 lat-pr-fast tests and sanitizer checks. A
520-cycle guest SMC workload also preserved child execution after parent
unmap. Unavailable guest integration tests were skipped.

Keep LATX_SMC=0 as the default. Per-page file creation has an unmeasured
throughput cost when shared backing is enabled.

Signed-off-by: Hanlu Li <heuleehanlu@gmail.com>
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.

1 participant