summaryrefslogtreecommitdiffstats
path: root/tests/blockwise-compat-test
diff options
context:
space:
mode:
Diffstat (limited to 'tests/blockwise-compat-test')
-rwxr-xr-xtests/blockwise-compat-test379
1 files changed, 379 insertions, 0 deletions
diff --git a/tests/blockwise-compat-test b/tests/blockwise-compat-test
new file mode 100755
index 0000000..11db493
--- /dev/null
+++ b/tests/blockwise-compat-test
@@ -0,0 +1,379 @@
+#!/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 >/dev/null 2>&1
+ if [ -b "$1" ]; then
+ sleep .1
+ _tries=$((_tries-1))
+ fi
+ done
+
+ test ! -b "$1" || rmmod scsi_debug >/dev/null 2>&1
+}
+
+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 77
+}
+
+add_device() {
+ rmmod scsi_debug >/dev/null 2>&1
+ if [ -d /sys/module/scsi_debug ] ; then
+ skip "Cannot use scsi_debug module (in use or compiled-in)."
+ fi
+ modprobe scsi_debug $@ delay=0 >/dev/null 2>&1
+ if [ $? -ne 0 ] ; then
+ skip "This kernel seems to not support proper scsi_debug module."
+ fi
+ grep -q scsi_debug /sys/block/*/device/model || sleep 2
+ 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))
+}
+
+command -v $STRACE >/dev/null || 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)"