xfstests: support post-udev device mapper nodes
[xfstests-dev.git] / common.rc
index f649bc249c6438f2fd9c35744f0216fa01ab9e14..e634fbb359392808ffb25888504742b3a1f46655 100644 (file)
--- a/common.rc
+++ b/common.rc
@@ -1,4 +1,4 @@
-##/bin/sh
+##/bin/bash
 #-----------------------------------------------------------------------
 #  Copyright (c) 2000-2006 Silicon Graphics, Inc.  All Rights Reserved.
 #  This program is free software; you can redistribute it and/or modify
@@ -37,10 +37,26 @@ dd()
    fi
 }
 
+# ls -l w/ selinux sometimes puts a dot at the end:
+# -rwxrw-r--. id1 id2 file1
+
+_ls_l()
+{
+       ls -l $* | sed "s/\(^[-rwxdlbcpsStT]*\)\. /\1 /"
+}
+
 _mount_opts()
 {
+    # SELinux adds extra xattrs which can mess up our expected output.
+    # So, mount with a context, and they won't be created
+    # nfs_t is a "liberal" context so we can use it.
+    if [ -x /usr/sbin/selinuxenabled ] && /usr/sbin/selinuxenabled; then
+       SELINUX_MOUNT_OPTIONS="-o context=system_u:object_r:nfs_t:s0"
+    fi
+
     case $FSTYP in
     xfs)
+       export SELINUX_MOUNT_OPTIONS
        export MOUNT_OPTIONS=$XFS_MOUNT_OPTIONS
        ;;
     udf)
@@ -49,6 +65,18 @@ _mount_opts()
     nfs)
        export MOUNT_OPTIONS=$NFS_MOUNT_OPTIONS
        ;;
+    ext2|ext3|ext4)
+       # acls & xattrs aren't turned on by default on ext$FOO
+       export MOUNT_OPTIONS="-o acl,user_xattr $EXT_MOUNT_OPTIONS"
+       ;;
+    reiserfs)
+       # acls & xattrs aren't turned on by default on reiserfs
+       export MOUNT_OPTIONS="-o acl,user_xattr $REISERFS_MOUNT_OPTIONS"
+       ;;
+    gfs2)
+       # acls aren't turned on by default on gfs2
+       export MOUNT_OPTIONS="-o acl $GFS2_MOUNT_OPTIONS"
+       ;;
     *)
        ;;
     esac
@@ -68,14 +96,36 @@ _mkfs_opts()
     nfs)
        export MKFS_OPTIONS=$NFS_MKFS_OPTIONS
        ;;
+    reiserfs)
+       export MKFS_OPTIONS="$REISERFS_MKFS_OPTIONS -q"
+       ;;
+    gfs2)
+       export MKFS_OPTIONS="$GFS2_MKFS_OPTIONS -O -p lock_nolock"
+       ;;
     *)
        ;;
     esac
 }
 
+_fsck_opts()
+{
+    case $FSTYP in
+    ext2|ext3|ext4)
+       export FSCK_OPTIONS="-nf"
+       ;;
+    reiserfs)
+       export FSCK_OPTIONS="--yes"
+       ;;
+    *)
+       export FSCK_OPTIONS="-n"
+       ;;
+    esac
+}
+
 [ -z "$FSTYP" ] && FSTYP=xfs
 [ -z "$MOUNT_OPTIONS" ] && _mount_opts
 [ -z "$MKFS_OPTIONS" ] && _mkfs_opts
+[ -z "$FSCK_OPTIONS" ] && _fsck_opts
 
 
 # we need common.config
@@ -172,7 +222,7 @@ _scratch_mount_options()
 {
     _scratch_options mount
 
-    echo $SCRATCH_OPTIONS $MOUNT_OPTIONS $* $SCRATCH_DEV $SCRATCH_MNT
+    echo $SCRATCH_OPTIONS $MOUNT_OPTIONS $SELINUX_MOUNT_OPTIONS $* $SCRATCH_DEV $SCRATCH_MNT
 }
 
 _scratch_mount()
