# DF-0813 — hammer2_flush() NULL-deref in retry loop

## Summary

`sys/vfs/hammer2/hammer2_flush.c` retry loop (lines 397-406) dereferences
`info.parent` at lines 403 (`hammer2_chain_drop`) and 405 (`hammer2_chain_ref`)
**without a NULL guard**. The setup (382-383) and teardown (434-435) of the same
function correctly guard against NULL. If `chain->parent` becomes NULL during
`flush_core` (via concurrent delete at `hammer2_chain.c:3559`), the retry loop
crashes with a NULL deref panic.

**Status: NOT REPRODUCED.** The code defect is confirmed real (missing NULL
guard, inconsistent with setup/teardown), but the trigger is an extremely tight
race between hammer2 flush and concurrent chain deletion. ~15 min of aggressive
churn on two hammer2 mounts (with debug trace bit 0x0040 enabled showing the
retry-loop body never fired) produced zero panics.

**Impact ceiling:** NULL-deref panic / DoS (no escalation — fixed-offset deref).

## How to reproduce (best-effort — race is probabilistic)

```sh
# 1. root: create + mount a hammer2 image
sudo sh setup_h2.sh
# (if label is DATA not DEFAULT: mount_hammer2 /dev/vn0@DATA /mnt/h2 && chmod 1777 /mnt/h2)

# 2. user: build + run the churn harness
./build.sh
H2DIR=/mnt/h2 SECS=300 ./run.sh

# 3. check for panic
dmesg | grep -i panic
# or check the serial console boot.log
```

The race may require extended churn (many minutes) to win, if winnable at all
from pure userspace. Enable `sysctl vfs.hammer2.debug=0x40` to observe "LOST
CHILD4" trace messages (which fire when the retry-loop body executes at all).

## Fix

See `fix.diff` — adds `if (info.parent)` guards at lines 403/405, consistent
with the setup and teardown. Validated: applies cleanly, compiles, boots (#7),
runs the PoC without regression.
