_assert_report_list
fi
+_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 $*`
_mount $scratch_opts $*
if [ $? -eq 0 ]; then
+ # mount --move operation updates the mountpoint, so remove
+ # the old one and insert the new one
+ if [[ "$*" =~ --move|-M ]]; then
+ MOUNTED_POINT_STACK=`echo $MOUNTED_POINT_STACK | \
+ cut -d\ -f2-`
+ fi
MOUNTED_POINT_STACK="$mnt_point $MOUNTED_POINT_STACK"
else
return 1
_scratch_mkfs_ext4()
{
local mkfs_cmd="$MKFS_EXT4_PROG -F"
- local mkfs_filter="grep -v -e ^Warning: -e \"^mke2fs \""
+ local mkfs_filter="grep -v -e ^Warning: -e \"^mke2fs \" | grep -v \"^$\""
local tmp=`mktemp -u`
local mkfs_status
free -b | grep ^Mem | awk '{print $4}'
}
+_available_memory_bytes()
+{
+ nf=`free -b | grep ^Mem | awk '{print NF}'`
+ if [[ nf -lt 7 ]]; then
+ # Doesn't have available field. Fallback.
+ _free_memory_bytes
+ else
+ free -b | grep ^Mem | awk '{print $7}'
+ fi
+}
+
# Create fs of certain size on scratch device
# _scratch_mkfs_sized <size in bytes> [optional blocksize]
_scratch_mkfs_sized()
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"
_require_sane_bdev_flush $SCRATCH_DEV
_require_command "$DMSETUP_PROG" dmsetup
+ _normalize_mount_options | egrep -q "dax(=always| |$)"
+ if [ $? -eq 0 ]; then
+ case $target in
+ stripe|linear|log-writes)
+ ;;
+ *)
+ _notrun "Cannot run tests with DAX on $target devices."
+ ;;
+ esac
+ fi
+
modprobe dm-$target >/dev/null 2>&1
$DMSETUP_PROG targets 2>&1 | grep -q ^$target
return $status
}
-# this test requires y2038 sysfs switch and filesystem
-# timestamp ranges support.
-_require_y2038()
+_require_timestamp_range()
{
local device=${1:-$TEST_DEV}
- local sysfsdir=/proc/sys/fs/fs-timestamp-check-on
-
- if [ ! -e $sysfsdir ]; then
- _notrun "no kernel support for y2038 sysfs switch"
- fi
local tsmin tsmax
read tsmin tsmax <<<$(_filesystem_timestamp_range $device)
if [ $tsmin -eq -1 -a $tsmax -eq -1 ]; then
_notrun "filesystem $FSTYP timestamp bounds are unknown"
fi
+
+ # expect console warning from rw scratch mount if fs limit is near
+ if [ $tsmax -le $((1<<31)) ] && \
+ ! _check_dmesg_for "filesystem being mounted at .* supports timestamps until"
+ then
+ _notrun "Kernel does not support timestamp limits"
+ fi
}
_filesystem_timestamp_range()
{
local device=${1:-$TEST_DEV}
- case $FSTYP in
- ext4)
+ local fstyp=${2:-$FSTYP}
+ u32max=$(((1<<32)-1))
+ s32min=-$((1<<31))
+ s32max=$(((1<<31)-1))
+ s64max=$(((1<<63)-1))
+ s64min=$((1<<63))
+
+ case $fstyp in
+ ext2)
+ echo "$s32min $s32max"
+ ;;
+ ext3|ext4)
if [ $(dumpe2fs -h $device 2>/dev/null | grep "Inode size:" | cut -d: -f2) -gt 128 ]; then
- echo "-2147483648 15032385535"
+ printf "%d %d\n" $s32min 0x37fffffff
else
- echo "-2147483648 2147483647"
+ echo "$s32min $s32max"
fi
;;
+ jfs)
+ echo "0 $u32max"
+ ;;
xfs)
- echo "-2147483648 2147483647"
+ echo "$s32min $s32max"
;;
- jfs)
- echo "0 4294967295"
+ btrfs)
+ echo "$s64min $s64max"
;;
- f2fs)
- echo "-2147483648 2147483647"
+ overlay)
+ if [ ! -z $OVL_BASE_FSTYP -a $OVL_BASE_FSTYP != "overlay" ]; then
+ _filesystem_timestamp_range $OVL_BASE_TEST_DEV $OVL_BASE_FSTYP
+ else
+ echo "-1 -1"
+ fi
;;
*)
echo "-1 -1"
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`
_notrun "xfs_io $command support is missing"
;;
"utimes" )
- testio=`$XFS_IO_PROG -f -c "utimes" 0 0 0 0 $testfile 2>&1`
+ testio=`$XFS_IO_PROG -f -c "utimes 0 0 0 0" $testfile 2>&1`
;;
"syncfs")
touch $testfile
_notrun "xfs_io $command $param_checked not supported on $FSTYP"
echo $testio | grep -q "Function not implemented" && \
_notrun "xfs_io $command $param_checked support is missing (missing syscall?)"
+ echo $testio | grep -q "unknown flag" && \
+ _notrun "xfs_io $command $param_checked support is missing (unknown flag)"
[ -n "$param" ] || return
if [ -z "$param_checked" ]; then
- $XFS_IO_PROG -c "help $command" | grep -q "^ $param --" || \
+ $XFS_IO_PROG -c "help $command" | grep -E -q "^ $param ([a-zA-Z_]+ )?--" || \
_notrun "xfs_io $command doesn't support $param"
else
# xfs_io could result in "command %c not supported" if it was
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
_require_odirect()
{
- if [ $FSTYP = "ext4" ] ; then
+ if [ $FSTYP = "ext4" ] || [ $FSTYP = "f2fs" ] ; then
if echo "$MOUNT_OPTIONS" | grep -q "test_dummy_encryption"; then
- _notrun "ext4 encryption doesn't support O_DIRECT"
- elif echo "$MOUNT_OPTIONS" | grep -q "data=journal"; then
+ _notrun "$FSTYP encryption doesn't support O_DIRECT"
+ fi
+ fi
+ if [ $FSTYP = "ext4" ] ; then
+ if echo "$MOUNT_OPTIONS" | grep -q "data=journal"; then
_notrun "ext4 data journaling doesn't support O_DIRECT"
fi
fi
_require_scratch
_require_command "$MKSWAP_PROG" "mkswap"
- _scratch_mkfs >/dev/null
+ _scratch_mkfs >/dev/null 2>&1
# With mounting SELinux context(e.g. system_u:object_r:root_t:s0),
# standard mkswap tried to reset the type of default context to
_require_sparse_files()
{
case $FSTYP in
- hfsplus)
+ hfsplus|exfat)
_notrun "Sparse files not supported by this filesystem type: $FSTYP"
;;
*)
{
[ -f "$DEBUGFS_MNT/fail_make_request/probability" ] \
|| _notrun "$DEBUGFS_MNT/fail_make_request \
- not found. Seems that CONFIG_FAIL_MAKE_REQUEST kernel config option not enabled"
+ not found. Seems that CONFIG_FAULT_INJECTION_DEBUG_FS kernel config option not enabled"
}
# Disable extent zeroing for ext4 on the given device
_scratch_unmount
}
-# Does dax mount option work on this dev/fs?
-_require_scratch_dax()
+_check_s_dax()
+{
+ 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
+#
+# $1 can be either 'dax=always' or 'dax'
+#
+# dax=always
+# Check for the new dax options (dax=inode, dax=always or dax=never)
+# by passing "dax=always".
+# dax
+# Check for the old dax or new dax=always by passing "dax".
+#
+# This only accepts 'dax=always' because dax=always, dax=inode and
+# dax=never are always supported together. So if the other options are
+# required checking for 'dax=always' indicates support for the other 2.
+#
+# Return 0 if filesystem/device supports the specified dax option.
+# Return 1 if mount fails with the specified dax option.
+# Return 2 if /proc/mounts shows wrong dax option.
+_check_scratch_dax_mountopt()
{
+ local option=$1
+
_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
+
+ _try_scratch_mount "-o $option" > /dev/null 2>&1 || return 1
+
+ if _fs_options $SCRATCH_DEV | egrep -q "dax(=always|,|$)"; then
+ _scratch_unmount
+ return 0
+ else
+ _scratch_unmount
+ return 2
+ fi
+}
+
+# Throw notrun if _check_scratch_dax_mountopt() returns a non-zero value.
+_require_scratch_dax_mountopt()
+{
+ local mountopt=$1
+
+ _check_scratch_dax_mountopt "$mountopt"
+ local res=$?
+
+ [ $res -eq 1 ] && _notrun "mount $SCRATCH_DEV with $mountopt failed"
+ [ $res -eq 2 ] && _notrun "$SCRATCH_DEV $FSTYP does not support -o $mountopt"
+}
+
+_require_dax_iflag()
+{
+ _require_xfs_io_command "chattr" "x"
}
# Does norecovery support by this fs?
# It's possible that TEST_DEV and SCRATCH_DEV have different features (it'd be
# odd, but possible) so check $TEST_DEV by default, but we can optionall pass
# any dev we want.
-_require_metadata_journaling()
+_has_metadata_journaling()
{
if [ -z $1 ]; then
local dev=$TEST_DEV
fi
case "$FSTYP" in
- ext2|vfat|msdos|udf)
- _notrun "$FSTYP does not support metadata journaling"
+ ext2|vfat|msdos|udf|exfat)
+ echo "$FSTYP does not support metadata journaling"
+ return 1
;;
ext4)
# ext4 could be mkfs'd without a journal...
_require_dumpe2fs
- $DUMPE2FS_PROG -h $dev 2>&1 | grep -q has_journal || \
- _notrun "$FSTYP on $dev not configured with metadata journaling"
+ $DUMPE2FS_PROG -h $dev 2>&1 | grep -q has_journal || {
+ echo "$FSTYP on $dev not configured with metadata journaling"
+ return 1
+ }
# ext4 might not load a journal
- _exclude_scratch_mount_option "noload"
+ if _normalize_mount_options | grep -qw "noload"; then
+ echo "mount option \"noload\" not allowed in this test"
+ return 1
+ fi
;;
overlay)
# metadata journaling check is based on base filesystem configurations
# and because -overlay option saves those configurations to OVL_BASE_*,
# adding restore/override the configurations before/after the check.
if [ ! -z $OVL_BASE_FSTYP -a $OVL_BASE_FSTYP != "overlay" ]; then
+ local ret
+
_overlay_config_restore
- _require_metadata_journaling
+ _has_metadata_journaling
+ ret=$?
_overlay_config_override
+ return $ret
else
- _notrun "No metadata journaling support for legacy overlay setup"
+ echo "No metadata journaling support for legacy overlay setup"
+ return 1
fi
;;
*)
# by default we pass; if you need to, add your fs above!
;;
esac
+ return 0
+}
+
+_require_metadata_journaling()
+{
+ local msg=$(_has_metadata_journaling $@)
+ if [ -n "$msg" ]; then
+ _notrun "$msg"
+ fi
}
_count_extents()
{
- $XFS_IO_PROG -c "fiemap" $1 | tail -n +2 | grep -v hole | wc -l
+ $XFS_IO_PROG -r -c "fiemap" $1 | tail -n +2 | grep -v hole | wc -l
+}
+
+# Similar to _count_extents() but if any extent is shared multiples times in
+# the file (reflinked to different file offsets), it is accounted as 1 extent
+# instead of N extents.
+_count_exclusive_extents()
+{
+ $XFS_IO_PROG -r -c "fiemap" $1 | tail -n +2 | grep -v hole | \
+ cut -d ' ' -f 3 | sort | uniq | wc -l
}
_count_holes()
{
- $XFS_IO_PROG -c "fiemap" $1 | tail -n +2 | grep hole | wc -l
+ $XFS_IO_PROG -r -c "fiemap" $1 | tail -n +2 | grep hole | wc -l
}
_count_attr_extents()
}
# 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
esac
shift
done
- echo $args
+ printf '%s\n' "$args"
}
#
"$@" >> $seqres.full 2>&1 || _fail "failed: '$@'"
}
-_require_test_symlinks()
+_require_symlinks()
{
local target=`mktemp -p $TEST_DIR`
local link=`mktemp -p $TEST_DIR -u`
rm -f $target $link
}
+_require_hardlinks()
+{
+ local target=`mktemp -p $TEST_DIR`
+ local link=`mktemp -p $TEST_DIR -u`
+ ln $target $link
+ if [ "$?" -ne 0 ]; then
+ rm -f $target
+ _notrun "No hardlink support"
+ fi
+ rm -f $target $link
+}
+
_require_test_fcntl_advisory_locks()
{
[ "$FSTYP" != "cifs" ] && return 0
_notrun "Require fcntl advisory locks support"
}
+_require_test_fcntl_setlease()
+{
+ _require_test_program "locktest"
+ touch $TEST_DIR/setlease_testfile
+ $here/src/locktest -t $TEST_DIR/setlease_testfile >/dev/null 2>&1
+ [ $? -eq 22 ] && _notrun "Require fcntl setlease support"
+}
+
_require_ofd_locks()
{
# Give a test run by getlk wrlck on testfile.
# return device size in kb
_get_device_size()
{
- grep `_short_dev $1` /proc/partitions | awk '{print $3}'
+ grep -w `_short_dev $1` /proc/partitions | awk '{print $3}'
}
# Make sure we actually have dmesg checking set up.
_dump_err "_check_dmesg: something found in dmesg (see $seqres.dmesg)"
return 1
else
- rm -f $seqres.dmesg
+ if [ "$KEEP_DMESG" != "yes" ]; then
+ rm -f $seqres.dmesg
+ fi
return 0
fi
}
{
case "$(getconf LONG_BIT)" in
"32")
- echo $(( ($(getconf PAGE_SIZE) << ($(getconf LONG_BIT) - 1) ) - 1))
+ local ulong_max=$(getconf ULONG_MAX)
+ local page_size=$(getconf PAGE_SIZE)
+ echo $(( ulong_max * page_size ))
;;
"64")
echo 9223372036854775807
return 0
}
+# exfat timestamps start at 1980 and cannot be prior to epoch
+_require_negative_timestamps() {
+ case "$FSTYP" in
+ ceph|exfat)
+ _notrun "$FSTYP does not support negative timestamps"
+ ;;
+ esac
+}
+
+# Require the 'accton' userspace tool and CONFIG_BSD_PROCESS_ACCT=y.
+_require_bsd_process_accounting()
+{
+ _require_command "$ACCTON_PROG" accton
+ $ACCTON_PROG on &> $tmp.test_accton
+ cat $tmp.test_accton >> $seqres.full
+ if grep 'Function not implemented' $tmp.test_accton; then
+ _notrun "BSD process accounting support unavailable"
+ fi
+ $ACCTON_PROG off >> $seqres.full
+}
+
+_require_sysctl_variable()
+{
+ local name=$1
+ sysctl $name &>/dev/null || _notrun "$name sysctl unavailable"
+}
+
+_require_mknod()
+{
+ mknod $TEST_DIR/$seq.null c 1 3 \
+ || _notrun "$FSTYP does not support mknod/mkfifo"
+ rm -f $TEST_DIR/$seq.null
+}
+
init_rc
################################################################################