Files
erofs-freebsd-out-tree/docs/pre11-completion-and-smoke.md
T
2026-08-18 09:20:44 +02:00

18 KiB

Pre11 Completion and Smoke Report

Status

Pre11 is complete for its approved mechanical maintenance scope.

  • Final implementation commit tested: 040fc69025c5031436205c3acd421be1d95fe86b
  • Final repo-pre-11 tree: f0cca92670c76ab13cc5b9353d5aeb993effa6e2
  • Final repo-pre-11/src tree: c4aac4d69cb25a4b049239d0c1f422dcb89465d6
  • Static review: ACCEPT, with no P0-P3 findings in the included changes
  • FreeBSD KLD build: PASS, using WITH_ZSTDIO=0
  • Targeted plain/LZ4/LZMA QEMU smoke: PASS
  • Full feature test and test_all.py: NOT RUN

This report does not claim full feature validation. Pre11 deliberately contains mechanical naming, responsibility, dead-scaffolding, file-layout, and cleanup changes that could be reviewed for behavioral equivalence and then covered by a focused build and smoke run. Behavior changes requiring purpose-built fixtures remain deferred.

Snapshot and Planning

Pre11 was created from the completed Pre10 tree in:

0483dcb41c2a980badb829ff4d17361bd1fec930
snapshot: create repo-pre-11 from repo-pre-10

At the snapshot boundary, repo-pre-10/src and repo-pre-11/src were both:

ec684d8dbd7662070234da1fe947aba48a293db8

The executable Pre11 plan was added in:

9ad1fa0cf8ba251b574da033bf0c9fad83acaa38
docs: add pre11 execution plan

The original plan included several candidates that would have changed visible filesystem behavior. An independent boundary review narrowed the release in:

c89c228ac1817cfd0337905b39247245eaa67f3b
docs: narrow pre11 execution boundaries

The narrowed scope retained only work that could preserve control flow, errno, on-disk interpretation, vnode and GEOM ownership, iterator order, decompressor semantics, and cache lifetime. The following candidates were removed from implementation because honest validation would require targeted feature tests:

  • root vnode type rejection;
  • zero-length mapping behavior in the UIO reader;
  • header-only xattr semantics;
  • duplicate or missing device.N behavior;
  • direct propagation of vnode_create_vobject() errors;
  • broad map, inode, directory, and name-lookup interface reshaping.

This narrowing allowed Pre11 to remain a comparatively large maintenance release without mixing low-risk structural alignment with unvalidated semantic changes.

Batch A: Type and Vocabulary Alignment

Commit:

b4e38c9fb15df127470d70bc144404f1f3afa2af
pre11: align mount and device helper vocabulary

Exact changes:

  • renamed struct erofs_mount.block_bits to blkszbits across its consumers;
  • renamed the private erofs_fill_map_dev() helper to erofs_fill_from_devinfo();
  • added the Batch A implementation report.

Linux-maintenance benefit:

  • blkszbits matches established EROFS vocabulary and makes comparisons with Linux mount geometry code more direct;
  • erofs_fill_from_devinfo() describes the same responsibility as the Linux helper without importing Linux block-device objects into FreeBSD.

BSD invariants retained:

  • field type, width, units, expressions, overflow handling, and structure layout were unchanged;
  • the helper remained a private FreeBSD device-map field filler;
  • GEOM provider selection, range checks, flat-device behavior, errno, and physical I/O remained unchanged;
  • no broad or search-driven integer type replacement was performed.

Static checks confirmed 48 intended block_bits replacements, zero remaining old identifiers, four helper-name replacements, zero stale helper references, and a source diff containing only the approved identifier changes.

Batch B: Vnode Operation Scaffolding

Commit:

67625d3afebb9142e69b19afd08cdfc1d2adaac5
refactor: clean up vnode operation scaffolding

Exact changes:

  • removed the unused EROFS_MOUNT_XATTR_USER option bit;
  • removed the zero-consumer erofs_node.vnode member and its only assignment;
  • grouped VOP declarations and erofs_vnodeops initializers by responsibility;
  • added the Batch B implementation report.

