diff options
Diffstat (limited to '')
-rwxr-xr-x | tests/blockwise-compat | 377 |
1 files changed, 377 insertions, 0 deletions
diff --git a/tests/blockwise-compat b/tests/blockwise-compat new file mode 100755 index 0000000..a764020 --- /dev/null +++ b/tests/blockwise-compat @@ -0,0 +1,377 @@ +#!/bin/bash + +# set _FORCE_LOCAL environment variable to run blockwise unit tests even on local +# nfs. Some tests will fail because nfs is eager to write for example 4095 bytes +# in O_DIRECT mode. + +BW_UNIT=./unit-utils-io +STRACE=strace +MNT_DIR=./mnt_bwunit +LOCAL_FILE=./blockwise_localfile + +# $1 path to scsi debug bdev +scsi_debug_teardown() { + local _tries=15; + + while [ -b "$1" -a $_tries -gt 0 ]; do + rmmod scsi_debug 2> /dev/null + if [ -b "$1" ]; then + sleep .1 + _tries=$((_tries-1)) + fi + done + + test ! -b "$1" || rmmod scsi_debug +} + +cleanup() { + if [ -d "$MNT_DIR" ] ; then + umount -f $MNT_DIR 2>/dev/null + rmdir $MNT_DIR 2>/dev/null + fi + rm -f $LOCAL_FILE 2> /dev/null + scsi_debug_teardown "$DEV" || exit 100 +} + +fail() +{ + if [ -n "$1" ] ; then echo "FAIL $1" ; else echo "FAIL" ; fi + cleanup + exit 100 +} + +fail_count() +{ + echo "$MSG[FAIL]" + FAILS=$((FAILS+1)) +} + +warn_count() +{ + echo "$MSG[WARNING]" + WARNS=$((WARNS+1)) +} + +skip() +{ + echo "TEST SKIPPED: $1" + cleanup + exit 0 +} + +add_device() { + modprobe scsi_debug $@ delay=0 + if [ $? -ne 0 ] ; then + echo "This kernel seems to not support proper scsi_debug module, test skipped." + exit 77 + fi + DEV=$(grep -l -e scsi_debug /sys/block/*/device/model | cut -f4 -d /) + DEV="/dev/$DEV" + [ -b $DEV ] || fail "Cannot find $DEV." +} + +falloc() { + dd if=/dev/zero of=$2 bs=1M count=$1 2> /dev/null +} + +run_all_in_fs() { + for file in $(ls img_fs_*.img.xz) ; do + echo "Run tests in $file put on top block device." + xz -d -c $file | dd of=$DEV bs=1M 2>/dev/null || fail "bad image" + [ ! -d $MNT_DIR ] && mkdir $MNT_DIR + mount $DEV $MNT_DIR + if [ $? -ne 0 ]; then + echo "Mounting image $file failed, skipped." + continue; + fi + rm -rf $MNT_DIR/* 2>/dev/null + local tfile=$MNT_DIR/bwunit_tstfile + falloc $DEVSIZEMB $tfile || fail "enospc?" + local iobsize=$(stat -c "%o" $tfile) + test -n "$iobsize" -a $iobsize -gt 0 || fail + local oldbsize=$BSIZE + BSIZE=$iobsize + run_all $tfile + BSIZE=$oldbsize + umount $MNT_DIR + done +} + +trunc_file() { + test $1 -eq 0 || truncate -c -s $1 $2 2>/dev/null || dd if=/dev/zero of=$2 bs=$1 count=1 2>/dev/null || fail "Failed to truncate test file $2." +} + +RUN() { + local _res=$1 + shift + local _dev=$1 + shift + local _fn=$1 + shift + local _type="bdev" + local _fsize=0 + + test -b $_dev || { + _type="file" + _fsize=$(stat -c "%s" $_dev) + } + + case "$_res" in + P) + MSG="Testing $_fn on $_type with params $@ [expecting TRUE]..." + $BW_UNIT $_dev $_fn $@ + if [ $? -ne 0 ]; then + if [ $_type = "file" ]; then + warn_count + else + fail_count + fi + trunc_file $_fsize $_dev + test -z "$STRACE" || $STRACE -o ./$BW_UNIT-fail-$FAILS-should-pass.log $BW_UNIT $_dev $_fn $@ 2> /dev/null + else + MSG="$MSG[OK]" + fi + ;; + F) + MSG="Testing $_fn on $_type with params $@ [expecting FALSE]..." + $BW_UNIT $_dev $_fn $@ 2> /dev/null + if [ $? -eq 0 ]; then + if [ $_type = "file" ]; then + warn_count + else + fail_count + fi + trunc_file $_fsize $_dev + test -z "$STRACE" || $STRACE -o ./$BW_UNIT-fail-$FAILS-should-fail.log $BW_UNIT $_dev $_fn $@ 2> /dev/null + else + MSG="$MSG[OK]" + fi + ;; + *) + fail "Internal test error" + ;; + esac + + trunc_file $_fsize $_dev +} + +run_all() { + if [ -b "$1" ]; then + BD_FAIL="F" + else + BD_FAIL="P" + fi + + # buffer io support only blocksize aligned ios + # device/file fn_name length + RUN "P" $1 read_buffer $BSIZE + RUN "P" $1 read_buffer $((2*BSIZE)) + RUN "F" $1 read_buffer $((BSIZE-1)) + RUN "F" $1 read_buffer $((BSIZE+1)) + RUN "P" $1 read_buffer 0 + + RUN "P" $1 write_buffer $BSIZE + RUN "P" $1 write_buffer $((2*BSIZE)) + + RUN "F" $1 write_buffer $((BSIZE-1)) + RUN "F" $1 write_buffer $((BSIZE+1)) + RUN "F" $1 write_buffer 0 + + # basic blockwise functions + # device/file fn_name length bsize + RUN "P" $1 read_blockwise 0 $BSIZE + RUN "P" $1 read_blockwise $((BSIZE)) $BSIZE + RUN "P" $1 read_blockwise $((BSIZE-1)) $BSIZE + RUN "P" $1 read_blockwise $((BSIZE+1)) $BSIZE + RUN "P" $1 read_blockwise $((DEVSIZE)) $BSIZE + RUN "P" $1 read_blockwise $((DEVSIZE-1)) $BSIZE + RUN "F" $1 read_blockwise $((DEVSIZE+1)) $BSIZE + + RUN "P" $1 write_blockwise 0 $BSIZE + RUN "P" $1 write_blockwise $((BSIZE)) $BSIZE + RUN "P" $1 write_blockwise $((BSIZE-1)) $BSIZE + RUN "P" $1 write_blockwise $((BSIZE+1)) $BSIZE + RUN "P" $1 write_blockwise $((DEVSIZE)) $BSIZE + RUN "P" $1 write_blockwise $((DEVSIZE-1)) $BSIZE + RUN "$BD_FAIL" $1 write_blockwise $((DEVSIZE+1)) $BSIZE + + # seek variant blockwise functions + # device/file fn_name length bsize offset + RUN "P" $1 read_lseek_blockwise 0 $BSIZE 0 + RUN "P" $1 read_lseek_blockwise 0 $BSIZE 1 + RUN "P" $1 read_lseek_blockwise 0 $BSIZE $((DEVSIZE)) + # length = 0 is significant here + RUN "P" $1 read_lseek_blockwise 0 $BSIZE $((DEVSIZE+1)) + + # beginning of device + RUN "P" $1 read_lseek_blockwise 1 $BSIZE 0 + RUN "P" $1 read_lseek_blockwise 1 $BSIZE 1 + RUN "P" $1 read_lseek_blockwise 1 $BSIZE $((BSIZE-1)) + RUN "P" $1 read_lseek_blockwise 1 $BSIZE $((BSIZE/2)) + + # somewhere in the 'middle' + RUN "P" $1 read_lseek_blockwise 1 $BSIZE $BSIZE + RUN "P" $1 read_lseek_blockwise 1 $BSIZE $((BSIZE+1)) + RUN "P" $1 read_lseek_blockwise 1 $BSIZE $((2*BSIZE-1)) + RUN "P" $1 read_lseek_blockwise 1 $BSIZE $((BSIZE+BSIZE/2-1)) + + # cross-sector tests + RUN "P" $1 read_lseek_blockwise 2 $BSIZE $((BSIZE-1)) + RUN "P" $1 read_lseek_blockwise $((BSIZE+1)) $BSIZE $((BSIZE-1)) + RUN "P" $1 read_lseek_blockwise $((BSIZE+2)) $BSIZE $((BSIZE-1)) + RUN "P" $1 read_lseek_blockwise 2 $BSIZE $((2*BSIZE-1)) + RUN "P" $1 read_lseek_blockwise $((BSIZE+1)) $BSIZE $((2*BSIZE-1)) + RUN "P" $1 read_lseek_blockwise $((BSIZE+2)) $BSIZE $((2*BSIZE-1)) + + # including one whole sector + RUN "P" $1 read_lseek_blockwise $((BSIZE+2)) $BSIZE $((BSIZE)) + RUN "P" $1 read_lseek_blockwise $((2*BSIZE)) $BSIZE $((BSIZE+1)) + RUN "P" $1 read_lseek_blockwise $((2*BSIZE)) $BSIZE $((BSIZE-1)) + RUN "P" $1 read_lseek_blockwise $((BSIZE+2)) $BSIZE $((BSIZE-1)) + RUN "P" $1 read_lseek_blockwise $((2*BSIZE)) $BSIZE $((BSIZE+1)) + RUN "P" $1 read_lseek_blockwise $((3*BSIZE-2)) $BSIZE $((BSIZE+1)) + + # hiting exactly the sector boundary + RUN "P" $1 read_lseek_blockwise $((BSIZE-1)) $BSIZE 1 + RUN "P" $1 read_lseek_blockwise $((BSIZE-1)) $BSIZE $((BSIZE+1)) + RUN "P" $1 read_lseek_blockwise $((BSIZE+1)) $BSIZE $((BSIZE-1)) + RUN "P" $1 read_lseek_blockwise $((BSIZE+1)) $BSIZE $((2*BSIZE-1)) + + # device end + RUN "P" $1 read_lseek_blockwise 1 $BSIZE $((DEVSIZE-1)) + RUN "P" $1 read_lseek_blockwise $((BSIZE-1)) $BSIZE $((DEVSIZE-BSIZE+1)) + RUN "P" $1 read_lseek_blockwise $((BSIZE)) $BSIZE $((DEVSIZE-BSIZE)) + RUN "P" $1 read_lseek_blockwise $((BSIZE+1)) $BSIZE $((DEVSIZE-BSIZE-1)) + + # this must fail on both device and file + RUN "F" $1 read_lseek_blockwise 1 $BSIZE $((DEVSIZE)) + RUN "F" $1 read_lseek_blockwise $((BSIZE-1)) $BSIZE $((DEVSIZE-BSIZE+2)) + RUN "F" $1 read_lseek_blockwise $((BSIZE)) $BSIZE $((DEVSIZE-BSIZE+1)) + RUN "F" $1 read_lseek_blockwise $((BSIZE+1)) $BSIZE $((DEVSIZE-BSIZE)) + + RUN "P" $1 write_lseek_blockwise 0 $BSIZE 0 + # TODO: this may pass but must not write a byte (write(0) is undefined). + # Test it with underlying dm-error or phony read/write syscalls. + # Skipping read is optimization. + # HINT: currently it performs useless write and read as well + RUN "P" $1 write_lseek_blockwise 0 $BSIZE 1 + RUN "P" $1 write_lseek_blockwise 0 $BSIZE $BSIZE + + # beginning of device + RUN "P" $1 write_lseek_blockwise 1 $BSIZE 0 + RUN "P" $1 write_lseek_blockwise 1 $BSIZE 1 + RUN "P" $1 write_lseek_blockwise 1 $BSIZE $((BSIZE-1)) + RUN "P" $1 write_lseek_blockwise 1 $BSIZE $((BSIZE/2)) + + # somewhere in the 'middle' + RUN "P" $1 write_lseek_blockwise 1 $BSIZE $BSIZE + RUN "P" $1 write_lseek_blockwise 1 $BSIZE $((BSIZE+1)) + RUN "P" $1 write_lseek_blockwise 1 $BSIZE $((2*BSIZE-1)) + RUN "P" $1 write_lseek_blockwise 1 $BSIZE $((BSIZE+BSIZE/2-1)) + + # cross-sector tests + RUN "P" $1 write_lseek_blockwise 2 $BSIZE $((BSIZE-1)) + RUN "P" $1 write_lseek_blockwise $((BSIZE+1)) $BSIZE $((BSIZE-1)) + RUN "P" $1 write_lseek_blockwise $((BSIZE+2)) $BSIZE $((BSIZE-1)) + RUN "P" $1 write_lseek_blockwise 2 $BSIZE $((2*BSIZE-1)) + RUN "P" $1 write_lseek_blockwise $((BSIZE+1)) $BSIZE $((2*BSIZE-1)) + RUN "P" $1 write_lseek_blockwise $((BSIZE+2)) $BSIZE $((2*BSIZE-1)) + + # including one whole sector + RUN "P" $1 write_lseek_blockwise $((BSIZE+2)) $BSIZE $((BSIZE)) + RUN "P" $1 write_lseek_blockwise $((2*BSIZE)) $BSIZE $((BSIZE+1)) + RUN "P" $1 write_lseek_blockwise $((2*BSIZE)) $BSIZE $((BSIZE-1)) + RUN "P" $1 write_lseek_blockwise $((BSIZE+2)) $BSIZE $((BSIZE-1)) + RUN "P" $1 write_lseek_blockwise $((2*BSIZE)) $BSIZE $((BSIZE+1)) + RUN "P" $1 write_lseek_blockwise $((3*BSIZE-2)) $BSIZE $((BSIZE+1)) + + # hiting exactly the sector boundary + RUN "P" $1 write_lseek_blockwise $((BSIZE-1)) $BSIZE 1 + RUN "P" $1 write_lseek_blockwise $((BSIZE-1)) $BSIZE $((BSIZE+1)) + RUN "P" $1 write_lseek_blockwise $((BSIZE+1)) $BSIZE $((BSIZE-1)) + RUN "P" $1 write_lseek_blockwise $((BSIZE+1)) $BSIZE $((2*BSIZE-1)) + + # device end + RUN "P" $1 write_lseek_blockwise 1 $BSIZE $((DEVSIZE-1)) + RUN "P" $1 write_lseek_blockwise $((BSIZE-1)) $BSIZE $((DEVSIZE-BSIZE+1)) + RUN "P" $1 write_lseek_blockwise $((BSIZE)) $BSIZE $((DEVSIZE-BSIZE)) + RUN "P" $1 write_lseek_blockwise $((BSIZE+1)) $BSIZE $((DEVSIZE-BSIZE-1)) + + # this must fail on device, but pass on file (which is unfortunate and maybe design mistake) + RUN "$BD_FAIL" $1 write_lseek_blockwise 1 $BSIZE $((DEVSIZE)) + RUN "$BD_FAIL" $1 write_lseek_blockwise $((BSIZE-1)) $BSIZE $((DEVSIZE-BSIZE+2)) + RUN "$BD_FAIL" $1 write_lseek_blockwise $((BSIZE)) $BSIZE $((DEVSIZE-BSIZE+1)) + RUN "$BD_FAIL" $1 write_lseek_blockwise $((BSIZE+1)) $BSIZE $((DEVSIZE-BSIZE)) +} + +[ -n "$CRYPTSETUP_PATH" ] && skip "Cannot run this test with CRYPTSETUP_PATH set." + +which $STRACE > /dev/null 2>&1 || unset STRACE +test -x $BW_UNIT || skip "Run \"make `basename $BW_UNIT`\" first" + +FAILS=0 +WARNS=0 +DEVSIZEMB=2 +DEVSIZE=$((DEVSIZEMB*1024*1024)) + +PAGE_SIZE=$(getconf PAGE_SIZE) +echo "System PAGE_SIZE=$PAGE_SIZE" + +echo "Run tests in local filesystem" +falloc $DEVSIZEMB $LOCAL_FILE || fail "Failed to create file in local filesystem." +BSIZE=$(stat -c "%o" $LOCAL_FILE) +if [ $BSIZE -gt $((512*1024)) ]; then + echo "Detected file block size: $BSIZE bytes" + echo "Tuning it down to system page size ($PAGE_SIZE bytes)" + BSIZE=$PAGE_SIZE +fi +run_all $LOCAL_FILE + +[ $(id -u) -eq 0 ] || { + echo "WARNING: You must be root to run remaining tests." + test $FAILS -eq 0 || fail "($FAILS wrong result(s) in total)" + cleanup + exit 0 +} + +DEVBSIZE=512 +BSIZE=$DEVBSIZE +EXP=0 +DEVSIZEMBIMG=32 + +echo "# Create classic 512B drive" +echo "# (logical_block_size=$DEVBSIZE, physical_block_size=$((DEVBSIZE*(1<<EXP))))" +add_device dev_size_mb=$DEVSIZEMB sector_size=$DEVBSIZE physblk_exp=$EXP num_tgts=1 +run_all $DEV +cleanup +add_device dev_size_mb=$DEVSIZEMBIMG sector_size=$DEVBSIZE physblk_exp=$EXP num_tgts=1 +run_all_in_fs +cleanup + +EXP=3 +echo "# Create desktop-class 4K drive" +echo "# (logical_block_size=$DEVBSIZE, physical_block_size=$((DEVBSIZE*(1<<EXP))))" +add_device dev_size_mb=$DEVSIZEMB physblk_exp=$EXP sector_size=$DEVBSIZE num_tgts=1 +run_all $DEV +BSIZE=$((DEVBSIZE*(1<<EXP))) +run_all $DEV +cleanup + +add_device dev_size_mb=$DEVSIZEMBIMG physblk_exp=$EXP sector_size=$DEVBSIZE num_tgts=1 +run_all_in_fs +cleanup + +DEVBSIZE=4096 +BSIZE=$DEVBSIZE +EXP=0 +echo "# Create enterprise-class 4K drive" +echo "# (logical_block_size=$DEVBSIZE, physical_block_size=$((DEVBSIZE*(1<<EXP))))" +add_device dev_size_mb=$DEVSIZEMB physblk_exp=$EXP sector_size=$DEVBSIZE num_tgts=1 +run_all $DEV +cleanup +add_device dev_size_mb=$DEVSIZEMBIMG sector_size=$DEVBSIZE physblk_exp=$EXP num_tgts=1 +run_all_in_fs +cleanup + +test $WARNS -eq 0 || echo "(WARNING: $WARNS suspicious result(s) in total)" +test $FAILS -eq 0 || fail "($FAILS wrong result(s) in total)" |