@@ -180,10 +230,21 @@ _scratch_mount()
     _mount -t $FSTYP `_scratch_mount_options $*`
 }
 
+_scratch_unmount()
+{
+    $UMOUNT_PROG $SCRATCH_DEV
+}
+
+_scratch_remount()
+{
+    _scratch_unmount
+    _scratch_mount
+}
+
 _test_mount()
 {
     _test_options mount
-    _mount -t $FSTYP $TEST_OPTIONS $TEST_FS_MOUNT_OPTS $* $TEST_DEV $TEST_DIR
+    _mount -t $FSTYP $TEST_OPTIONS $TEST_FS_MOUNT_OPTS $SELINUX_MOUNT_OPTIONS $* $TEST_DEV $TEST_DIR
 }
 
 _scratch_mkfs_options()
@@ -247,11 +308,73 @@ _scratch_mkfs()
         $MKFS_UDF_PROG $MKFS_OPTIONS $* $SCRATCH_DEV > /dev/null
        ;;
     *)
-       /sbin/mkfs -t $FSTYP -- $MKFS_OPTIONS $* $SCRATCH_DEV > /dev/null
+       /sbin/mkfs -t $FSTYP -- $MKFS_OPTIONS $* $SCRATCH_DEV
+       ;;
+    esac
+}
+
+# Create fs of certain size on scratch device
+# _scratch_mkfs_sized <size in bytes> [optional blocksize]
+_scratch_mkfs_sized()
+{
+    fssize=$1
+    blocksize=$2
+    [ -z "$blocksize" ] && blocksize=4096
+    blocks=`expr $fssize / $blocksize`
+
+    case $FSTYP in
+    xfs)
+       _scratch_mkfs_xfs -d size=$fssize -b size=$blocksize
+       ;;
+    ext2|ext3|ext4)
+       /sbin/mkfs.$FSTYP $MKFS_OPTIONS -b $blocksize $SCRATCH_DEV $blocks
+       ;;
+     btrfs)
+       /sbin/mkfs.$FSTYP $MKFS_OPTIONS $SCRATCH_DEV -b $fssize
+       ;;
+    *)
+       _notrun "Filesystem $FSTYP not supported in _scratch_mkfs_sized"
        ;;
     esac
 }
 
+# Emulate an N-data-disk stripe w/ various stripe units
+# _scratch_mkfs_geom <sunit bytes> <swidth multiplier> [optional blocksize]
+_scratch_mkfs_geom()
+{
+    sunit_bytes=$1
+    swidth_mult=$2
+    blocksize=$3
+    [ -z "$blocksize" ] && blocksize=4096
+
+    let sunit_blocks=$sunit_bytes/$blocksize
+    let swidth_blocks=$sunit_blocks*$swidth_mult
+
+    case $FSTYP in
+    xfs)
+       MKFS_OPTIONS+=" -b size=$blocksize, -d su=$sunit_bytes,sw=$swidth_mult"
+       ;;
+    ext4)
+       MKFS_OPTIONS+=" -b $blocksize -E stride=$sunit_blocks,stripe_width=$swidth_blocks"
+       ;;
+    *)
+       _notrun "can't mkfs $FSTYP with geometry"
+       ;;
+    esac
+    _scratch_mkfs
+}
+
+_scratch_resvblks()
+{
+       case $FSTYP in
+       xfs)
+               xfs_io -x -c "resblks $1" $SCRATCH_MNT
+               ;;
+       *)
+               ;;
+       esac
+}
+
 _scratch_xfs_db_options()
 {
     SCRATCH_OPTIONS=""
@@ -312,14 +435,6 @@ _get_pids_by_name()
        -e "/[0-9]:[0-9][0-9]  *$1 /s/ .*//p"
 }
 
-# fqdn for localhost
-#
-_get_fqdn()
-{
-    host=`hostname`
-    $NSLOOKUP_PROG $host | $AWK_PROG '{ if ($1 == "Name:") print $2 }'
-}
-
 # fix malloc libs output
 #
 _fix_malloc()
@@ -472,7 +587,14 @@ _is_block_dev()
        exit 1
     fi
 
