# repo22 G8 Documentation, NFS, and Integrity Manual Regression

Date: 2026-08-09 13:07-13:56 UTC

Executor: G8 manual agent

Source baseline: `f11fff5b8e8050e1017ed86f0bcf71042b2b45aa`

Exact scope: `TC111`, `TC131`-`TC133`, `TC154`-`TC156` (7 IDs)

## Result

All seven requested test cases passed. There are no KFAIL, SHELVED, or ENV
results, no duplicate IDs, and no omitted IDs.

| Status | Count |
| --- | ---: |
| PASS | 7 |
| KFAIL | 0 |
| SHELVED | 0 |
| ENV | 0 |
| Duplicate | 0 |
| Omitted | 0 |

| Test ID | Status | Manual evidence |
| --- | --- | --- |
| TC111 | PASS | Audited current source and documentation against real generic `/sbin/mount`; corrected helper and writable-request claims. |
| TC131 | PASS | Real mountd/nfsd NFSv3 export, four vnode types, read-only behavior, 16-byte handle resolution, and RPC statistics. |
| TC132 | PASS | Handle ABI/classes, stable remount, replacement `ESTALE`, metabox and external-provider regressions, and nfsd restart. |
| TC133 | PASS | Exact 12,050-name READDIRPLUS lists, five cold remounts, 20 individually waited workers, and zero RPC errors. |
| TC154 | PASS | Same-superblock/UUID/NID replacement changed per-inode generation; unchanged remount stayed stable. |
| TC155 | PASS | Explicit-extent physical-address wrap returned `EINTEGRITY` on both direct reads and in `truss`. |
| TC156 | PASS | Compact/extended epoch, `time_t`, and nanosecond boundary corruptions returned `EINTEGRITY`. |

No kernel source changed. No kernel failure remained, so no issue file was
created.

## Isolated Environment

- Worktree: `/work/build/repo22-manual-g8-20260809T130723Z`, branch
  `manual-g8-20260809T130723Z`, created directly from the source baseline.
- VM: independent qcow2 overlay backed by the clean FreeBSD development base;
  QEMU TCG, 6144 MB, 4 vCPUs, SSH only on `127.0.0.1:9228`.
- Guest: FreeBSD `15.0-RELEASE-p8` amd64,
  `releng/15.0-n281036-53054229dcb3`, OSREL `1500068`.
- Guest kernel SHA256:
  `b9abf7b58f9dd4d87f14d2fbc306cf255e6eadc47b8ae885a230f65e28be4562`.
- Host erofs-utils: 1.8.6.
- No CI, runner, or test wrapper was used. Markdown procedures were issued
  manually through SSH, with direct command status kept separate from tracing
  tool status.

## Exact Build

The repo22 source archive came from the exact baseline commit. The matching
tracked FreeBSD build input was `dev-freebsd-releng/sys`, identified by
`REVISION="15.0"` and `BRANCH="RELEASE-p9"`. The build ran natively in the
guest as:

```sh
FREEBSD_SRC=/root/freebsd-src WITH_ZSTDIO=1 ./build.sh
```

The compile command contained `-DZSTDIO` and kernel `-Werror`. The module had
the five expected `ZSTD_*` kernel references and no unresolved `bcmp`.

| Object | SHA256 |
| --- | --- |
| repo22 source archive | `2f76ef7df9117c6e7d62ad41809638ad306e676191346083bf95fe551f7df515` |
| FreeBSD 15 `sys` archive | `cd806ac4d6aee5d7ceb6a2f9603020b48b5012835bc8c7f2ec0985572fcd0262` |
| `erofs.ko` | `e8cd4839328de089355505efb1629c835d2f93faad2e14f63c6e6cb844ce9589` |
| `nfs_fh_tool` | `db704f67d718d04b84ed32b5cdbecb93a99c5fe3b4ab238d603a10e005d790e3` |

The guest kernel is p8 and the tracked source is p9, but both use the FreeBSD
15.0 OSREL ABI. The exact module loaded and unloaded successfully.

## Fixture Qualification

`tests/review_fixtures.py` generated two independent output directories. Their
manifests and checksum inventories were byte-identical, and all nine image
checksums self-verified. Its structured assertions recorded:

- target NID 452 at inode offset 14464 after checksum block 4096;
- identical complete superblock block and UUID for NFS images A and B;
- generations `3895653226 -> 548470773` from the changed raw inode;
- explicit extent base `0xfffffffffffff000`, `plen0=8192`, `plen1=4096`, and
  wrap before logical cluster 4096;
- compact epoch wrap/range, compact nanoseconds 1000000000, extended
  nanoseconds 1000000000, and extended seconds `INT64_MAX+1`.

