#!/bin/sh
# DF-0117 PoC run script (single-shot per invocation; reset between variants).
#
# ENVIRONMENT PRECONDITIONS
#   - DragonFlyBSD master DEV guest (tested: v6.5.0.1712.g89e6DEVELOPMENT).
#   - Run as ROOT (must open /dev/vbd0 and issue DIOCRECLUSTER; the raw disk
#     node is root:operator crw-r-----, so unprivileged users cannot trigger
#     the LOCAL vector).
#   - The kernel comconsole is baked into the clean-install baseline, so any
#     panic + DDB trace is already captured in dfbsd-qemu/boot.log.  Do NOT
#     re-add console="comconsole" or reboot to enable capture.
#
# WHAT THIS DOES
#   1. Kill the hammer2 userland cluster daemon (frees the disk DMSG iocom
#      that it pre-connects at boot; otherwise DIOCRECLUSTER deadlocks).
#   2. Run ./trigger <nreads> <mode> <preclose_us> ONCE: opens /dev/vbd0,
#      builds an AF_UNIX socketpair, attaches one end to the kernel disk
#      DMSG iocom via DIOCRECLUSTER, writes <nreads> forged
#      DMSG_BLK_READ|CREATE[|DELETE] messages (each dispatches a real async
#      disk I/O storing bio->bio_caller_info1.ptr = msg->state with NO state
#      hold), then closes the socket to race the I/O completions against the
#      writer-thread teardown (kdmsg_simulate_failure -> state abort/free).
#
# EXPECTED (bug present): kernel panic in diskiodone / kdmsg_state_free /
#   page fault on freed kdmsg_state_t memory; guest freezes in DDB.
# EXPECTED (state protected by topology refs): trigger exits cleanly, guest
#   stays up, dmesg clean.
#
# The script invokes one mode then exits.  To test the other modes, rerun
# with an arg (0/1/2) AFTER a guest reset, because each run consumes the
# disk iocom and a second DIOCRECLUSTER in the same boot can deadlock.
#
set -u
cd "$(dirname "$0")"
MODE="${1:-0}"
NREADS="${2:-256}"
PRECLOSE="${3:-2000}"

[ "$(id -u)" = "0" ] || { echo "run.sh: must be run as root (need DIOCRECLUSTER on /dev/vbd0)" >&2; exit 1; }
[ -x ./trigger ] || { echo "run.sh: ./trigger not built; run ./build.sh first" >&2; exit 1; }

# 1. free the disk DMSG iocom (kill the boot-time hammer2 daemon)
pkill -9 -x hammer2 2>/dev/null
sleep 2
echo "[setup] killed hammer2 daemon; disk DMSG iocom is free"

# 2. fire the trigger once for the requested mode
echo "============================================================"
echo "[run] mode=$MODE  ./trigger $NREADS $MODE $PRECLOSE"
echo "------------------------------------------------------------"
./trigger "$NREADS" "$MODE" "$PRECLOSE"
echo "TRIGGER_EXIT=$?  (mode=$MODE)"
echo "============================================================"
echo "[done] mode=$MODE completed without userspace-detected panic"
echo "       (check dmesg + dfbsd-qemu/boot.log for kernel-side faults)"
