fstests: check if the scratch device is an lv device for certain tests
[xfstests-dev.git] / common / rc
index d4ad421ed5c7f09ed00a951afe8b75531cc80d1e..0a30a8421328043da671e00384e46c86ccece5c1 100644 (file)
--- a/common/rc
+++ b/common/rc
@@ -4,7 +4,7 @@
 
 . common/config
 
-BC=$(which bc 2> /dev/null) || BC=
+BC="$(type -P bc)" || BC=
 
 _require_math()
 {
@@ -339,7 +339,7 @@ _try_scratch_mount()
 # mount scratch device with given options and _fail if mount fails
 _scratch_mount()
 {
-       _try_scratch_mount $* || _fail "mount failed"
+       _try_scratch_mount $* || _fail "mount $(_scratch_mount_options $*) failed"
 }
 
 _scratch_mount_idmapped()
@@ -631,6 +631,30 @@ _ext4_metadump()
                $DUMP_COMPRESSOR -f "$dumpfile" &>> "$seqres.full"
 }
 
+# Capture the metadata of a filesystem in a dump file for offline analysis.
+# This is not supported by all filesystem types, so this function should only
+# be used after a test has already failed.
+_metadump_dev() {
+       local device="$1"
+       local dumpfile="$2"
+       local compressopt="$3"
+
+       test "$DUMP_CORRUPT_FS" = 1 || return 0
+
+       case "$FSTYP" in
+       ext*)
+               _ext4_metadump $device $dumpfile $compressopt
+               ;;
+       xfs)
+               _xfs_metadump $dumpfile $device none $compressopt
+               ;;
+       *)
+               echo "Don't know how to metadump $FSTYP"
+               return 1
+               ;;
+       esac
+}
+
 _test_mkfs()
 {
     case $FSTYP in
@@ -893,15 +917,15 @@ _scratch_dev_pool_get()
                _fail "Usage: _scratch_dev_pool_get ndevs"
        fi
 
-       local test_ndevs=$1
-       local config_ndevs=`echo $SCRATCH_DEV_POOL| wc -w`
-       local -a devs="( $SCRATCH_DEV_POOL )"
-
-       typeset -p config_ndevs >/dev/null 2>&1
+       typeset -p SCRATCH_DEV_POOL >/dev/null 2>&1
        if [ $? -ne 0 ]; then
                _fail "Bug: cant find SCRATCH_DEV_POOL ndevs"
        fi
 
+       local test_ndevs=$1
+       local config_ndevs=`echo $SCRATCH_DEV_POOL| wc -w`
+       local -a devs="( $SCRATCH_DEV_POOL )"
+
        if [ $config_ndevs -lt $test_ndevs ]; then
                _notrun "Need at least test requested number of ndevs $test_ndevs"
        fi
@@ -956,6 +980,16 @@ _available_memory_bytes()
        fi
 }
 
+_check_minimal_fs_size()
+{
+       local fssize=$1
+
+       if [ -n "$MIN_FSSIZE" ]; then
+               [ $MIN_FSSIZE -gt "$fssize" ] &&
+                       _notrun "specified filesystem size is too small"
+       fi
+}
+
 # Create fs of certain size on scratch device
 # _scratch_mkfs_sized <size in bytes> [optional blocksize]
 _scratch_mkfs_sized()
@@ -968,7 +1002,10 @@ _scratch_mkfs_sized()
        xfs)
                def_blksz=`echo $MKFS_OPTIONS | sed -rn 's/.*-b ?size= ?+([0-9]+).*/\1/p'`
                ;;
-       ext2|ext3|ext4|ext4dev|udf|btrfs|reiser4|ocfs2|reiserfs)
+       btrfs)
+               def_blksz=`echo $MKFS_OPTIONS | sed -rn 's/.*-s ?+([0-9]+).*/\1/p'`
+               ;;
+       ext2|ext3|ext4|ext4dev|udf|reiser4|ocfs2|reiserfs)
                def_blksz=`echo $MKFS_OPTIONS | sed -rn 's/.*-b ?+([0-9]+).*/\1/p'`
                ;;
        jfs)
@@ -989,6 +1026,8 @@ _scratch_mkfs_sized()
 
        local blocks=`expr $fssize / $blocksize`
 
+       _check_minimal_fs_size $fssize
+
        if [ -b "$SCRATCH_DEV" ]; then
                local devsize=`blockdev --getsize64 $SCRATCH_DEV`
                [ "$fssize" -gt "$devsize" ] && _notrun "Scratch device too small"