Review generator SHA256 was
`b92fd6b6122d55882998138efc0109e24b236f9e877405dbff7914284a18c124`;
manifest SHA256 was
`be0836043d172b34eb625e5259f7e6cb9a8992ff74e7d1a5cdc10d69282e2335`.

The NFS stress image was generated from a fresh deterministic tree containing
12,050 `bigdir` files, 256 concurrent-read files, four basic vnode types, and a
22,020,096-byte throughput file. Image A SHA256 was
`88721877dc3762c8eafdf3bcca2653787cdcf41983978ab159705761abefac37`;
image B was
`964b3d75579740c9b08bc9cae8329e3d641d3c505e9391de3ab9f5d24fbecd17`.
The expected sorted-name list SHA256 was
`4fbf1b6103e8884223629c3fd03f4ec36061e65cd2a1becfc96670daa96f9d71`.

Fresh structured metabox and multidevice helpers also self-verified the two
TC132 regression inputs. The metabox image SHA256 was
`dd7b04097d1bfe283b65c95d759acd2176beb7cb0f1fe9d5ddbc0694b5acba9d`;
the multidevice primary/slot hashes were `918aa3a64e8861011914d967912909ce9de98418cff711cfbf8f91c0c7717f72`,
`4e31d95a12405f2f1396fb926a6854c591fc335eade8944f73fdc7fe6758aee6`,
and `355a74880bd3648dea22ad18e19f809cee12303ceed2a99f53094c2b66563a11`.

## TC111

`/sbin/mount_erofs` was absent and `command -v mount_erofs` returned 127.
Generic `/sbin/mount -t erofs` mounted the image successfully without `-o ro`.
The following real behavior was recorded:

- the default mount was read-only and `touch` failed with `EROFS`;
- `-o rw` returned 0 but the resulting mount was still read-only;
- `-o ro,noexec,nosuid` returned 0 and all three flags appeared;
- non-export `mount -u` returned `EOPNOTSUPP`;
- an unknown filesystem option returned direct rc 1, with
  `nmount(..., MNT_RDONLY) ERR#22`, and created no mount.

Current `src`, `README.md`, `docs/features.md`, `docs/architecture.md`,
`docs/erofs.5`, and current progress material were checked. `README.md`,
`docs/erofs.5`, and the test procedure now describe the generic frontend and
the forced-read-only `rw` behavior accurately. The man page's split-device
example was also exercised by the TC132 multidevice mount. SEE ALSO entries
absent from the qualified guest were removed; `mandoc -Tlint -Werror` and
ASCII rendering both returned 0 in that guest.

## TC131

The direct EROFS line lacked `NFS exported` before mountd. After installing the
loopback export and reloading mountd, `showmount -e` listed the exact path and
the direct mount gained `NFS exported`. `rpcinfo` showed NFSv3 and mountd over
TCP and UDP.

The NFSv3 TCP client negotiated `rdirplus`. Regular file content, directory,
symlink target, FIFO type, and inode number matched the direct EROFS mount.
`touch` failed with `Read-only file system`. Local `fhstat` and `fhopen`
resolved the regular handle with `len=16`, `pad=0`, NID 116, and generation
2068234290.

After basic operations client READDIRPLUS was 2. Server Write and Create were
both 0. TimedOut, Invalid, X Replies, and Retries were all 0.

## TC132

Regular, directory, symlink, and FIFO handles all had `len=16`, `pad=0`, full
64-bit NIDs, and nonzero generations matching `st_gen`. Bad length/pad returned
`EINVAL`; bad generation/NID returned `ESTALE` through both `fhstat` and
`fhopen`.

The unchanged image remounted on md80 preserved the complete handle SHA256
`9e1df1952b43d383fea295301525ede7a69b7d57e5f60a75a6d7f1531e13df0a`,
and the old handle still read the file. Replacement B retained fsid and NID
116 but changed generation `2068234290 -> 857800581`; both old-handle paths
returned `ESTALE` while B resolved.

The metabox handle preserved NID `0x8000000000000010`; invalid metabox NID and
generation returned `ESTALE`. After forced orphaning of external slot 2, the
valid file handle still resolved metadata and the read returned `ENXIO(6)`,
not `ESTALE`.

An NFS client descriptor remained open across `service nfsd onerestart 3<&-`.
The old descriptor and a new path read both returned SHA256
`3e2d0b4971e1f4bf00c3562a8bf9c5d85378c9de054f3da89541f49f2b449a7b`;
the export and all RPC registrations remained live.

## TC133

Requested readdir sizes 512, 1024, and 4096 were all clamped by the FreeBSD
client to 8192; the default remained 65536. This is the recorded client floor.

Every one of the four mounts returned exactly 12,050 unique expected names.
Every sorted list, plus all five cold-remount lists, had SHA256
`4fbf1b6103e8884223629c3fd03f4ec36061e65cd2a1becfc96670daa96f9d71`.
The `ls -a1` list contained 12,052 entries, with `.` and `..` exactly once.

