# repo22 Metadata and VFS Manual Test Report Started: 2026-08-08 23:37 UTC Completed: 2026-08-09 UTC Baseline: `c208bf1f4b8d7a85777f7fe45e8c6e8d3a9f2d1a` Guest: FreeBSD 15.0-RELEASE-p8 amd64, QEMU TCG FreeBSD source reference: `/work/dev-freebsd-releng`, releng/15.0 Linux source reference: `/work/dev-src-linux/fs/erofs` Host production tool: erofs-utils 1.8.6 ## Result **PASS** for the implemented metadata/VFS changes and every runnable required FreeBSD 15 regression. Two limitations are recorded rather than misreported as PASS: 1. The Linux host had no loop provider/EROFS kernel mount path, so the deterministic nonzero-padding fixture passed Linux erofs-utils 1.8.6 `fsck.erofs` and `dump.erofs`, while the Linux kernel mount is **ENVIRONMENT-UNAVAILABLE**. 2. A real TC010 48-bit `statfs` mount needs a provider as large as the declared multi-terabyte image. The corrected test records this as a provider/tool requirement; no small-media mount is called a positive PASS. An initial NFS stress run completed all data and metadata assertions but failed cleanup because `service nfsd onerestart` inherited the deliberately open NFS client descriptor. The procedure was corrected to run the service command with `3<&-`; the complete stress/background/cleanup sequence then passed. The first cleanup failure is retained here as evidence for the TC132 ordering fix. ## Baseline and Scope Audit - `HEAD` and `FETCH_HEAD` both resolved to the required baseline. - `find /work -name AGENTS.md -type f -print` returned no paths. - Only `repo-community/repo22` was modified. - Existing untracked `build/` objects and historical manual-test artifacts were preserved and excluded from staging. - No CI implementation, binary fixture, overlay, image, or VM artifact is part of the intended commit. ## Build and ABI Validation Commands: ```sh EROFS_ZSTDIO=0 ./build.sh EROFS_ZSTDIO=1 ./build.sh nm -u module.ko | awk '$NF == "bcmp" { n++ } END { print n + 0 }' git diff --check -- repo-community/repo22 ``` Results: | Build | SHA256 | `bcmp` count | Result | |---|---|---:|---| | ZSTDIO disabled | `031038ef195497dc6a1d840d55b293292e051fb888c679c89c8cfbd19b56d525` | 0 | PASS | | ZSTDIO enabled | `16166b9ffc96a532bda9925513e10df11f4cf8a06b3c15afbc09b1a4e4b9d2df` | 0 | PASS | Both modules loaded and unloaded on FreeBSD 15. The final unload used the observed KLD ID so arbitrary copied filenames did not affect cleanup. FreeBSD 15 source inspection confirmed the exact current ABI: ```text vnode_pager_local_getpages(struct vop_getpages_args *) vnode_pager_local_getpages_async(struct vop_getpages_async_args *) ``` The local ext2 vnode vector registers both functions directly. EROFS now does the same. ## Deterministic Fixture Evidence The checked-in `prepare-fixtures.sh` was syntax-checked and rerun into separate untracked `repro3-*` directories. It reproduced the expected byte-identical inline, special, pager, NFS, and nlink images and generated the current namei variants. Key structural evidence: ```text inline_nid=39 inode_off=1248 inode_blockoff=1248 xattr_icount=0->695 inline_data_blockoff=4068 inline_size=31 wide_nid=42 block=6 dirents=80 last_nameoff=4043 padding_patch=4084:4092 nlink1_nid=43 i_format_bit4=1 i_nb=0x1234 special compact rdev raw_u=0x543abc21 special extended rdev raw_u=0x543abc21 ``` Generated image hashes: | Image | SHA256 | |---|---| | `inline.erofs` | `0435b3ea748a88cccbdc6390dec4285a3706bec3dc09de58aa1808544ebc63d0` | | `inline-cross-block.erofs` | `63ebb7632687b564beb4c9dd8036eb4ac63c4495f63061ad7eec1c134c656932` | | `special-compact.erofs` | `fd78256dd83d9d6d957e5f843c7a8e8a175a4b3243d528bebd299b0226853237` | | `special-extended.erofs` | `e73e9b84d9ceb8c2b07e9c2732733b0fd607736c68c09522a2402fbeef6ba8d5` | | `namei-base.erofs` | `d1730ff23836797c6c09e1b39b1cf23efc16e27f85ab07fdcab577bb82871659` | | `namei-padding-nonzero.erofs` | `9a94e9af2cab264b9c11975a20d78e615d6fe1e6f86267173cb5ac86aecb2b17` | | `namei-corrupt-short.erofs` | `fb89f74795a5569ed3a85d63836dd75a06e1f17823d0508048c37da710ea6e75` | | `namei-corrupt-nameoff.erofs` | `b0b70ee615f163430f04edb91ab76c27ee8cc9a75b8ebb2008834f5b550e3933` | | `namei-corrupt-name.erofs` | `6a980ad3e241603eda2ef71a470c82975291c614366a401e4e89c17c9adf9b91` | | `pager-plain.erofs` | `36596edea5bfbaa1157f6c142095a7ee9949b5df1b1a35620c0d22ec853f3c09` | | `pager-lz4.erofs` | `b06daee6b02a6ebe967655be760b496c8a9d922cf47acb5c840e82a48a34c51d` | | `nfs-a.erofs` | `6d86dcf620b007d069895e3e94a21a74dadcf35e84c92dc4f7c21a2ec23bd901` | | `nfs-b.erofs` | `18913fd319daca20b3e4d30a89c05c416b4d3ca396394509e5112d548674f4c2` | | `nlink.erofs` | `798eb81b3ba7270ee653b00adeba47a6e03c982adef1982bf5b4e0935669ae83` | | `nlink1-patched.erofs` | `19fd85f32ed89117d8e02bc19ca09655dd3bae9152cf693a399eda2135233042` | The padding patch was followed by a rigorous CRC32C recomputation over the superblock block. Linux erofs-utils produced the exact payload: ```text wide entry 079 ``` The Linux kernel comparison command failed before mount with “failed to setup loop device”; it is therefore not labeled PASS. ## TC147: FLAT_INLINE Bounds Commands included fresh md attach/mount for the base and cross-block images, then cold `cat`/`stat` access. Observed on the final module: ```text positive hash=0347f272ba395aff6df5fd824a7c552fa26d7f017283f0544136385abef31b01 stat=31 8 corrupt stat: Integrity check failed corrupt stat: Integrity check failed corrupt cat: Integrity check failed dmesg_before=122 dmesg_after=122 mounts=0 mds= module_rc=1 ``` The positive file read exactly. The checksum-valid corrupt inode failed with `EINTEGRITY` before its 31-byte inline range could cross the metadata block. The mapping path also uses checked additions, and primary/metabox declared bounds are validated at inode decode. Self-review first rejected the old `i_xattr_icount=1020` mutation because it merely moved the inline data into the next block without crossing that block. The corrected value `695` places the tail at block offset 4068. Its first genuine rerun exposed a stale constructing vnode: the second `stat` returned `EBADF`. The failure path now calls `vgone()` before `vput()`, and the complete final rerun above returned `EINTEGRITY` for every repeated access. ## TC022/TC056: Special `st_rdev` The source fixture used real Linux char/block nodes with major `2748`, minor `344865`, plus a FIFO. `stat_special.c` checked `st_rdev` directly because FreeBSD `stat -f %Lr` truncates before `minor()` for large values. Compact and extended results were identical: ```text PASS char rdev=0xa430005bc21 major=2748 minor=344865 PASS block rdev=0xa430005bc21 major=2748 minor=344865 PASS fifo rdev=0xffffffffffffffff ``` This proves Linux `new_decode_dev(0x543abc21)` followed by FreeBSD `makedev()`; a little-endian integer cast would not produce this FreeBSD `dev_t`. ## TC055: Real Compressed Allocation For every row, full FreeBSD kernel reads matched the expected SHA256 and `st_blocks * 512` matched the inode's real on-disk compressed size: | Shape | File | Size | Allocated bytes | SHA256/result | |---|---|---:|---:|---| | LZ4 full | `shape.dat` | 1048576 | 8192 | `370eb0a8...` PASS | | LZ4 compact | `shape.dat` | 1048576 | 8192 | `370eb0a8...` PASS | | LZ4 fragment | `fragment.dat` | 1048699 | 0 | `a3a83e5c...` PASS | | LZ4 ztailpacking | `inline.dat` | 65536 | 0 | `e2aa4a0a...` PASS | | MicroLZMA partial A | `a.dat` | 1048576 | 4096 | `370eb0a8...` PASS | | MicroLZMA partial B | `b.dat` | 700000 | 4096 | `5a840803...` PASS | | DEFLATE compact/partial | `a.dat` | 1048576 | 36864 | `370eb0a8...` PASS | | DEFLATE full/partial | `b.dat` | 1050624 | 8192 | `61b17076...` PASS | | ZSTD partial A | `a.dat` | 1048576 | 4096 | `370eb0a8...` PASS | | ZSTD partial B | `b.dat` | 700000 | 4096 | `5a840803...` PASS | Uncompressed regressions: ```text inline size=31 st_blocks=8 plain size=21211 st_blocks=48 chunk size=90017 st_blocks=176 ``` Representative compression image hashes were: ```text LZ4 full d784f8dc... LZ4 compact 37942ef1... LZ4 fragment a4e5d40e... LZ4 ztail 035069eb... MicroLZMA 2f4bd89d... DEFLATE 8bc720a1... ZSTD 7f5ee4f8... ``` ## TC141/TC148: Directory Compatibility and Strictness FreeBSD results: - Cold `/alpha/bravo/charlie/payload.txt`: PASS without parent warming. - Repeated cold lookup and post-negative-cache existing lookup: PASS. - Patched nonzero tail bytes: accepted. - `wide` enumeration: 320 files plus `.` and `..`; 322 dirents through a 128-byte buffer and restart cookies. - Short block, non-monotonic `nameoff`, and `/` in an on-disk name: lookup and readdir both returned `EINTEGRITY`. - Repeated corrupted lookup remained `EINTEGRITY`, not cached `ENOENT`. The duplicate validators were removed; lookup and readdir use the shared helper in `dir.c`. ## TC132/TC133: NFS Generation and Stress Direct handle validation after the final superblock-hash implementation: ```text nfs-a: fsid=00000034:000000e0 nid=0x2e gen=849213208 nfs-b: fsid=00000034:000000e0 nid=0x2e gen=4011239099 ``` - `nfs-a` remount on the same md unit produced byte-identical complete handles. - `va_gen` equaled handle generation. - Replacing `nfs-a` with `nfs-b` on the same md unit made the old handle return `ESTALE` through both `fhstat` and `fhopen`. - Bad length/pad returned `EINVAL`; bad generation/NID returned `ESTALE`. - Handle generation mutation used `gen_xor 1`, not a hard-coded value. NFSv3/TCP READDIRPLUS stress: - Four clients mounted; requested 512/1024/4096 readdir sizes were clamped by FreeBSD to 8192, while default was 65536. - All four 12,050-name sorted listings had SHA256 `4fbf1b6103e8884223629c3fd03f4ec36061e65cd2a1becfc96670daa96f9d71`. - Twelve traversal workers and eight cat/stat controller jobs were waited by PID; every exit status was zero. - READDIRPLUS client/server count was 1304 in the recorded full run. - RPC timeouts, invalid replies, retries, and server write RPCs were zero. - The 21,757,952-byte throughput file hash was `0841effed82d1adf394b6834ce30d4d9eb5fc9427527e854ec1cb6bb4b86c119`. - nfsd restart with an open descriptor passed after the service command closed inherited fd 3. - Corrected full rerun ended `NFS-STRESS-CLEAN-PASS`. ## TC149: Real Pager Faults `tests/mmap_fault.c` was compiled natively on FreeBSD 15 and run against both plain and LZ4 images. Both runs printed: ```text PASS size=21211 pages=6 fnv1a64=a1890a1c216724be random-faults=6 \ eof-zero=PASS sigbus=PASS private-cow=PASS ``` The helper verified deterministic random faults after `MADV_DONTNEED`, full mapping equality with `pread`, partial EOF-page zeroes, child `SIGBUS` on the next full page, `MAP_SHARED` write denial, FreeBSD private COW semantics, and `O_RDWR -> EROFS`. dmesg added exactly the two expected child exits on signal 10 (`SIGBUS`). No parent crash, VM assertion, trap, panic, or dirty writeback appeared. ## Additional Regressions | Area | Evidence | Result | |---|---|---| | Inline/system xattr | trusted, security, long-prefix, user values exact | PASS | | Shared xattr | shared and per-inode values exact | PASS | | Metabox xattr | `dirA/nested.txt` and `hello.txt` enumerated/read | PASS | | Fragment-backed metabox | positive file/xattrs exact; self-loop and range images rejected | PASS | | Single-device chunk | `plain.bin`, `deep/payload.bin` hashes exact | PASS | | Chunk multidevice | block-map and indexed files hashes exact | PASS | | External compressed multidevice | complete 1 MiB LZ4 SHA256 `370eb0a8...` | PASS | | Compact nlink rules | explicit nlink 1/2 plus flagged nlink-one image | PASS | | ZSTD enabled final load/read | final module and `zstd-partial-ref` read | PASS | Supporting fixture hashes: ```text system-inline-four 6f521b62... shared xattr 208b61ca... metabox xattr ef8d619c... chunk single 7aa8db22... chunk multidev 73343b70... + a36c2b9b... external LZ4 56256124... + 0d71102c... NFS stress image 6928f05b... ``` The final-module fragment-backed metabox rerun used the previously qualified, checksum-valid image with SHA256 `8a9a62bd203994711b8272192915d811e6c3de23e07ad9607dd63e66cc109bcd`. `/tree/d00/file000.txt` produced SHA256 `4536c1d7121f48829475f29179f54baa57154b4ef817cf0776f81782585d29ad`; the shared and per-file xattrs were `shared-value` and `value-000`. The self-loop and out-of-range images returned `Integrity check failed`. dmesg remained at 122 lines, and the post-run audit showed zero mounts, md providers, and loaded EROFS modules. ## Final-Binary Closure Rerun After the `vgone()` error-path fix, the final ZSTDIO module SHA256 `16166b9ffc96a532bda9925513e10df11f4cf8a06b3c15afbc09b1a4e4b9d2df` was used for one continuous closure matrix: - LZ4 full/compact/fragment/ztailpacking, MicroLZMA partial, DEFLATE compact/full partial, and ZSTD partial hashes and `st_blocks` all matched. - Inline trusted/security/long-prefix/user xattrs matched exact values. - Metabox shared xattrs returned `answer=forty-two`; the fragment carrier file and `repo22.item-000=value-000` matched. - Single-device chunk, external chunk provider, and external compressed LZ4 hashes matched; compressed `st_blocks=16`. - The final module preserved the same NFS handle across same-md remount, made the old handle `ESTALE` after image replacement, synchronized `va_gen`, and completed a real local NFSv3/TCP client read with matching SHA256. The first closure script stopped after the system-xattr row because it queried an obsolete metabox attribute name. Its trap left zero mounts, md providers, modules, and services. The corrected `answer`/`metaboxshared` queries and all remaining rows passed. The complete final audit was: ```text dmesg_before=122 dmesg_after=122 erofs_mounts=0 nfs_mounts=0 mds= module_rc=1 services=0/0/0 FINAL-REGRESSION-REST-PASS ``` ## Final Environment and Cleanup Final guest audit: ```text mounts=0 mds= modules=0 services=0 final_dmesg_before=122 final_dmesg_after=122 ``` The final dmesg tail contained only the historical pre-test duplicate-module diagnostic and the two intentional pager-child SIGBUS exits. The final compression, xattr, chunk, multidevice, generation, and NFS closure pass added no dmesg lines. Guest helper hashes: | Helper | SHA256 | |---|---| | `mmap_fault` | `b19c9c28a7abdfebe4243e3f4876b711eebc1c02b9856c15cb8bf15ae2da3a65` | | `nfs_fh_tool` | `0dcad233cc8768ca84569c8d030939b526d50c64190fc54d5f0de013191f11d6` | | `stat_special` | `b5c0eabd06541268e799df4f72fa7f37a460617bd8960f918b27710483db3841` | | `readdir_probe` | `44747ccd8d9a285a37d8049b7d61d00946db88482c08a3570e59b5a2fa1b4ea2` | No password material was printed into this report or written into tracked files.