# DF-3012 experiment log (all Phase V attempts, chronological)

Guest: DragonFly 6.5-DEVELOPMENT #0 (Thu Jul 2 06:02:54 UTC 2026),
X86_64_GENERIC, INVARIANTS, 6 vCPU KVM, 4 GB RAM. All attacker processes
ran as `nobody`; root only set up vn/newfs/mount and took measurements.

Evidence channels used throughout:
- `dmesg | grep -c "reservation failed"` — hdkprintf is ungated
  (hammer.h:1606), so every add_bulk failure prints exactly once.
- `vmstat -m | awk '/HAMMER-others/'` — the m_misc zone where
  struct hammer_record is kmalloc'd; leaks here are permanent.
- `sysctl vfs.hammer.count_reservations`.

## E1 — plain fill + mmap/msync, 800M fs (512M undo), history mount
Fresh fs (264M usable / 38.8M avail). Stage A: 16K write loop until
ENOSPC (59,473,920 bytes, errno 28). Stage B: mmap 64M file, 2000×
dirty-page+msync(MS_SYNC) — **all 2000 "succeeded"**.
Zone 10→46 allocs (record churn only). 0 reservation failures.
Follow-up probe (probe.c): msync "success" with zero hammer disk-write
counter movement and a readback MATCH only for recently-touched pages;
dmesg carried `vnode_pager_putpages: I/O error 28` + `residual I/O
262144` — putpages routes through VOP_WRITE (vnode_pager.c:768), i.e.
the same checkspace gate; the pager's failure is not propagated to
msync's return value.  mmap is NOT a gate bypass.

## E2 — same fs, PRNG-unique pages (defeat dedup), 3 rounds
16384 pages × 16K pushed per round "ok"; readback of last page:
MISMATCH (data never reached the fs — gate rejected the putpages write,
pages stayed dirty in the object).  Zone unchanged, 0 failures.
(Lesson: E1/E2's earlier "successes" were partly dedup artifacts —
repeated/low-entropy blocks dedup in HAMMER1 and consume no bigblocks.)

## E3 — tiny-file spray, 800M fs: 20,000 then 40,000 files (unique 1-15B)
40,000 files created, 0 write failures, 241M used / 22.8M avail left.
Zone peaked 5.56K allocs during churn, settled 4.34K after rm+sync
(pending-delete record drain), 0 reservation failures.  The estimate's
rsv_recs/rsv_databytes accounting keeps up with tiny-file metadata.

## E4 — 256M fs with 64M undo (small-undo), nohistory
df showed avail=0 at format (df-side reserve ≥ free) — gate never passes;
abandoned (also hit su-quoting issue, fixed with /tmp/writers.sh).

## E5 — 6-parallel unique-data writers, 512M fs/64M undo on /root
(virtio/hammer2-backed image: slow drain) + /tmp/rand.bin source (fast
dirtying), nohistory. Stage 1 filled 199M to 100%: 0 failures. rm freed
(nohistory), stage 2 re-filled: 0 failures. Zone 10→150→169 allocs
(churn). The buffer flush pipeline stayed synchronous with write(2) —
no unaccounted in-flight window.

## E6 — E5 with gate headroom removed: sysctl
vfs.hammer.limit_dirtybufspace=2M (root-set, runtime RW sysctl; writes
still by nobody). Fill to 100%: STILL 0 reservation failures.
On this guest, strategy runs inside the write(2) path before the next
block's gate check, so pending reservations are always accounted and the
blockmap never runs dry behind the gate.

## Conclusion
The checkspace gate + synchronous strategy pipeline on this guest makes
`hammer_blockmap_reserve() == NULL` unreachable organically.  The leak
defect itself is code-certain; residual real-world triggers: freemap
bread I/O errors, concurrent admin ops (reblock/prune/mirror), drain-lag
topologies where in-flight dirty exceeds the 49M per-mount reserve
(hammer reserves half the global ~103M dirty cap), or reduced
limit_dirtybufspace on systems where strategies DO lag.
