DF-4801 / hang.sh
#!/bin/sh # DF-4801 exact trigger (panic-free variant): revive waitlist orphaned. # # The revive state machine is driven one block per ioctl by userland. # sd->waitlist is drained ONLY from revive_block()'s success path # (vinumrevive.c:198-218). Prime the sd into sd_reviving with ONE # `setstate up` (runs exactly one clean revive_block with a 64k block, # empty waitlist; cursor lands at sector 128 = byte 64k), then simply # never drive it again: every write straddling the cursor is queued on # the waitlist forever. No set_sd_state transition away from # sd_reviving (down/stale/detach/stop) drains it, so the writers hang # uninterruptibly (biowait without PCATCH). # # Writers target ONLY the straddle window [64k,96k) so every write is # XFR_REVIVECONFLICT -> waitlisted (never the REQUEST_DOWN / # trailing-BAD-group launch path of the DF-4721 arm, so this trigger # is deterministic and does not race the UAF). # # Expect (stock): writers freeze in state D immediately; kill -9 # ineffective; `vinum setstate -f down` (aborting the revive) leaves # them hung. Expect (fix): abort drains -> writers return (EIO). date echo "== setup ==" sh /tmp/df4800_setup.sh echo "== prime sd into sd_reviving (one 64k block via ONE ioctl, then STOP driving it) ==" cc -O -o /tmp/prime /tmp/prime.c 2>/dev/null || echo "prime build failed" /tmp/prime 1 vinum list | tr -d "\r" | grep -E "^S " echo "== 4 writers hammering the straddle window [64k,96k) ==" for id in 1 2 3 4; do ( i=0 while [ ! -f /tmp/df4801.stop ]; do off=$(( 16 + id % 8 )) dd if=/dev/zero of=/dev/vinum/vol/vol bs=4k seek=$off count=1 conv=notrunc >/dev/null 2>&1 i=$((i + 1)) echo $i > /tmp/df4801.w.$id done ) & eval WPID$id=$! done sleep 3 echo "== writer progress (should be FROZEN: waitlisted, no drainer) ==" for id in 1 2 3 4; do echo "writer$id: $(cat /tmp/df4801.w.$id 2>/dev/null) writes"; done sleep 3 echo "-- +3s --" for id in 1 2 3 4; do echo "writer$id: $(cat /tmp/df4801.w.$id 2>/dev/null) writes"; done echo "== ps: hung writers ==" ps -axww -o pid,stat,wchan,command | grep -E "[d]d if=/dev/zero of=/dev/vinum|seek=\$" | head -8 echo "== kill -9 the writer subshells AND dd children ==" for id in 1 2 3 4; do kill -9 $(eval echo \$WPID$id) 2>/dev/null; done pkill -9 -f "dd if=/dev/zero of=/dev/vinum" 2>/dev/null sleep 3 echo "-- after kill -9 --" N=$(ps -axww -o pid,stat | awk '$2 ~ /^D/ {n++} END {print n+0}') echo "D-state threads now: $N" ps -axww -o pid,stat,wchan,command | grep "[d]d if=/dev/zero of=/dev/vinum" && echo ">>> UNKILLABLE HUNG WRITERS <<<" || echo "writers gone (no hang)" echo "== abort the revive: setstate down -- does anything drain? ==" vinum setstate -f down vol.p1.s0 2>&1 | tr -d '\r' | head -3 sleep 3 echo "-- after revive abort --" ps -axww -o pid,stat,wchan,command | grep "[d]d if=/dev/zero of=/dev/vinum" && echo ">>> STILL HUNG AFTER ABORT <<<" || echo "writers gone (drained: fix working)" vinum list | tr -d "\r" | grep -E "^S " touch /tmp/df4801.stop dmesg | tail -3 date |