@@ -1637,6 +1676,17 @@ _require_scratch_nocheck()
     rm -f ${RESULT_DIR}/require_scratch
 }
 
+# we need the scratch device and it needs to not be an lvm device
+_require_scratch_nolvm()
+{
+       _require_scratch_nocheck
+
+       # This works if we don't have LVM, all we want is to skip if the scratch
+       # device is an lvm device.
+       $LVM_PROG lvdisplay $SCRATCH_DEV > /dev/null 2>&1
+       [ $? -eq 0 ] && _notrun "test requires a non-lvm scratch device"
+}
+
 # we need the scratch device and it should be checked post test.
 _require_scratch()
 {
@@ -1822,6 +1872,9 @@ _require_loop()
     else
        _notrun "This test requires loopback device support"
     fi
+
+    # loop device does not handle zone information
+    _require_non_zoned_device ${TEST_DEV}
 }
 
 # this test requires kernel support for a secondary filesystem
@@ -1922,10 +1975,33 @@ _require_sane_bdev_flush()
        fi
 }
 
+# Decide if the scratch filesystem is likely to be mounted in fsdax mode.
+# It goes 3 ways based on mount options::
+#      1. "dax" or "dax=always" means always test using DAX
+#      2. "dax=never" means we'll never use DAX
+#      3. "dax=inode" or nothing means "use scratch dev capability" to
+#          determine whether DAX is going to be used.
+#
+# Returns 0 if DAX will be used, 1 if DAX is not going to be used.
+__scratch_uses_fsdax()
+{
+       local ops=$(_normalize_mount_options)
+
+       echo $ops | egrep -qw "dax(=always| |$)" && return 0
+       echo $ops | grep -qw "dax=never" && return 1
+
+       local sysfs="/sys/block/$(_short_dev $SCRATCH_DEV)"
+       test -e "${sysfs}/dax" && return 0
+       test "$(cat "${sysfs}/queue/dax" 2>/dev/null)" = "1" && return 0
+       return 1
+}
+
 # this test requires a specific device mapper target
 _require_dm_target()
 {
        local target=$1
+       local fsdax
+       local bdevdax
 
        # require SCRATCH_DEV to be a valid block device with sane BLKFLSBUF
        # behaviour
@@ -1933,9 +2009,7 @@ _require_dm_target()
        _require_sane_bdev_flush $SCRATCH_DEV
        _require_command "$DMSETUP_PROG" dmsetup
 
-       _normalize_mount_options | egrep -q "dax(=always| |$)" || \
-                       test -e "/sys/block/$(_short_dev $SCRATCH_DEV)/dax"
-       if [ $? -eq 0 ]; then
+       if __scratch_uses_fsdax; then
                case $target in
                stripe|linear|log-writes)
                        ;;
@@ -1951,6 +2025,16 @@ _require_dm_target()
        if [ $? -ne 0 ]; then
                _notrun "This test requires dm $target support"
        fi
+
+       # dm-error cannot handle the zone information
+       #
+       # dm-snapshot and dm-thin-pool cannot ensure sequential writes on
+       # the backing device
+       case $target in
+       error|snapshot|thin-pool)
+               _require_non_zoned_device ${SCRATCH_DEV}
+               ;;
+       esac
 }
 
 _zone_type()
@@ -2237,18 +2321,27 @@ _cat_group()
        cat /etc/group
 }
 
-# check for a user on the machine, fsgqa as default
+# check if a user exists in the system
+#
+_require_user_exists()
+{
+       local user=$1
+       _cat_passwd | grep -q "^$user:"
+       [ "$?" == "0" ] || _notrun "$user user not defined."
+}
+
+# check if a user exists and is able to execute commands.
+# Uses 'fsgqa' user as default.
 #
 _require_user()
 {
-    qa_user=fsgqa
-    if [ -n "$1" ];then
-        qa_user=$1
-    fi
-    _cat_passwd | grep -q $qa_user
-    [ "$?" == "0" ] || _notrun "$qa_user user not defined."
-    echo /bin/true | su $qa_user
-    [ "$?" == "0" ] || _notrun "$qa_user cannot execute commands."
+       qa_user=fsgqa
+       if [ -n "$1" ];then
+               qa_user=$1
+       fi
+       _require_user_exists $qa_user
+       echo /bin/true | su $qa_user
+       [ "$?" == "0" ] || _notrun "$qa_user cannot execute commands."
 }
 
 # check for a chown support
@@ -2511,9 +2604,11 @@ _require_odirect()
        rm -f $testfile 2>&1 > /dev/null
 }
 
