DF-3093 / run5.sh
#!/bin/sh # DF-3093 run v5: sub-word free-run granularity. # # v4 proved (kernel DFDBG counters) that clusteralloc critical sections DO # overlap (66 events in one campaign) but 0 double-allocations: 256-cluster # free runs are word-aligned (256 % 32 == 0) so concurrent chainalloc() # commits never RMW the same pm_inusemap word, and pm_nxtfree is advanced # at commit START, which steers later scanners away from the frontier. # # v5 geometry: free runs of exactly 4 clusters (half a bitmap word), so # concurrent commits of ADJACENT free runs read-modify-write the SAME # pm_inusemap word non-atomically (msdosfs_fat.c:385 `|=`, no lock, no # atomics). A lost update leaves an ALLOCATED cluster's bit clear ("free") # -> the next allocation hands that cluster to a second file: cross-link. # # volume: 320 MiB FAT32, 4 KiB clusters (81920 clusters) # fill: 8192 x 16 KiB files (4-cluster runs) + one big file for the tail # delete every other small file -> 4096 free runs of 4 clusters, no tail # race: 6 pinned procs x N rounds x 2 MiB (512-cluster) writes; # each write = 128 fallback-scan iterations, each committing a # 4-cluster run (4 non-atomic word RMWs inside shared words). # # usage: run5.sh [cycles] [procs] [rounds] [chunk] set -u ID=DF-3093 MNT=/mnt/df3093 VND=vn0 IMG=/root/df3093.img CYCLES=${1:-2} PROCS=${2:-6} ROUNDS=${3:-3} CHUNK=${4:-2097152} DIR="$(dirname "$0")" cleanup() { umount $MNT 2>/dev/null || true vnconfig -u $VND 2>/dev/null || true } trap cleanup EXIT cd "$DIR" || exit 1 cc -O2 -o race2 race2.c || exit 1 cc -O2 -o fat_scan fat_scan.c || exit 1 c=1 while [ $c -le $CYCLES ]; do echo "=== cycle $c/$CYCLES: half-word fragment + ${PROCS}p x ${ROUNDS}r x ${CHUNK}B ===" cleanup rm -f $IMG newfs_msdos -C 320m -c 8 $IMG >/dev/null 2>&1 || { echo newfs fail; exit 1; } vnconfig -c $VND $IMG mkdir -p $MNT mount_msdos -m 644 /dev/$VND $MNT || { echo mount fail; exit 1; } sysctl -n debug.df3093_overlaps debug.df3093_double > /tmp/dfdbg.before 2>/dev/null # fill: 8192 small files (4-cluster runs) then one tail file i=0 while [ $i -lt 8192 ]; do dd if=/dev/zero of=$MNT/S$(printf %05d $i) bs=16k count=1 \ >/dev/null 2>&1 i=$((i + 1)) done dd if=/dev/zero of=$MNT/TAIL bs=1m count=180 >/dev/null 2>&1 # free every other small run i=1 while [ $i -lt 8192 ]; do rm -f $MNT/S$(printf %05d $i) i=$((i + 2)) done echo "fragmented: $(df $MNT | tail -1 | awk '{print $4}') 512B-secs free" ./race2 $MNT $PROCS $ROUNDS $CHUNK 1 sync echo "df after race: $(df $MNT | tail -1 | awk '{print $4}') free" umount $MNT vnconfig -u $VND echo "DFDBG before: $(cat /tmp/dfdbg.before | tr '\n' ' ')" echo "DFDBG after: $(sysctl -n debug.df3093_overlaps debug.df3093_double | tr '\n' ' ')" echo "DFDBG dmesg lines: $(dmesg | grep -c DFDBG)" dmesg | grep DFDBG | head -5 if ./fat_scan $IMG; then : else echo "=== CYCLE $c: FAT SCAN FOUND CROSS-LINKS ===" cp $IMG /root/df3093-hit-$c.img exit 42 fi c=$((c + 1)) done echo "RESULT $ID: run5 complete" |