# DF-2284 — sgwrite() queues sg_rdwr that nothing but a matching sgread() ever frees

## What (sys/bus/cam/scsi/scsi_sg.c)
sgwrite: :652 kmalloc(sg_rdwr), :664 xpt_alloc_ccb(), :700/:706 buf,
:740 TAILQ_INSERT_TAIL(&sc->rdwr_done).  The ONLY free path is a
matching sgread (:807 TAILQ_REMOVE + :855-856 kfree).
sgoninvalidate (:169-191) carries the comment "XXX Return all queued I/O
with ENXIO" and drains NOTHING; sgcleanup (:194-206) kfrees the softc
with the list still populated.

## Reproduce (guest, root; single open, holder process keeps the fd open
so the DF-2282 close-underflow does not interleave with the measurement)

    cc -O -Wall -o sg2284 sg2284.c
    ./sg2284              # 400 write-only requests of 64 KiB, never read
    vmstat -m | grep devbuf   # before / after / after-close

## Result (run1.log, phase2.log, phase3.log)
* M_DEVBUF: 211 allocs / 208 K before -> 1011 allocs / **25.3M** after
  400 write-only requests (~64 KiB + ccb + rdwr each) — ~25 MB leaked
* phase 3 (kill holder -> last close -> sgoninvalidate + sgcleanup run
  with the list full): **1011 / 25.3M unchanged** — invalidation and
  cleanup freed NOTHING; the entries are orphaned forever (the softc
  itself is freed).

## Impact
Unbounded kernel-memory exhaustion by a write-only user of /dev/sgN
(RESTRICTEDROOT/operator gated; 0600 root-only on this guest).
Additionally the invalidation UAF surface (sleeping reader + freed
softc) is real — see DF-2283's run.log aggravation note where exactly
that combination wedged the guest.

## Fix
fix.diff drains rdwr_done in sgoninvalidate (completed entries) and in
sgcleanup (everything remaining) before the softc free.  Validated: see
VERDICT.md fix_validation.
