common/rc: Add extra check for xfs_io -c "chattr" on XFS
[xfstests-dev.git] / common / rc
index fa70453d63276b0e7a1dfa8598cd755ac1fb0dd0..807a1f6ca225c5b5fbbde1af7a62f4e1f55ff929 100644 (file)
--- a/common/rc
+++ b/common/rc
@@ -170,6 +170,16 @@ _get_filesize()
     stat -c %s "$1"
 }
 
+# Get hugepagesize in bytes
+_get_hugepagesize()
+{
+       local hugepgsz=$(awk '/Hugepagesize/ {print $2}' /proc/meminfo)
+       # Call _notrun if $hugepgsz is not a number
+       echo "$hugepgsz" | egrep -q ^[0-9]+$ || \
+               _notrun "Cannot get the value of Hugepagesize"
+       echo $((hugepgsz * 1024))
+}
+
 _mount()
 {
     $MOUNT_PROG `_mount_ops_filter $*`
@@ -1051,7 +1061,19 @@ _scratch_mkfs_geom()
 
     case $FSTYP in
     xfs)
-       MKFS_OPTIONS+=" -b size=$blocksize, -d su=$sunit_bytes,sw=$swidth_mult"
+       if echo "$MKFS_OPTIONS" | egrep -q "b?size="; then
+               MKFS_OPTIONS=$(echo "$MKFS_OPTIONS" | sed -r "s/(b?size=)[0-9]+/\1$blocksize/")
+       else
+               MKFS_OPTIONS+=" -b size=$blocksize"
+       fi
+
+       if echo "$MKFS_OPTIONS" | egrep -q "(su|sunit|sw|swidth)="; then
+               MKFS_OPTIONS=$(echo "$MKFS_OPTIONS" | sed -r \
+                       -e "s/(su|sunit)=[0-9kmg]+/su=$sunit_bytes/" \
+                       -e "s/(sw|swidth)=[0-9kmg]+/sw=$swidth_mult/")
+       else
+               MKFS_OPTIONS+=" -d su=$sunit_bytes,sw=$swidth_mult"
+       fi
        ;;
     ext4|ext4dev)
        MKFS_OPTIONS+=" -b $blocksize -E stride=$sunit_blocks,stripe_width=$swidth_blocks"
@@ -1874,7 +1896,7 @@ _require_dm_target()
        _require_sane_bdev_flush $SCRATCH_DEV
        _require_command "$DMSETUP_PROG" dmsetup
 
-       echo $MOUNT_OPTIONS | grep -q dax
+       _normalize_mount_options | egrep -q "dax(=always| |$)"
        if [ $? -eq 0 ]; then
                case $target in
                stripe|linear|log-writes)
@@ -2136,19 +2158,31 @@ _require_xfs_io_command()
        local param="$*"
        local param_checked=""
        local opts=""
+       local attr_info=""
 
        local testfile=$TEST_DIR/$$.xfs_io
        local testio
        case $command in
        "chattr")
+               local testdir=$TEST_DIR/$$.attr_dir
+               mkdir $TEST_DIR/$$.attr_dir
                if [ -z "$param" ]; then
                        param=s
                fi
                # Test xfs_io chattr support AND
                # filesystem FS_IOC_FSSETXATTR support
-               testio=`$XFS_IO_PROG -F -f -c "chattr +$param" $testfile 2>&1`
-               $XFS_IO_PROG -F -f -r -c "chattr -$param" $testfile 2>&1
+               # 'tPnE' flags are only valid for a directory so check them on a directory.
+               if echo "$param" | egrep -q 't|P|n|E'; then
+                       testio=`$XFS_IO_PROG -F -c "chattr +$param" $testdir 2>&1`
+                       attr_info=`$XFS_IO_PROG -F -r -c "lsattr" $testdir | awk '{print $1}'`
+                       $XFS_IO_PROG -F -r -c "chattr -$param" $testdir 2>&1
+               else
+                       testio=`$XFS_IO_PROG -F -f -c "chattr +$param" $testfile 2>&1`
+                       attr_info=`$XFS_IO_PROG -F -r -c "lsattr" $testfile | awk '{print $1}'`
+                       $XFS_IO_PROG -F -r -c "chattr -$param" $testfile 2>&1
+               fi
                param_checked="+$param"