Linux-maintenance benefit:

  • removes misleading compatibility-shaped state that had no consumer;
  • presents vnode operations in a responsibility-oriented order that is easier to compare with upstream filesystem responsibilities while retaining the native FreeBSD operation table.

BSD invariants retained:

  • no VOP function definition or registration changed;
  • erofs_vnodeops retained 24 unique field=value entries;
  • erofs_fifoops retained 14 unique entries and its original sequence;
  • fifo_specops, vnode locking, hash insertion, reclaim, pager behavior, and vnode_create_vobject() errno translation were unchanged.

The removed symbols had no reads, address consumers, initializer dependencies, offset consumers, or external ABI use.

Batch C: ACL Parsing Responsibilities

Commit:

a86b5cac4d193d131de8870bca4132fdc881f992
erofs: split ACL parsing responsibilities

Exact changes:

  • extracted private erofs_posix_acl_from_xattr() from erofs_get_acl();
  • changed the private mode fallback helper to receive the inode mode directly;
  • left xattr acquisition and all FreeBSD VOP/UIO responsibilities in the caller;
  • added the Batch C implementation report.

Linux-maintenance benefit:

  • separates wire-format ACL parsing from filesystem acquisition and VOP glue, matching the upstream responsibility split more closely;
  • gives maintainers a bounded parser to compare without introducing Linux ACL objects, RCU, xattr handlers, or inode lifecycle assumptions.

BSD invariants retained:

  • mount-option checks, ACL type validation, default-ACL directory checks, namespace selection, both erofs_getxattr() stages, UIO setup, and ENOATTR fallback remain in erofs_get_acl();
  • parser validation order, positive errno, tag phases, duplicate ID checks, UINT32_MAX handling, partial ACL writes, and final acl_posix1e_check() ordering remain unchanged;
  • input storage remains caller-owned stack memory, with no new allocation or cleanup path;
  • erofs_xattr_load_body() and the known header-only xattr behavior were not changed.

Static comparison confirmed equivalent branch, error, phase-transition, and ACL-population behavior.

Batch D: LZ4 Backend File Responsibility

Commit:

e631e33a1b8c053ebcb2d737af33e363cba48b34
erofs: align LZ4 backend file responsibility

Exact changes:

  • renamed src/lz4.c to src/decompressor_lz4.c;
  • updated the Makefile source entry;
  • updated current architecture documentation references;
  • added the Batch D implementation report.

Linux-maintenance benefit:

  • makes the filename communicate that the translation unit is the LZ4 codec backend beside decompressor_lzma.c, decompressor_deflate.c, and decompressor_zstd.c;
  • reduces unnecessary file-layout differences when maintainers inspect codec implementations across the independent Linux and FreeBSD repositories.

BSD invariants retained:

  • Git identified a 100% rename;
  • the old and new source blobs are both 2cc19f5eb0c283e12ba0a3a4334b8817a1686888;
  • function bodies, request ABI, descriptor registration, input/output bounds, partial decode behavior, and error normalization were unchanged;
  • historical reports and historical test evidence were not rewritten.

Batch E: Mount Device Argument Cleanup

Commit:

040fc69025c5031436205c3acd421be1d95fe86b
erofs: consolidate mount device argument cleanup

Exact changes:

  • consolidated caller-owned copied device.N argument release into one out_args exit in erofs_mount();
  • removed two impossible NULL checks immediately following M_WAITOK | M_ZERO allocations;
  • added the Batch E implementation report.

Linux-maintenance benefit:

  • makes mount setup ownership and cleanup easier to audit by reducing repeated release sites;
  • removes defensive branches that contradict the FreeBSD M_WAITOK contract, keeping BSD-specific allocation behavior explicit instead of emulating a nullable Linux allocation path.

BSD invariants retained:

  • operation order remains parse, filter, get option, open primary, update I/O size, mount setup, free copied arguments, publish mounted-from, and statfs;
  • parse failure still returns before caller ownership exists;
  • out_args releases only copied arguments and never releases primary;
  • erofs_mountfs() still takes ownership of primary at entry;
  • erofs_mountfs(), erofs_sb_free(), reverse external-device cleanup, errno, and mount error text are unchanged;
  • duplicate and missing external-device slot behavior remains deferred.

Static Review

Independent reviews were performed after the individual batches and again over the complete source range from 0483dcb through 040fc690.

