# G6 Chunk and Multi-Device Manual Setup

This setup applies only to `TC006`, `TC093` through `TC101`, and `TC118`.
There are exactly 11 test cases.  The commands below generate new inputs; no
fixture or result from an earlier run is an input.

## Host prerequisites

- Linux host with erofs-utils 1.8.6 (`mkfs.erofs` and `fsck.erofs`).
- Python 3.11 or newer.
- QEMU with qcow2 support.
- A clean FreeBSD 15 amd64 base disk used only as the backing file for a new
  per-run overlay.

Set a new run directory and generate the fixtures twice:

```sh
REPO=/path/to/worktree/repo-community/repo22
RUN=/work/build/repo22-g6-$(date -u +%Y%m%dT%H%M%SZ)
mkdir -p "$RUN"
cd "$REPO"
python3 -B tests/g6_multidev_fixtures.py generate \
  --output "$RUN/fixtures-a"
python3 -B tests/g6_multidev_fixtures.py generate \
  --output "$RUN/fixtures-b"
cmp "$RUN/fixtures-a/manifest.json" "$RUN/fixtures-b/manifest.json"
cmp "$RUN/fixtures-a/SHA256SUMS" "$RUN/fixtures-b/SHA256SUMS"
python3 -B tests/g6_multidev_fixtures.py verify "$RUN/fixtures-a"
```

`generate` refuses an existing output directory, fixes source bytes, UUIDs,
timestamps, worker count, and every binary transformation, and asserts the
old field before each patch.  `verify` checks every artifact size and SHA256,
then reparses superblock, device-table, and chunk-index fields from disk.

The manifest records two erofs-utils 1.8.6 limitations.  Its fsck qualifies
the mkfs split image, single-index image, explicit 2/3-slot images, table-at-0,
`uniaddr=0`, fragment image, and original two-block LZ4 pcluster.  Flatdev and
device-ID-0 unified relocation are qualified by the FreeBSD kernel reads in
TC094 and TC101 because this fsck release does not implement those mappings.

## Dedicated FreeBSD 15 VM

Create a new overlay and use only SSH port 9226 for this run:

```sh
qemu-img create -f qcow2 -F qcow2 \
  -b /work/build/vm-freebsd-dev-base.qcow2 \
  "$RUN/freebsd15-overlay.qcow2"
qemu-system-x86_64 -accel tcg,thread=multi -cpu qemu64 \
  -m 6144 -smp 4 \
  -drive file="$RUN/freebsd15-overlay.qcow2",if=virtio,format=qcow2 \
  -netdev user,id=net0,hostfwd=tcp:127.0.0.1:9226-:22 \
  -device virtio-net-pci,netdev=net0 -display none \
  -serial file:"$RUN/freebsd15-serial.log" -monitor none \
  -pidfile "$RUN/freebsd15-qemu.pid" \
  -D "$RUN/freebsd15-qemu.log" -daemonize
```

Record the guest identity before installing test artifacts:

```sh
uname -a
freebsd-version -ku
sysctl -n kern.osreldate
sha256 /boot/kernel/kernel
mdconfig -l
mount -p | awk '$3 == "erofs"'
```

The initial `mdconfig` and EROFS mount outputs must be empty.

## Exact-source KLD

On the host, record and archive the exact worktree source:

```sh
git rev-parse HEAD | tee "$RUN/source.commit"
git status --short
git archive --format=tar HEAD repo-community/repo22 | \
  gzip -n > "$RUN/repo22-source.tar.gz"
git archive --format=tar HEAD dev-freebsd-releng/sys | \
  gzip -n > "$RUN/freebsd-sys-source.tar.gz"
tar -C "$RUN/fixtures-a" -czf "$RUN/g6-fixtures.tar.gz" \
  SHA256SUMS manifest.json images sources
```

Transfer both archives to the new guest.  Authentication details remain
outside the repository:

```sh
scp -O -P 9226 "$RUN/repo22-source.tar.gz" \
  "$RUN/freebsd-sys-source.tar.gz" \
  "$RUN/g6-fixtures.tar.gz" root@127.0.0.1:/root/
```

Build natively in the guest, with no source edits:

```sh
mkdir -p /root/freebsd-src /root/repo22-g6-src /root/repo22-g6
tar -xzf /root/freebsd-sys-source.tar.gz -C /root/freebsd-src \
  --strip-components 1
tar -xzf /root/repo22-source.tar.gz -C /root/repo22-g6-src \
  --strip-components 2
tar -xzf /root/g6-fixtures.tar.gz -C /root/repo22-g6
cd /root/repo22-g6-src
grep -E '^(REVISION|BRANCH)=' /root/freebsd-src/sys/conf/newvers.sh
env WITH_ZSTDIO=1 FREEBSD_SRC=/root/freebsd-src ./build.sh
sha256 build/erofs.ko
file build/erofs.ko
cp build/erofs.ko /root/repo22-g6/erofs.ko
```

At baseline `6b33b4afb490be7d6fec70e499469c306a58435d`, the tracked sys tree is
15.0-RELEASE-p9 and the clean guest is p8; both report OSREL 1500068.  Record
this source/guest distinction rather than claiming they are the same patch
level.  Also record `source.commit`, `WITH_ZSTDIO=1`, FreeBSD source archive
SHA256, KLD SHA256, kernel SHA256, and all guest values in the report.

## Manual evidence rules

Run the commands in each TC Markdown directly.  Do not use a runner, CI job,
or test wrapper.  Before each test:

```sh
mkdir -p /mnt/g6
kldload /root/repo22-g6/erofs.ko
dmesg | tail -40 > /tmp/g6-dmesg-before
```

For a negative mount or read, capture the syscall result with `truss` and
record the named errno, not only command exit status:

```sh
truss -f -o /tmp/operation.truss command arguments
tail -20 /tmp/operation.truss
```

After every TC, unmount first, detach external providers in descending slot
order, detach the primary, and unload the module.  All four checks must report
zero:

```sh
mount -p | awk '$3 == "erofs" { print }'
mdconfig -l
kldstat -n erofs 2>/dev/null || true
sysctl -n kern.geom.conftxt | \
  awk '/Geom name: md9[0-3]$|Consumers:|Providers:|erofs/ { print }'
```

Also compare the new dmesg suffix and reject any panic, trap, assertion,
watchdog, or EROFS error not expected by the current negative operation.

## FreeBSD and Linux behavior

Linux EROFS accepts a device table at byte offset zero and excludes a slot
whose `uniaddr` is zero from device-ID-0 unified lookup; a nonzero device ID
still selects that slot.  FreeBSD uses explicit `device.<slot>=/dev/<provider>`
mount options because GEOM providers are not discovered from Linux block
device tags.  FreeBSD also holds one read-only GEOM consumer per provider, so
normal `mdconfig -d` returns `EBUSY` while mounted.  A forced GEOM orphan makes
later cold I/O return `ENXIO`; unmount must still release vnode, cdev, and GEOM
references.  These lifecycle details have no direct Linux loop-device
equivalent and are checked in TC006 and TC118.