-    [ -b $1 ] && src/lstat64 $1 | $AWK_PROG '/Device type:/ { print $9 }'
+    _dev=$1
+    if [ -L "${_dev}" ]; then
+        _dev=`readlink -f ${_dev}`
+    fi
+
+    if [ -b "${_dev}" ]; then
+        src/lstat64 ${_dev} | $AWK_PROG '/Device type:/ { print $9 }'
+    fi
 }
 
 # Do a command, log it to $seq.full, optionally test return status
@@ -575,25 +697,26 @@ _supported_os()
 _require_scratch()
 {
     case "$FSTYP" in
-       xfs|udf)
-                if [ -z "$SCRATCH_DEV" -o "`_is_block_dev $SCRATCH_DEV`" = "" ]
+       nfs*)
+                echo $SCRATCH_DEV | grep -q ":" > /dev/null 2>&1
+                if [ -z "$SCRATCH_DEV" -o "$?" != "0" ]
                 then
                     _notrun "this test requires a valid \$SCRATCH_DEV"
                 fi
-                if [ "`_is_block_dev $SCRATCH_DEV`" = "`_is_block_dev $TEST_DEV`" ]
+                ;;
+       *)
+                if [ -z "$SCRATCH_DEV" -o "`_is_block_dev $SCRATCH_DEV`" = "" ]
                 then
                     _notrun "this test requires a valid \$SCRATCH_DEV"
                 fi
-                ;;
-       nfs*|ext2|ext3|reiserfs)
-                echo $SCRATCH_DEV | grep -q ":" > /dev/null 2>&1
-                if [ ! -z "$SCRATCH_DEV" -a ! -b "$SCRATCH_DEV" -a "$?" != "0" ]
+                if [ "`_is_block_dev $SCRATCH_DEV`" = "`_is_block_dev $TEST_DEV`" ]
                 then
                     _notrun "this test requires a valid \$SCRATCH_DEV"
                 fi
-                ;;
-       *)
-                _notrun "\$FSTYP ($FSTYP) unknown or not specified"
+               if [ ! -d "$SCRATCH_MNT" ]
+               then
+                    _notrun "this test requires a valid \$SCRATCH_MNT"
+               fi
                 ;;
     esac
 
@@ -666,10 +789,12 @@ _require_realtime()
 }
 
 # this test requires that a specified command (executable) exists
+# $1 - command, $2 - name for error message
 #
 _require_command()
 {
-    [ -x "$1" ] || _notrun "$1 utility required, skipped this test"
+    [ -n "$1" ] && _cmd="$1" || _cmd="$2"
+    [ -n "$1" -a -x "$1" ] || _notrun "$_cmd utility required, skipped this test"
 }
 
 # this test requires that external log/realtime devices are not in use
@@ -680,38 +805,134 @@ _require_nonexternal()
        _notrun "External device testing in progress, skipped this test"
 }
 
+# indicate whether YP/NIS is active or not
+#
+_yp_active()
+{
+       local dn
+       dn=$(domainname 2>/dev/null)
+       test -n "${dn}" -a "${dn}" != "(none)"
+       echo $?
+}
+
+# cat the password file
+#
+_cat_passwd()
+{
+       [ $(_yp_active) -eq 0 ] && ypcat passwd
+       cat /etc/passwd
+}
+
+# cat the group file
+#
+_cat_group()
+{
+       [ $(_yp_active) -eq 0 ] && ypcat group
+       cat /etc/group
+}
+
 # check for the fsgqa user on the machine
 #
 _require_user()
 {
     qa_user=fsgqa
-    cat /etc/passwd | grep -q $qa_user
+    _cat_passwd | grep -q $qa_user
     [ "$?" == "0" ] || _notrun "$qa_user user not defined."
 }
 
-# check that a FS is mounted as XFS. if so, return mount point
+# check that xfs_io, glibc, kernel, and filesystem all (!) support
+# fallocate
 #
