# DF-2701 — swap_pager_getpage() timeout diagnostic dereferences a pbuf that completion may already have freed

## Status: **untested** (Info severity — below the verification threshold; mechanism is certain, trigger needs a >20 s stalled swap I/O)

## Build / run (of the accompanying negative-result validation, which WAS run)

```
# on the guest, as root:
sysctl vm.report_swap_allocs=400
cc -O2 -o /tmp/hog hog.c && /tmp/hog      # ~5 GB touch storm on a 4 GB box
dmesg | grep swap_alloc > swap_allocs.txt # 400 (blk, n) allocation records
```

Expected (validation, observed): 400 allocations, 268 at non-16-aligned offsets
(heavy fragmentation), **0 runs crossing a SWB_DMMAX stripe boundary**,
40 runs ending exactly on a stripe boundary (live fire of known DF-0948's
trigger), all runs confined to interleave slot 0 (single active swap device).

## The finding itself (not reproduced; Info)

`sys/vm/swap_pager.c:1486-1490` states bp is invalid after `vn_strategy()`.
`sys/vm/swap_pager.c:1527-1535` violates that invariant: when the 20 s
`tsleep()` times out, the kprintf dereferences `bio->bio_offset` and
`bp->b_bcount` — if the I/O completes in the window between timeout wakeup and
the kprintf, `swp_pager_async_iodone()` has already `relpbuf()`'d the bp and it
may have been reused by any other swap I/O. UAF-read confined to a console
diagnostic.

## Fix sketch

Save `bio_offset` and `b_bcount` into locals before `vn_strategy()` (alongside
`blk`/`i`) and print those.