The final review found no P0-P3 issue in the included Pre11 source changes and accepted all five batches. It confirmed:

  • the source changes were confined to the approved Batch A-E paths;
  • no deferred behavior fix entered the source;
  • old identifiers had no stale consumers and new private helpers had unique definitions and expected call counts;
  • both VOP vectors retained the same registration mappings;
  • ACL acquisition, parsing, fallback, errno, and partial-write behavior were preserved;
  • the LZ4 backend was a byte-identical rename and the Makefile contained the new filename once;
  • mount cleanup retained error order and GEOM ownership;
  • uncompressed mapping interfaces, directory/name lookup, decompressor request ABI, LZMA cache policy, disk structures, and Linux reference sources were not changed;
  • git diff --check passed and the implementation worktree was clean before runtime validation.

The final source delta from the snapshot contains 202 insertions and 188 deletions across ten source paths, including the 100% LZ4 file rename. Much of that textual delta is identifier replacement, declaration/vector reordering, or moved ACL parser code rather than new behavior.

First Smoke Attempt: Infrastructure Failure

Evidence directory:

/work/tests-dev/temp/pre11-smoke-final-20260813T122923Z

Result: FAIL, specifically an infrastructure failure before DUT transfer or execution.

The guest reached FreeBSD and two SSH identity probes succeeded, but the first runner opened an SSH ControlMaster using a detached invocation. The open command returned success and created the control socket, then the master terminated or lost its connection before the immediate health check. The check failed with:

Control socket connect(.../control.sock): Connection refused

The test stopped before source transfer, KLD build, module load, or any EROFS mount. Therefore this attempt is not a PASS, but it is also not evidence of a Pre11 build or driver failure. Its source archive SHA was:

5bbffb101364f350fe1a3771b6f018bc10a68785d8c55cc2a186273a074e9182

The owned QEMU stopped, port 10043 was released, its overlay was removed, the base image remained unchanged, and the retained guard VM remained reachable. The run's cleanup status was nonzero only because closing the already-dead ControlMaster returned an error.

Corrected Smoke Retry

Evidence directory:

/work/tests-dev/temp/pre11-smoke-retry-final-20260813T124214Z

Result: PASS.

The retry used an SSH master process in normal foreground mode but launched it in the runner shell background, without ssh -f. The runner captured the real master PID, repeatedly required both kill -0 and ssh -O check to succeed, and refused to transfer sources unless the master remained alive. Long build work ran inside the guest with a completion sentinel, so one long SSH command was not treated as the build lifetime.

Tested identities:

commit:            040fc69025c5031436205c3acd421be1d95fe86b
repo-pre-11 tree:  f0cca92670c76ab13cc5b9353d5aeb993effa6e2
src tree:          c4aac4d69cb25a4b049239d0c1f422dcb89465d6
source archive:    179b80365c26295770afab58f1209ae3fffd73182ada0bcf97ea027904f781e9
guest:             FreeBSD 15.0-RELEASE-p8

The archive hashes differ between attempts because separately generated gzip archives are not required to be byte-reproducible. Both identity files name the same committed repository and source trees; only the passing retry is used as runtime evidence.

Build and Module Lifecycle

The committed repo-pre-11 archive was transferred to the disposable guest, validated there, extracted, and built with:

make WITH_ZSTDIO=0

Results:

  • guest build return code: 0;
  • erofs.ko SHA256: 77ce41bff5cb7d7c934dd9dba20ba06c20b660ad15ebfc4210f86f6473dffbf7;
  • kldload /root/pre11-smoke/erofs.ko: success;
  • kldstat -n erofs: success, reporting erofs.ko loaded;
  • all smoke mounts and md providers were released;
  • kldunload erofs: success;
  • the post-unload kldstat -n erofs check confirmed the module was absent.

WITH_ZSTDIO=1 was not built and is not claimed as tested.

Smoke Cases

Each case used an independently attached vnode-backed md provider, required a successful EROFS mount to be visible in mount -p, computed the complete target file hash, then unmounted and detached the provider before the next case.