-_xfs_mounted()
+_require_xfs_io_falloc()
+{
+       testfile=$TEST_DIR/$$.falloc
+       testio=`$XFS_IO_PROG -F -f -c "falloc 0 1m" $testfile 2>&1`
+       rm -f $testfile 2>&1 > /dev/null
+       echo $testio | grep -q "not found" && \
+               _notrun "xfs_io fallocate support is missing"
+       echo $testio | grep -q "Operation not supported" && \
+               _notrun "xfs_io fallocate command failed (old kernel/wrong fs?)"
+}
+
+# check that xfs_io, kernel and filesystem all support fallocate with hole
+# punching
+_require_xfs_io_falloc_punch()
+{
+       testfile=$TEST_DIR/$$.falloc
+       testio=`$XFS_IO_PROG -F -f -c "pwrite 0 20k" -c "fsync" \
+               -c "fpunch 4k 8k" $testfile 2>&1`
+       rm -f $testfile 2>&1 > /dev/null
+       echo $testio | grep -q "not found" && \
+               _notrun "xfs_io fallocate punch support is missing"
+       echo $testio | grep -q "Operation not supported" && \
+               _notrun "xfs_io fallocate punch command failed (no fs support?)"
+}
+
+# check that xfs_io, kernel and filesystem support fiemap
+_require_xfs_io_fiemap()
+{
+       testfile=$TEST_DIR/$$.fiemap
+       testio=`$XFS_IO_PROG -F -f -c "pwrite 0 20k" -c "fsync" \
+               -c "fiemap -v" $testfile 2>&1`
+       rm -f $testfile 2>&1 > /dev/null
+       echo $testio | grep -q "not found" && \
+               _notrun "xfs_io fiemap support is missing"
+       echo $testio | grep -q "Operation not supported" && \
+               _notrun "xfs_io fiemap command failed (no fs support?)"
+}
+
+# Check that a fs has enough free space (in 1024b blocks)
+#
+_require_fs_space()
+{
+       MNT=$1
+       BLOCKS=$2       # in units of 1024
+       let GB=$BLOCKS/1024/1024
+
+       FREE_BLOCKS=`df -klP $MNT | grep -v Filesystem | awk '{print $4}'`
+       [ $FREE_BLOCKS -lt $BLOCKS ] && \
+               _notrun "This test requires at least ${GB}GB free on $MNT to run"
+}
+
+#
+# Check if the filesystem supports sparse files.
+#
+# Unfortunately there is no better way to do this than a manual black list.
+#
+_require_sparse_files()
+{
+    case $FSTYP in
+    hfsplus)
+        _notrun "Sparse files not supported by this filesystem type: $FSTYP"
+       ;;
+    *)
+        ;;
+    esac
+}
+
+# check that a FS on a device is mounted
+# if so, return mount point
+#
+_is_mounted()
 {
     if [ $# -ne 1 ]
     then
-       echo "Usage: _xfs_mounted device" 1>&2
+       echo "Usage: _is_mounted device" 1>&2
        exit 1
     fi
 
     device=$1
 
-    if _mount | grep "$device " | $AWK_PROG '
-        /type xfs/  { print $3 ; exit 0 }
-        END         { exit 1 }
+    if _mount | grep "$device " | $AWK_PROG -v pattern="type $FSTYP" '
+        pattern        { print $3 ; exit 0 }
+        END            { exit 1 }
     '
     then
-        echo "_xfs_mounted: $device is not a mounted XFS FS"
+        echo "_is_mounted: $device is not a mounted $FSTYP FS"
         exit 1
     fi
 }
 
-
 # remount a FS to a new mode (ro or rw)
 #
 _remount()
@@ -731,14 +952,116 @@ _remount()
     fi
 }
 
-# run xfs_check and friends on a FS.
+# Run the appropriate repair/check on a filesystem
 #
 # if the filesystem is mounted, it's either remounted ro before being
 # checked or it's unmounted and then remounted
 #
 
+# If set, we remount ro instead of unmounting for fsck
 USE_REMOUNT=0
 
