# Test Case: HEAD2, Interlaced, and Extent Mapping

**Overall Status Rule**: **PARTIAL** when HEAD2 and interlaced pass but the
explicit mapped-payload subscenario remains **SHELVED**; see
`issues/extent-metadata-fixture-unavailable.md`

**Test ID**: TC146-head2-interlaced-extent-mapping

**G5 fixture contract**: Use [G5-MANUAL-SETUP.md](G5-MANUAL-SETUP.md).
Its generated paths, source comparisons, structured corruption offsets, and
cleanup rules supersede placeholder examples in this file.
**Category**: Compression Mapping
**Priority**: Critical
**Regression**: New compressed mapping formats

## Objective
Verify FreeBSD kernel reads for HEAD2 and interlaced pclusters, and independently
review extent-record mapping when erofs-utils 1.8.6 cannot generate that format.

## Preconditions
- FreeBSD 15 guest and repo22 module.
- HEAD2 fixture with byte-level assertions:
  - incompat bit `EROFS_FEATURE_INCOMPAT_COMPR_HEAD2` is set;
  - `Z_EROFS_ADVISE_BIG_PCLUSTER_2` is set;
  - a proven full-index HEAD record type is changed from HEAD1 to HEAD2;
  - the high algorithm nibble names the decoder used by HEAD2;
  - CRC32C is recomputed.
- Interlaced fixture generated by erofs-utils 1.8.6:
  ```sh
  mkfs.erofs -zlz4 -C4096 -Efragments -T0 \
    interlaced.erofs source-dir
  ```
  `dump.erofs -e` must show real 4096-byte plain extents interspersed with
  compressed extents.

## HEAD2 and Interlaced Steps
1. Prove the HEAD2 feature, map-header advise bits, algorithm nibbles, and HEAD2
   record before guest transfer.
2. Mount the HEAD2 image, hash the full file, and compare a read crossing the
   first logical pcluster boundary recorded by the manifest. Do not assume the
   logical boundary is 65536 merely because the physical pcluster limit is
   65536.
3. Read the targeted corrupted HEAD2 copy and record errno.
4. Mount the erofs-utils 1.8.6 interlaced image, hash the full file, and compare
   a range crossing the first compressed/plain transition.
5. Compare pre/post `dmesg` and clean all resources.

## Extent Metadata Static Review
Run these checks against exactly erofs-utils 1.8.6 and both reference trees:

```sh
mkfs.erofs -V
grep -R -E 'Z_EROFS_ADVISE_EXTENTS|z_erofs_extent_recsize|struct z_erofs_extent[[:space:]]*\{' \
  /work/build/erofs-utils-v1.8.6-source/include \
  /work/build/erofs-utils-v1.8.6-source/lib
grep -n "struct z_erofs_extent\|z_erofs_extent_recsize" \
  src/erofs_fs.h /work/dev-src-linux/fs/erofs/erofs_fs.h
grep -n "z_erofs_map_blocks_ext" \
  src/zmap.c /work/dev-src-linux/fs/erofs/zmap.c
```

Review all four record sizes (4, 8, 16, 32 bytes):
- 4-byte records use the initial 64-bit physical base and accumulated `plen`;
- 8-byte records carry per-record 32-bit physical starts;
- 16/32-byte records use explicit extent counts and binary search by logical
  start, with 32-byte records adding `lstart_hi`;
- `plen` format, partial-reference, interlaced/shifted, and final fragment
  encodings are decoded in Linux order;
- metadata reads route through the metabox when the inode NID has bit 63;
- malformed zero-count explicit tables and fragment bounds fail closed.

## Expected Results
- HEAD2 and interlaced full SHA256 and boundary reads match source bytes.
- Targeted HEAD2 corruption returns errno 5 (`EIO`) without a panic/trap.
- Explicit mapped-payload result is **SHELVED**, not PASS, because erofs-utils
  1.8.6 has no extent-record generator or on-disk extent structure and the
  structured helper cannot validate a relocated mapped payload.
- The static FreeBSD/Linux format and control-flow review is recorded
  separately from guest results.
- TC146 overall is **PARTIAL** unless all three subscenarios have dynamic
  positive coverage.

## Cleanup
Unmount all images, detach md units, unload by exact module ID, and verify no
new `dmesg` lines.