+# Format a swapfile and return its size in bytes
 _format_swapfile() {
        local fname="$1"
        local sz="$2"
+       local swap_log=""
 
        rm -f "$fname"
        touch "$fname"
@@ -2522,14 +2617,17 @@ _format_swapfile() {
        $CHATTR_PROG +C "$fname" > /dev/null 2>&1
        _pwrite_byte 0x61 0 "$sz" "$fname" >> $seqres.full
        # Ignore permission complaints on filesystems that don't support perms
-       $MKSWAP_PROG "$fname" 2> >(grep -v 'insecure permission' >&2) >> $seqres.full
+       swap_log=$($MKSWAP_PROG "$fname" 2>&1 | grep -v "insecure permission")
+       echo $swap_log >> $seqres.full
+
+       echo $swap_log | grep -oP '\w+(?= bytes)'
 }
 
 _swapon_file() {
        local fname="$1"
 
        # Ignore permission complaints on filesystems that don't support perms
-       swapon "$fname" 2> >(grep -v "insecure permissions" >&2)
+       $(swapon "$fname" 2> >(grep -v "insecure permissions" >&2))
 }
 
 # Check that the filesystem supports swapfiles
@@ -2554,7 +2652,7 @@ _require_scratch_swapfile()
        _scratch_mount
 
        # Minimum size for mkswap is 10 pages
-       _format_swapfile "$SCRATCH_MNT/swap" $(($(get_page_size) * 10))
+       _format_swapfile "$SCRATCH_MNT/swap" $(($(get_page_size) * 10)) > /dev/null
 
        # ext* has supported all variants of swap files since their
        # introduction, so swapon should not fail.
@@ -2655,10 +2753,10 @@ _fstyp_has_non_default_seek_data_hole()
                return 0
                ;;
        nfs*)
-               # NFSv2 and NFSv3 only support default behavior of SEEK_HOLE,
-               # while NFSv4 supports non-default behavior
-               local nfsvers=`_df_device $TEST_DEV | $AWK_PROG '{ print $2 }'`
-               [ "$nfsvers" = "nfs4" ]
+               # NFSv2, NFSv3, and NFSv4.0/4.1 only support default behavior of SEEK_HOLE,
+               # while NFSv4.2 supports non-default behavior
+               local nfsvers=`_mount() | grep $TEST_DEV | sed -n 's/^.*vers=\([0-9.]*\).*$/\1/p'`
+               [ "$nfsvers" = "4.2" ]
                return $?
                ;;
        overlay)
@@ -3784,6 +3882,14 @@ _create_loop_device()
 {
        local file=$1 dev
        dev=`losetup -f --show $file` || _fail "Cannot assign $file to a loop device"
+
+       # Try to enable asynchronous directio mode on the loopback device so
+       # that writeback started by a filesystem mounted on the loop device
+       # won't be throttled by buffered writes to the lower filesystem.  This
+       # is a performance optimization for tests that want to write a lot of
+       # data, so it isn't required to work.
+       test -b "$dev" && losetup --direct-io=on $dev 2> /dev/null
+
        echo $dev
 }
 
@@ -4599,6 +4705,48 @@ _require_od_endian_flag()
                _notrun "od does not support endian flag"
 }
 
+# Skip this test unless the filesystem treats names (directory entries,
+# fs labels, and extended attribute names) as raw byte sequences.
+_require_names_are_bytes() {
+        case "$FSTYP" in
+        ext2|ext3|ext4|f2fs|xfs|btrfs)
+               # do nothing
+               ;;
+       *)
+                _notrun "$FSTYP does not allow unrestricted byte streams for names"
+               ;;
+        esac
+}
+
+_has_kernel_config()
+{
+       local option=$1
+       local uname=$(uname -r)
+       local config_list="$KCONFIG_PATH
+                    /proc/config.gz
+                    /lib/modules/$uname/build/.config
+                    /boot/config-$uname
+                    /lib/kernel/config-$uname"
+
+       for config in $config_list; do
+               [ ! -f $config ] && continue
+               [ $config = "/proc/config.gz" ] && break
+               grep -qE "^${option}=[my]" $config
+               return
+       done
+
+       [ ! -f $config ] && _notrun "Could not locate kernel config file"
+
+       # We can only get here with /proc/config.gz
+       _require_command "$GZIP_PROG" gzip
+       $GZIP_PROG -cd $config | grep -qE "^${option}=[my]"
+}
+
+_require_kernel_config()
+{
+       _has_kernel_config $1 || _notrun "Installed kernel not built with $1"
+}
+
 init_rc
 
 ################################################################################