7.2 KiB
P15-092 Stage0 Decision
Status: STOP. B15 is STOP-NO-SOURCE; terminal static review status is
TERMINAL_REVIEWED_NO_SOURCE. No production source, B15 case, or B15 fixture
was created. Historical acceptance remains NOT_TESTED.
P15-092 is the G11 zero-nlink candidate. The frozen BASE is
b22dae8dc634c68db4ea89dccade91350614c139, the FreeBSD source HEAD is
106727738dcfb6c001b46f25363b91cece970085, the erofs-utils source HEAD is
7db78788b000999e2de88decd2ba90654f26171c, and the generator is
mkfs.erofs (erofs-utils) 1.8.6. Linux EROFS identity is frozen by the three
source hashes in P15-092-input.json and the Pre15 semantic audit hash ledger.
The final gate script and input SHA256 values are
5943b85864da9095174ef51d1eed032ec6f0a1766c6465cb9660ea20cbd46b1e
and 0a6f6c76185644d3f5525a98429a310027556ef3cf7ebb43abb912f92e052bde.
Real Disk Oracle
The gate creates the same deterministic source tree twice in forced compact form and twice in forced extended form. It uses fixed UUID, timestamp, worker count, xattr policy, and inline-data policy. Both complete host output trees are byte-identical.
An independent parser reads the real superblock, checksum span, metadata block,
root NID, directory entries, compact i_nb.nlink, extended i_nlink, and the
compact EROFS_I_NLINK_1_BIT rule. It then materializes seven images:
- compact and extended positive seeds;
- namespace-reachable compact, extended, and directory inodes with nlink zero;
- a root inode with nlink zero;
- an unreachable inode with nlink zero, whose former name is redirected to a real hardlink NID and whose replacement link count is corrected to three.
Every derived image has a recomputed valid EROFS CRC32C. dump.erofs --path
resolves the actual directory edge and NID; no DUT helper or internal value
injection is used. All seven images, including all three namespace-reachable
zero-nlink images, pass fsck.erofs -d0 with no error marker. The fixture-set
SHA256 is 99897d4fd81da015bdaa66a5dfdbf3f42e9e830882c0d8c979e691fa9209ee7a.
Key deterministic host evidence SHA256 values are:
host-result.json:59a27e9389e2771c921d689f6b76caeb858f0fd28487a933529153727aac12e8disk-records.json:44bf0355dc5b34e93ec6868db9f9049de32500591b048a9016bf46aed9609485boundary.json:985df1236c6dd2016d6cb244b71578d36bd4cd10aa273b60a92d5bb6d24d5b60format-semantics.json:88efc1d7814103c044b36ff4dc3cac1dfa4da79f3d8955c682d1a60d9bfd9fcffixture-index.json:4d2b69bcc31709ecb96cfafb41f5db8ffcc97215c3290cfa476d0b6c7fc27886source-anchors.json:ef9e6871d5fe1a3a6113f1172340269da4ea0c1692003aad0b0fee06ec4deb42
Linux and FreeBSD Semantics
Linux EROFS calls set_nlink() with the compact or extended disk value and has
no zero-nlink rejection in inode decode or super initialization. This is an
inode/link-count behavior, not a FreeBSD vnode publication rule. Linux and
FreeBSD both permit a live unlinked inode/vnode with link count zero; the
FreeBSD VM code explicitly treats va_nlink == 0 as an unlinked mapping case.
The FreeBSD EROFS adapter has three distinct entry semantics:
erofs_lookup()owns a non-dot namespace edge and callserofs_vget()..vfs_vget = erofs_vgetis the raw NID entry used by VFS/root callers.erofs_fhtovp()calls rawVFS_VGETand then mapsnlink == 0toESTALE.
Therefore Linux's direct set_nlink() behavior does not authorize either a
global FreeBSD rejection or a namespace-only rejection. The latter would be a
new FreeBSD validator policy, and the disk/fsck corpus supplies no format-level
rule requiring it.
Publication Boundary
B09 moved the vnode constructor to src/erofs_vnops.c, but the frozen B15
write set is only src/namei.c and src/inode.c. erofs_vget() inserts the
constructing vnode in the hash, decodes the inode, marks it
VSTATE_CONSTRUCTED, and only then returns to erofs_lookup().
A post-erofs_vget() check in namei.c is therefore too late to reject before
vnode publication. vput() alone does not perform the required vgone
cleanup. An unconditional vgone() cannot preserve an already cached vnode
obtained through raw VFS_VGET, because erofs_vget() does not return a
created-versus-hit indicator. Pre-reading through erofs_read_inode() would
duplicate complete inode decode and metadata I/O on every cold namespace
lookup, then decode the same inode again in erofs_vget().
The four failed GO requirements are consequently:
- no format or cross-kernel rule requires reachable zero-nlink rejection;
- rejection before vnode publication is unavailable within the exact B15 write set;
- post-publication cleanup cannot preserve cached raw VGET semantics;
- pre-reading would duplicate full inode decode for a low-value validator.
Namespace and raw entrypoints are distinguishable, and the orphan needs no mount-wide scan, but those two facts do not outweigh the failed safety, compatibility, and cost requirements. P15-092 is therefore STOP rather than a partial or expanded-write-set implementation.
Replay and Infrastructure
The authoritative deterministic host command was run twice:
timeout -k 10 240 tests/pre15/gates/P15-092.sh \
--base b22dae8dc634c68db4ea89dccade91350614c139 \
--output OWNED_OUTPUT --host-only
Both runs exit 22 with STOP and have byte-identical host output trees.
One supplemental isolated runtime attempt used the standalone
/work/debug-qemu/local/vm/freebsd-build-runtime.qcow2, not the protected base
bp, with a fresh overlay, random port, exact baseline KLD, 180-second boot
deadline, 60-second guest command deadlines, 900-second inner timeout, and
1200-second outer timeout. Run
20260815T083854Z-qemu-P15-092-gate-runtime-1219662-0 was
INFRA_BLOCKED: guest SSH did not become ready before the boot deadline, so no
runtime vnode result is claimed. The run used only PID 1219981 and port
49795; it did not own PID 26318, port 9222, or the protected base bp.
Cleanup is PASS: the owned QEMU PID stopped, port 49795 is free, the
overlay and case temp were removed, and the standalone base SHA256 remained
ae09f47aef43cfd016049610e86bcf2073fdf70430961bcdb94662facac9f046.
The runtime manifest and cleanup SHA256 values are
2e9a4220dc86c5d8fa465e77e6d81e5e36c0f26338b70d71a84881af8fc02cb9
and 0a499d8fa3397f73998c6c3c3ae9dfc9070f61267a86361ba96d1e8bc64cb392.
Because the reproducible host gate already fails mandatory GO conditions, the
runtime infrastructure block does not defer or weaken the STOP decision. It is
reported separately and was not retried with another long-running VM. B15,
TC021, TC025, TC182, K0, and B15 acceptance QEMU are NOT_RUN by the mandatory
STOP-NO-SOURCE rule. The full feature suite was not run.
Terminal Static Review
The 2026-08-17 review rechecked the current repo-pre-15, Linux EROFS
implementation, P15-092 plan, frozen write set, and post-STOP history. It
found no format or cross-kernel requirement for namespace zero-nlink
rejection, no new B15 consumer or test target, and no safe implementation
entry within the frozen write set. The detailed evidence is
planning/pre15/evidence/20260817T-B15-terminal-review/VERDICT.md.
The terminal review does not convert the historical STOP or acceptance state:
STOP_NO_SOURCE and NOT_TESTED remain the authoritative historical values.