# DF-4801 verdict — REPRODUCED (permanent unkillable writer hang, deterministic), fix validated

- finding: `sd->waitlist` is drained ONLY from the tail of a successful
  `revive_block()` (`sys/dev/raid/vinum/vinumrevive.c:198-218`). The
  revive is driven one block per ioctl by userland `vinum start`; when
  that stops (killed, SIGSTOP, crash, scheduler starvation), queued
  conflicting writes (`launch_requests()`, `vinumrequest.c:327-355`)
  sleep in PCATCH-less `biowait` forever. No state transition
  (`set_sd_state`, detach, stop, unload) drains the list.
- guest: DragonFly dfbsd 6.5-DEVELOPMENT #0 (stock), mirrored concat
  volume on md drives.

## Runs (stock)

One `VINUM_SETSTATE(object_up, blocksize=64k)` ioctl primes the sd into
`sd_reviving` (cursor at 64k, empty waitlist, no drainer ever again);
four writers hammer `[64k,96k)` — every write is XFR_REVIVECONFLICT and
queues:

* all four writers freeze instantly, `D`-state (`wchan physstr`);
* `kill -9` on writers AND their dd children: **all four remain**;
* `vinum setstate -f down vol.p1.s0` (explicit revive abort): **all four
  remain** (`>>> STILL HUNG AFTER ABORT <<<`, `run.log`).

Deterministic (no race needed): the writers' requests are queued the
moment they straddle the frozen cursor; the trigger deliberately avoids
the DF-4482/DF-4721 launch paths so the hang shows in isolation.
4/4 writers hung; the requests and their buffers leak until reboot.

Unprivileged angle: any filesystem mounted on the volume turns every
user write that straddles a frozen/abandoned cursor into a permanent
unkillable hang of that user's process.

## Fix validation

`fix.diff`: `drain_sd_waitlist()` (atomic steal; relaunch if the sd came
up, else biodone(EIO)+freerq) hooked into `set_sd_state()` on every
real transition out of `sd_reviving`. Patched module, same workload:
writers still freeze while queued (expected), and the abort drains them
— post-abort ps shows **no dd left** (`fix_run.log`), vs. stock's four
immortal D-state writers.

fix_status: **fixed** (baseline_reproduced=1, patched_reproduced=0).

Residual (documented in fix.diff): transitions that bypass
`set_sd_state`'s commit point (e.g. the `driveoffset < 0` early path,
direct slot reuse) are not covered; a full redesign would keep the
waitlist in the sd's own teardown.

## Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest `make -j6 nativekernel KERNCONF=X86_64_GENERIC` completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