+               rm -rf $testdir 2>&1 > /dev/null
                ;;
        "chproj")
                testio=`$XFS_IO_PROG -F -f -c "chproj 0" $testfile 2>&1`
@@ -2269,6 +2303,19 @@ _require_xfs_io_command()
                echo $testio | grep -q "\(invalid option\|not supported\)" && \
                        _notrun "xfs_io $command doesn't support $param"
        fi
+
+       # On XFS, ioctl(FSSETXATTR)(called by xfs_io -c "chattr") maskes off unsupported
+       # or invalid flags silently so need to check these flags by extra ioctl(FSGETXATTR)
+       # (called by xfs_io -c "lsattr").
+       # The following URL explains why we don't change the behavior of XFS.
+       # https://www.spinics.net/lists/linux-xfs/msg44725.html
+       if [ -n "$attr_info" -a "$FSTYP" = "xfs" ]; then
+               local num=${#param}
+               for i in $(seq 0 $((num-1))); do
+                       echo $attr_info | grep -q "${param:$i:1}" || \
+                               _notrun "xfs_io $command +${param:$i:1} support is missing (unknown flag in kernel)"
+               done
+       fi
 }
 
 # check that kernel and filesystem support direct I/O
@@ -3174,18 +3221,29 @@ _require_scratch_shutdown()
        _scratch_unmount
 }
 
-# Does dax mount option work on this dev/fs?
-_require_scratch_dax()
+_check_s_dax()
 {
-       _require_scratch
-       _scratch_mkfs > /dev/null 2>&1
-       _try_scratch_mount -o dax || \
-               _notrun "mount $SCRATCH_DEV with dax failed"
-       # Check options to be sure. XFS ignores dax option
-       # and goes on if dev underneath does not support dax.
-       _fs_options $SCRATCH_DEV | grep -qw "dax" || \
-               _notrun "$SCRATCH_DEV $FSTYP does not support -o dax"
-       _scratch_unmount
+       local target=$1
+       local exp_s_dax=$2
+
+       local attributes=$($XFS_IO_PROG -c 'statx -r' $target | awk '/stat.attributes / { print $3 }')
+       if [ $exp_s_dax -eq 0 ]; then
+               (( attributes & 0x2000 )) && echo "$target has unexpected S_DAX flag"
+       else
+               (( attributes & 0x2000 )) || echo "$target doen't have expected S_DAX flag"
+       fi
+}
+
+_check_xflag()
+{
+       local target=$1
+       local exp_xflag=$2
+
+       if [ $exp_xflag -eq 0 ]; then
+               _test_inode_flag dax $target && echo "$target has unexpected FS_XFLAG_DAX flag"
+       else
+               _test_inode_flag dax $target || echo "$target doen't have expected FS_XFLAG_DAX flag"
+       fi
 }
 
 # Check if dax mount options are supported
@@ -3450,12 +3508,16 @@ _normalize_mount_options()
 }
 
 # skip test if MOUNT_OPTIONS contains the given strings
+# Both dax and dax=always are excluded if dax or dax=always is passed
 _exclude_scratch_mount_option()
 {
        local mnt_opts=$(_normalize_mount_options)
 
        while [ $# -gt 0 ]; do
-               if echo $mnt_opts | grep -qw "$1"; then
+               local pattern=$1
+               echo "$pattern" | egrep -q "dax(=always|$)" && \
+                       pattern="dax(=always| |$)"
+               if echo $mnt_opts | egrep -q "$pattern"; then
                        _notrun "mount option \"$1\" not allowed in this test"
                fi
                shift