Case Target SHA256 Elapsed Provider Result
Plain 056f8f7585667dc695e2edf936deaf84cfee0f88671ba6cd5be22ce890763433 0 s md70 PASS
LZ4 3ff012b76087c4da65ce0b69813a76f47ea367e95782edf8b8cd6cd3ec4d1880 5 s md71 PASS
LZMA ddda39737f0f6093e828a032ec161511fefbb1fa361bc6cbffdbc91e48e4c461 2 s md72 PASS

The LZMA case hashed the complete file. No timeout, mount failure, hash mismatch, unmount failure, or md detach failure occurred.

Kernel Messages and Cleanup

The runner captured dmesg before loading the module and after all smoke cases. The delta contained no EROFS error, decompression failure, panic, or assertion; the suspect-output file is empty.

Cleanup evidence records:

qemu_stopped=1
port_released=1
overlay_removed=1
base_mode_after=444
base_sha_after=67f359621f23a1d745f0889370cbb99a096cee3e99a0b2f3bb18fc7a91bf6fef
guard_unchanged_and_reachable=1
body_rc=0
cleanup_rc=0

The test owned only port 10044, its QEMU PID, its ControlMaster PID, and its overlay. All were closed or removed. The permanent base image was never booted directly and retained mode 0444 and its original SHA256. The retained guard VM PID 26318 kept start time 1102996924, an identical command line, and a reachable forwarded SSH port at 9222.

Feature-Test Decision

No feature test and no test_all.py run was performed.

That decision is appropriate for the included Pre11 scope because:

  • Batch A changed only private identifiers;
  • Batch B removed proven dead state and reordered designated VOP initializers without changing their mappings;
  • Batch C mechanically moved parser statements while retaining inputs, outputs, writes, error order, and ownership;
  • Batch D was a byte-identical file rename;
  • Batch E consolidated one caller-owned cleanup action and removed checks that cannot be reached after M_WAITOK allocation.

Static equivalence review plus the FreeBSD build and plain/LZ4/LZMA smoke is sufficient evidence for these changes. It is not sufficient for the deferred behavior changes below, and this report does not claim otherwise.

Deferred Behavior and Required Targeted Tests

Non-directory root

The current root path does not add a new rejection for a root NID that resolves to a non-directory vnode. A future fix requires a purpose-built image and checks for mount errno, vnode release, mount error text, and complete cleanup.

Zero-length internal run

The uncompressed UIO reader's existing run_len == 0 behavior was not changed. A future fix requires a corrupt mapping fixture that reaches a zero-length run while the request remains inside the file, with exact comparison to the contiguous-buffer path and expected EINTEGRITY.

Header-only xattr

The existing behavior for an ibody containing only the xattr header was not changed. Targeted coverage must distinguish zero and nonzero shared counts, name filters, get/list results, ACL mode fallback, and corruption results.

Duplicate or missing device slots

device.N slot parsing behavior and diagnostics were not changed. Future tests must cover duplicate, out-of-order, missing, excessive, and malformed slots, flat and non-flat device tables, exact errno and mount error text, and GEOM cleanup.

insmntque() race closure

The earlier ownership fix remains accepted by static lifecycle review but is not runtime-closed by ordinary smoke. A dedicated mount/unmount or forced unmount race must stress vnode creation and inspect panic, use-after-free, lock, reference, and cleanup behavior.

Explicit mapped extent fixtures

Positive payload fixtures are still unavailable for explicit mapped extent records of 4, 8, 16, and 32 bytes. No restructuring or coverage claim should be made until validated mappings and file hashes exist.

vnode_create_vobject() errno

Pre11 intentionally retains the current conversion of a nonzero vnode_create_vobject() result to ENOMEM. Direct propagation is a visible behavior change and requires controlled pager failure or fault injection that verifies the caller-visible errno and vnode state.

Final Conclusion

Pre11 completed all five narrowed maintenance batches, passed independent static review, built successfully as a FreeBSD KLD, and passed the required plain, LZ4, and full-file LZMA smoke. The first smoke attempt was correctly classified as an infrastructure failure before DUT transfer or build; the corrected retry provides the runtime evidence.

Pre11 improves cross-repository maintainability without replacing native FreeBSD vnode, GEOM, UIO, pager, ACL, or synchronous decompression contracts. Full feature validation remains outside this release and must not be inferred from the targeted smoke result.