All 12 traversal workers were waited by PID and returned 0. All four parallel
cat workers and four parallel stat workers were also waited by PID and returned
0. The informational 22,020,096-byte read completed in 14.51 seconds.

Final client/server READDIRPLUS was 3420. TimedOut, Invalid, X Replies, and
Retries remained 0. Server Write, WriteRPC, Create, and Commit remained 0.
There were no new stale-handle, timeout, retry, panic, trap, assertion,
watchdog, or EROFS error lines.

## TC154

Image A produced fsid `00000034:000000e0`, `len=16`, `pad=0`, NID 452, and
generation 3895653226. `nfs_fh_tool`, `stat st_gen`, and the fixture manifest
agreed. The unchanged remount preserved complete handle SHA256
`79f2f4b8e354af0ae369849d7f66a739162ffadc4a5689c09643c9949b548de1`
and the old handle remained readable.

Image B retained the complete superblock block, UUID, fsid, NID, and content,
but generation became 548470773. Both old-handle paths returned `ESTALE`; B's
handle resolved. The malformed same-NID replacement returned positive errno 45
through both paths.

## TC155

The self-checked fixture SHA256 was
`1e49ecf1917265fde9b606e80f7dbae8b14aca8c6f149128b31d6c825da546dd`.
The image mounted and target `stat` reported inode 40, size 1,048,576. Two
direct one-byte reads at logical offset 4096 returned rc 1 and `Integrity check
failed`; the traced read was `ERR#97`. The repeat exercised the cached vnode.
A DTrace `io:::start` positive control observed one raw
`md90 offset=4096 bytes=4096` event. A separate trace around the failing EROFS
read observed zero md90 events, proving the wrapped address did not reach the
provider. No panic or resource remained.

## TC156

Both compact root corruptions failed `nmount` with `ERR#97`. The compact range
image mounted with root mtime `INT64_MAX`; target stat returned `ERR#97` for
`INT64_MAX+1`. Both extended images mounted, and target stat returned `ERR#97`
for nanoseconds 1000000000 and seconds `INT64_MAX+1`. Every failure was run
directly and again under `truss`; no panic or resource remained.

## Cleanup and Restoration

Before NFS setup, `/etc/exports` did not exist; rpcbind, mountd, and nfsd were
stopped; and `rpcbind_enable`, `mountd_enable`, and `nfs_server_enable` were all
`NO`. Cleanup unmounted every loopback client while nfsd was alive, cleared and
reloaded exports, stopped nfsd/mountd/rpcbind, then removed the direct EROFS
mount, md42, and the module.

Final state exactly matched the baseline: `/etc/exports` absent, all three
services stopped with rc 1, all three rc settings `NO`, zero NFS/EROFS mounts,
zero md providers, no EROFS KLD, no service process, and `rpcinfo` refused the
connection because rpcbind was stopped. The complete NFS-period dmesg delta had
zero anomaly lines.

The retained guest evidence archive is outside the repository at
`/work/build/repo22-manual-g8-20260809T130723Z-vm/evidence/`:

| Artifact | SHA256 |
| --- | --- |
| `final-guest-evidence.txt` | `eb67210818e663c15e4670ada9ba63b82b44e9ed3a9486c575df3a71ed3f0522` |
| `TC155-dtrace-assert.txt` | `f8b52985a74c8c777b3b830c39749be65c613165ffbcde6d0018dc471018c433` |
| `final-post-dtrace-cleanup.txt` | `90f04d8f5a4ae35c87cc3adb1aeb939c7cc5534233ed63e9ff4501c83fd857d2` |
| `repo22-g8-evidence.tar.gz` | `9a378fd619f9bca21f40689d746308933aa22e440f7201104732f91634c21290` |

## Non-Qualified Attempts

One TC131 setup command stopped at the expected nonzero service-status probe
because that probe was mistakenly under `set -e`; it occurred before module,
exports, or service changes. One TC133 attempt stopped after the four exact
lists because a shell-quoted dot assertion matched zero; the three added
clients were unmounted and the complete procedure was rerun from the start.
Tracing wrappers returned 0 even when their child failed, so all error claims
use separate direct statuses plus syscall errno. None of these discarded
attempts is counted as PASS evidence.

Two initial DTrace specifications used field names from other provider ABIs
and failed at compile time before any probe I/O. The qualified specification
used FreeBSD `struct devstat` and `struct bio` fields. Its first assertion used
a line anchor even though the format emitted a literal `\\n`; substring counts
then proved one positive md90 event and zero failing-read md90 events. DTrace's
automatically loaded module set was unloaded as a unit and the original KLD
set was reverified.

## Issues

None.
