# DF-3696 — Degraded RAID5 I/O: request leaked and bio never completed → wedge / unbootable system

## Root cause (source)
`ata_raid_strategy` allocates an `ata_request` per chunk (`:386`), then for
RAID5 in DEGRADED state does nothing with it — the recovery path ("XOR
game") is unimplemented and the fall-through neither queues nor frees the
request nor completes the bio:

```c
609:	    if (rdp->status & AR_S_DEGRADED) {
610:		/* do the XOR game if possible */
611:	    }
612:	    else {
613:	        ... ata_raid_send_request(request); ...
	    }
	    break;
```

Consequences for every bio issued to a degraded RAID5 array:
- the `ata_request` allocated at `:386` is leaked (objcache exhaustion /
  kernel memory leak, one per chunk);
- `bp->b_resid` never reaches 0 and `biodone(bp)` is never called — the
  caller sleeps forever in biowait (unkillable disk I/O).

## Reproduce
`f7_r5deg.img` = FreeBSD/Promise RAID5 metadata: `width=2`, `total_disks=2`,
`disks[0]` ONLINE, `disks[1]` absent → array comes up DEGRADED (READY kept).
Boot with that single disk attached:

```
ar0: WARNING - parity protection lost. RAID5 array in DEGRADED mode
ar0: 48MB <FreeBSD PseudoRAID RAID5 (stripe 0 KB)> status: DEGRADED
ar0: disk0 READY using ad0 at ata0-master
ar0: disk1 DOWN no device found for this subdisk
```
…and nothing else: the kernel's MBR slice-scan of ar0 blocks forever (note
the missing `ar0: MBR magic not found` line that a completing probe prints).
ssh never comes up; the system is unbootable while the disk is present.
Captured in `panic.txt` (serial console).

## Expected
Baseline: boot wedges right after the ar0 lines (guest never reaches login;
`vm.sh status` → down).
Patched (fix.diff: degraded branch frees the request and fails the bio with
EIO): array announced, I/O errors out, boot proceeds to login
(`run.patched.log`).

## Impact
Persistent local DoS from crafted metadata (system cannot boot); with an
operator-built degraded RAID5, every read/write hangs its process and leaks
kernel memory (CWE-401 + CWE-835).

## Files
`mkmeta.py` (shared), `run.sh`, `panic.txt`, `run.patched.log`, `fix.diff`,
`verdict.json`