+_umount_or_remount_ro()
+{
+    if [ $# -ne 1 ]
+    then
+       echo "Usage: _umount_or_remount_ro <device>" 1>&2
+       exit 1
+    fi
+
+    device=$1
+    mountpoint=`_is_mounted $device`
+
+    if [ $USE_REMOUNT -eq 0 ]; then
+        $UMOUNT_PROG $device
+    else
+        _remount $device ro
+    fi
+    echo "$mountpoint"
+}
+
+_mount_or_remount_rw()
+{
+    if [ $# -ne 3 ]
+    then
+       echo "Usage: _mount_or_remount_rw <opts> <device> <mountpoint>" 1>&2
+       exit 1
+    fi
+    mount_opts=$1
+    device=$2
+    mountpoint=$3
+
+    if [ $USE_REMOUNT -eq 0 ]
+    then
+        if ! _mount -t $FSTYP $mount_opts $device $mountpoint
+        then
+            echo "!!! failed to remount $device on $mountpoint"
+            return 0 # ok=0
+        fi
+    else
+        _remount $device rw
+    fi
+
+    return 1 # ok=1
+}
+
+# Check a generic filesystem in no-op mode; this assumes that the
+# underlying fsck program accepts "-n" for a no-op (check-only) run,
+# and that it will still return an errno for corruption in this mode.
+#
+# Filesystems which don't support this will need to define their
+# own check routine.
+#
+_check_generic_filesystem()
+{
+    device=$1
+
+    # If type is set, we're mounted
+    type=`_fs_type $device`
+    ok=1
+
+    if [ "$type" = "$FSTYP" ]
+    then
+        # mounted ...
+        mountpoint=`_umount_or_remount_ro $device`
+    fi
+
+    fsck -t $FSTYP $FSCK_OPTIONS $device >$tmp.fsck 2>&1
+    if [ $? -ne 0 ]
+    then
+        echo "_check_generic_filesystem: filesystem on $device is inconsistent (see $seq.full)"
+
+        echo "_check_generic filesystem: filesystem on $device is inconsistent" >>$here/$seq.full
+        echo "*** fsck.$FSTYP output ***"                     >>$here/$seq.full
+        cat $tmp.fsck                                         >>$here/$seq.full
+        echo "*** end fsck.$FSTYP output"                     >>$here/$seq.full
+
+        ok=0
+    fi
+    rm -f $tmp.fsck
+
+    if [ $ok -eq 0 ]
+    then
+        echo "*** mount output ***"                             >>$here/$seq.full
+        _mount                                                  >>$here/$seq.full
+        echo "*** end mount output"                             >>$here/$seq.full
+    elif [ "$type" = "$FSTYP" ]
+    then
+       # was mounted ...
+       _mount_or_remount_rw "$MOUNT_OPTIONS" $device $mountpoint
+       ok=$?
+    fi
+
+    if [ $ok -eq 0 ]; then
+       status=1
+       exit 1
+    fi
+
+    return 0
+}
+
+# run xfs_check and friends on a FS.
+
 _check_xfs_filesystem()
 {
     if [ $# -ne 3 ]
@@ -769,15 +1092,8 @@ _check_xfs_filesystem()
 
     if [ "$type" = "xfs" ]
     then
-        # mounted...
-
-        if [ $USE_REMOUNT -eq 0 ]
-        then
-            mountpoint=`_xfs_mounted $device`
-            $UMOUNT_PROG $device
-        else
-            _remount $device ro
-        fi
+        # mounted ...
+        mountpoint=`_umount_or_remount_ro $device`
     fi
 
     $XFS_LOGPRINT_PROG -t $extra_log_options $device 2>&1 \
@@ -830,20 +1146,14 @@ _check_xfs_filesystem()
         echo "*** end mount output"                             >>$here/$seq.full
     elif [ "$type" = "xfs" ]
     then
-        # mounted...
-        if [ $USE_REMOUNT -eq 0 ]
-        then
-            if ! _mount -t xfs $extra_mount_options $device $mountpoint
-            then
-                echo "!!! failed to remount $device on $mountpoint"
-                ok=0
-            fi
-        else
-            _remount $device rw
-        fi
+       _mount_or_remount_rw "$extra_mount_options" $device $mountpoint
+    fi
+
+    if [ $ok -eq 0 ]; then
+       status=1
+       exit 1
     fi
 
-    [ $ok -eq 0 ] && exit 1
     return 0
 }
 
@@ -890,12 +1200,8 @@ _check_udf_filesystem()
 
 }
 
-_check_test_fs()
+_check_xfs_test_fs()
 {
-    if [ "$FSTYP" != "xfs" ]; then
-        return
-    fi
-
     TEST_LOG="none"
     TEST_RT="none"
     [ "$USE_EXTERNAL" = yes -a ! -z "$TEST_LOGDEV" ] && \
@@ -914,6 +1220,24 @@ _check_test_fs()
     fi
 }
 
+_check_test_fs()
+{
+    case $FSTYP in
+    xfs)
+       _check_xfs_test_fs
+       ;;
+    nfs)
+       # no way to check consistency for nfs
+       ;;
+    udf)
+       # do nothing for now
+       ;;
+    *)
+       _check_generic_filesystem $TEST_DEV
+       ;;
+    esac
+}
+
 _check_scratch_fs()
 {
     case $FSTYP in
@@ -935,6 +1259,7 @@ _check_scratch_fs()
        # Don't know how to check an NFS filesystem, yet.
        ;;
     *)
