# Test Case: Invalid Device Table

**Test ID**: TC097-device-table-invalid  
**Category**: Multi-Device / Error Handling
**Priority**: Critical

## Objective

Verify fail-closed table validation and complete cleanup after parse failure or
after slot 1 has opened and slot 2 fails.

## Deterministic negative fixtures

The G6 generator makes one asserted change per checksum-valid image:

| Image | Exact expected errno |
| --- | --- |
| `bad-table-oob.erofs` | `EINTEGRITY` |
| `bad-slot-zero-blocks.erofs` | `EINTEGRITY` |
| `bad-slot-inside-primary.erofs` | `EINTEGRITY` |
| `bad-slot-overlap.erofs` | `EINTEGRITY` |
| `bad-slot-32bit-limit.erofs` | `EINTEGRITY` |
| `bad-slot-48bit-limit.erofs` | `EINTEGRITY` |

An on-disk slot has only 48-bit `blocks` and `uniaddr`; their sum cannot
overflow a 64-bit C integer.  Therefore an alleged uint64-add-overflow fixture
is not representable.  The last image tests the real format boundary: a
48-bit range ending above `2^48`.  `devt_slotoff=0` and `uniaddr=0` are legal
TC096 positives, not invalid fixtures.

## Manual procedure for each structural image

For each row above, execute the following commands directly, replacing
`IMAGE` with that row.  Do not put the rows in a runner or shell loop.

```sh
I=/root/repo22-g6/images
IMAGE=bad-table-oob.erofs
mkdir -p /mnt/g6
kldload /root/repo22-g6/erofs.ko
mdconfig -a -t vnode -f "$I/$IMAGE" -u 90
mdconfig -a -t vnode -f "$I/multi2-slot1.blob" -u 91
mdconfig -a -t vnode -f "$I/multi2-slot2.blob" -u 92
truss -f -o "/tmp/tc097-$IMAGE.truss" mount -t erofs -o ro \
  -o device.1=/dev/md91 -o device.2=/dev/md92 /dev/md90 /mnt/g6
tail -20 "/tmp/tc097-$IMAGE.truss"
mount -p | awk '$3 == "erofs" { print }'
mdconfig -d -u 92
mdconfig -d -u 91
mdconfig -d -u 90
kldunload erofs
mdconfig -l
kldstat -n erofs 2>/dev/null || true
sysctl -n kern.geom.conftxt | grep -E 'md9[0-2]|erofs' || true
```

Each mount must return exactly `EINTEGRITY`.  After each individual failure,
the mount, md, KLD, and matching GEOM consumer outputs must all be empty before
proceeding to the next image.

## Reverse-open cleanup

This valid table opens slot 1 and then fails the slot-2 pathname lookup:

```sh
kldload /root/repo22-g6/erofs.ko
mdconfig -a -t vnode -f "$I/multi2-primary.erofs" -u 90
mdconfig -a -t vnode -f "$I/multi2-slot1.blob" -u 91
truss -f -o /tmp/tc097-reverse.truss mount -t erofs -o ro \
  -o device.1=/dev/md91 -o device.2=/no/such/repo22-g6-slot2 \
  /dev/md90 /mnt/g6
tail -20 /tmp/tc097-reverse.truss
mdconfig -d -u 91
mdconfig -d -u 90
kldunload erofs
```

The mount returns `ENOENT`, and immediate detach of md91 proves reverse-order
cleanup released the already-open consumer.

## Final zero-state check

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

All four outputs must be empty, with no panic, trap, hang, leaked mount, or
stale GEOM consumer.