+       _check_generic_filesystem $SCRATCH_DEV
        ;;
     esac
 }
@@ -969,34 +1294,6 @@ _full_platform_details()
      echo "$os/$platform $host $kernel"
 }
 
-_check_testdir()
-{
-    case $FSTYP in
-    xfs)
-       _check_test_fs
-       ;;
-    udf)
-       _cleanup_testdir
-       _check_scratch_fs
-       _scratch_mount
-       ;;
-    nfs*)
-       # Don't know how to check an NFS filesystem, yet.
-       ;;
-    *)
-       ;;
-    esac
-}
-
-
-_setup_xfs_testdir()
-{
-    [ "$FSTYP" != "xfs" ] \
-       && _fail "setup_xfs_testdir: \$FSTYP ($FSTYP) is not xfs"
-
-    testdir=$TEST_DIR
-}
-
 _setup_udf_scratchdir()
 {
     [ "$FSTYP" != "udf" ] \
@@ -1050,16 +1347,17 @@ _setup_nfs_scratchdir()
 }
 
 #
-# Warning for UDF and NFS this function calls _setup_udf_scratchdir and
-# _setup_udf_scratchdir. This is done because testdir is a persistent
-# XFS only partition.
+# Warning for UDF and NFS:
+# this function calls _setup_udf_scratchdir and _setup_udf_scratchdir
+# which actually uses the scratch dir for the test dir.
+#
+# This was done because testdir was intended to be a persistent
+# XFS only partition.  This should eventually change, and treat
+# at least local filesystems all the same.
 #
 _setup_testdir()
 {
     case $FSTYP in
-    xfs)
-       _setup_xfs_testdir
-       ;;
     udf)
        _setup_udf_scratchdir
        ;;
@@ -1067,7 +1365,7 @@ _setup_testdir()
        _setup_nfs_scratchdir
        ;;
     *)
-       _fail "\$FSTYP is not xfs, udf or nfs"
+       testdir=$TEST_DIR
        ;;
     esac
 }
@@ -1075,10 +1373,6 @@ _setup_testdir()
 _cleanup_testdir()
 {
     case $FSTYP in
-    xfs)
-       # do nothing, testdir is $TEST_DIR
-       :
-       ;;
     udf)
        # umount testdir as it is $SCRATCH_MNT which could be used by xfs next
        [ -n "$testdir" ] && $UMOUNT_PROG $testdir
@@ -1088,7 +1382,8 @@ _cleanup_testdir()
        [ -n "$testdir" ] && $UMOUNT_PROG $testdir
        ;;
     *)
-       _fail "\$FSTYP is not xfs, udf or nfs"
+       # do nothing, testdir is $TEST_DIR
+       :
        ;;
     esac
 }