mirror of
https://github.com/linux-apfs/apfstests.git
synced 2026-05-01 15:01:44 -07:00
2fd273886b
Create a new helper function to discover the minimum log size that will work with the mkfs options provided, then remove all the hardcoded block sizes from various xfs tests. This will be necessary when we turn on reflink or rmap by default and the minimum log size increases. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> Tested-by: Yang Xu<xuyang2018.jy@cn.fujitsu.com> Signed-off-by: Eryu Guan <guaneryu@gmail.com>
853 lines
22 KiB
Plaintext
853 lines
22 KiB
Plaintext
#
|
|
# XFS specific common functions.
|
|
#
|
|
|
|
_setup_large_xfs_fs()
|
|
{
|
|
fs_size=$1
|
|
local tmp_dir=/tmp/
|
|
|
|
[ "$LARGE_SCRATCH_DEV" != yes ] && return 0
|
|
[ -z "$SCRATCH_DEV_EMPTY_SPACE" ] && SCRATCH_DEV_EMPTY_SPACE=0
|
|
[ $SCRATCH_DEV_EMPTY_SPACE -ge $fs_size ] && return 0
|
|
|
|
# calculate the size of the file we need to allocate.
|
|
# Default free space in the FS is 50GB, but you can specify more via
|
|
# SCRATCH_DEV_EMPTY_SPACE
|
|
file_size=$(($fs_size - 50*1024*1024*1024))
|
|
file_size=$(($file_size - $SCRATCH_DEV_EMPTY_SPACE))
|
|
|
|
# mount the filesystem, create the file, unmount it
|
|
_try_scratch_mount 2>&1 >$tmp_dir/mnt.err
|
|
local status=$?
|
|
if [ $status -ne 0 ]; then
|
|
echo "mount failed"
|
|
cat $tmp_dir/mnt.err >&2
|
|
rm -f $tmp_dir/mnt.err
|
|
return $status
|
|
fi
|
|
rm -f $tmp_dir/mnt.err
|
|
|
|
xfs_io -F -f \
|
|
-c "truncate $file_size" \
|
|
-c "falloc -k 0 $file_size" \
|
|
-c "chattr +d" \
|
|
$SCRATCH_MNT/.use_space 2>&1 > /dev/null
|
|
export NUM_SPACE_FILES=1
|
|
status=$?
|
|
_scratch_unmount
|
|
if [ $status -ne 0 ]; then
|
|
echo "large file prealloc failed"
|
|
cat $tmp_dir/mnt.err >&2
|
|
return $status
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
_scratch_mkfs_xfs_opts()
|
|
{
|
|
mkfs_opts=$*
|
|
|
|
# remove metadata related mkfs options if mkfs.xfs doesn't them
|
|
if [ -n "$XFS_MKFS_HAS_NO_META_SUPPORT" ]; then
|
|
mkfs_opts=`echo $mkfs_opts | sed "s/-m\s\+\S\+//g"`
|
|
fi
|
|
|
|
_scratch_options mkfs
|
|
|
|
echo "$MKFS_XFS_PROG $SCRATCH_OPTIONS $mkfs_opts"
|
|
}
|
|
|
|
|
|
_scratch_mkfs_xfs_supported()
|
|
{
|
|
local mkfs_opts=$*
|
|
|
|
_scratch_options mkfs
|
|
|
|
$MKFS_XFS_PROG -N $MKFS_OPTIONS $SCRATCH_OPTIONS $mkfs_opts $SCRATCH_DEV
|
|
local mkfs_status=$?
|
|
|
|
# a mkfs failure may be caused by conflicts between $MKFS_OPTIONS and
|
|
# $mkfs_opts, try again without $MKFS_OPTIONS
|
|
if [ $mkfs_status -ne 0 -a -n "$mkfs_opts" ]; then
|
|
$MKFS_XFS_PROG -N $SCRATCH_OPTIONS $mkfs_opts $SCRATCH_DEV
|
|
mkfs_status=$?
|
|
fi
|
|
return $mkfs_status
|
|
}
|
|
|
|
# Returns the minimum XFS log size, in units of log blocks.
|
|
_scratch_find_xfs_min_logblocks()
|
|
{
|
|
local mkfs_cmd="`_scratch_mkfs_xfs_opts`"
|
|
|
|
# The smallest log size we can specify is 2M (XFS_MIN_LOG_BYTES) so
|
|
# pass that in and see if mkfs succeeds or tells us what is the
|
|
# minimum log size.
|
|
local XFS_MIN_LOG_BYTES=2097152
|
|
|
|
_scratch_do_mkfs "$mkfs_cmd" "cat" $* -N -l size=$XFS_MIN_LOG_BYTES \
|
|
2>$tmp.mkfserr 1>$tmp.mkfsstd
|
|
local mkfs_status=$?
|
|
|
|
# mkfs suceeded, so we must pick out the log block size to do the
|
|
# unit conversion
|
|
if [ $mkfs_status -eq 0 ]; then
|
|
local blksz="$(grep '^log.*bsize' $tmp.mkfsstd | \
|
|
sed -e 's/log.*bsize=\([0-9]*\).*$/\1/g')"
|
|
echo $((XFS_MIN_LOG_BYTES / blksz))
|
|
return
|
|
fi
|
|
|
|
# Usually mkfs will tell us the minimum log size...
|
|
if grep -q 'minimum size is' $tmp.mkfserr; then
|
|
grep 'minimum size is' $tmp.mkfserr | \
|
|
sed -e 's/^.*minimum size is \([0-9]*\) blocks/\1/g'
|
|
return
|
|
fi
|
|
|
|
# Don't know what to do, so fail
|
|
echo "Cannot determine minimum log size" >&2
|
|
cat $tmp.mkfsstd >> $seqres.full
|
|
cat $tmp.mkfserr >> $seqres.full
|
|
}
|
|
|
|
_scratch_mkfs_xfs()
|
|
{
|
|
local mkfs_cmd="`_scratch_mkfs_xfs_opts`"
|
|
local mkfs_filter="sed -e '/less than device physical sector/d' \
|
|
-e '/switching to logical sector/d' \
|
|
-e '/Default configuration/d'"
|
|
local tmp=`mktemp -u`
|
|
local mkfs_status
|
|
|
|
_scratch_do_mkfs "$mkfs_cmd" "$mkfs_filter" $* 2>$tmp.mkfserr 1>$tmp.mkfsstd
|
|
mkfs_status=$?
|
|
|
|
grep -q crc=0 $tmp.mkfsstd && _force_xfsv4_mount_options
|
|
|
|
if [ $mkfs_status -eq 0 -a "$LARGE_SCRATCH_DEV" = yes ]; then
|
|
# manually parse the mkfs output to get the fs size in bytes
|
|
local fs_size
|
|
fs_size=`cat $tmp.mkfsstd | perl -ne '
|
|
if (/^data\s+=\s+bsize=(\d+)\s+blocks=(\d+)/) {
|
|
my $size = $1 * $2;
|
|
print STDOUT "$size\n";
|
|
}'`
|
|
_setup_large_xfs_fs $fs_size
|
|
mkfs_status=$?
|
|
fi
|
|
|
|
# output mkfs stdout and stderr
|
|
cat $tmp.mkfsstd
|
|
cat $tmp.mkfserr >&2
|
|
rm -f $tmp.mkfserr $tmp.mkfsstd
|
|
|
|
return $mkfs_status
|
|
}
|
|
|
|
# xfs_check script is planned to be deprecated. But, we want to
|
|
# be able to invoke "xfs_check" behavior in xfstests in order to
|
|
# maintain the current verification levels.
|
|
_xfs_check()
|
|
{
|
|
OPTS=" "
|
|
DBOPTS=" "
|
|
USAGE="Usage: xfs_check [-fsvV] [-l logdev] [-i ino]... [-b bno]... special"
|
|
|
|
OPTIND=1
|
|
while getopts "b:fi:l:stvV" c; do
|
|
case $c in
|
|
s) OPTS=$OPTS"-s ";;
|
|
t) OPTS=$OPTS"-t ";;
|
|
v) OPTS=$OPTS"-v ";;
|
|
i) OPTS=$OPTS"-i "$OPTARG" ";;
|
|
b) OPTS=$OPTS"-b "$OPTARG" ";;
|
|
f) DBOPTS=$DBOPTS" -f";;
|
|
l) DBOPTS=$DBOPTS" -l "$OPTARG" ";;
|
|
V) $XFS_DB_PROG -p xfs_check -V
|
|
return $?
|
|
;;
|
|
esac
|
|
done
|
|
set -- extra $@
|
|
shift $OPTIND
|
|
case $# in
|
|
1) ${XFS_DB_PROG}${DBOPTS} -F -i -p xfs_check -c "check$OPTS" $1
|
|
status=$?
|
|
;;
|
|
2) echo $USAGE 1>&1
|
|
status=2
|
|
;;
|
|
esac
|
|
return $status
|
|
}
|
|
|
|
_scratch_xfs_db_options()
|
|
{
|
|
SCRATCH_OPTIONS=""
|
|
[ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_LOGDEV" ] && \
|
|
SCRATCH_OPTIONS="-l$SCRATCH_LOGDEV"
|
|
echo $SCRATCH_OPTIONS $* $SCRATCH_DEV
|
|
}
|
|
|
|
_scratch_xfs_db()
|
|
{
|
|
$XFS_DB_PROG "$@" $(_scratch_xfs_db_options)
|
|
}
|
|
|
|
_scratch_xfs_logprint()
|
|
{
|
|
SCRATCH_OPTIONS=""
|
|
[ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_LOGDEV" ] && \
|
|
SCRATCH_OPTIONS="-l$SCRATCH_LOGDEV"
|
|
$XFS_LOGPRINT_PROG $SCRATCH_OPTIONS $* $SCRATCH_DEV
|
|
}
|
|
|
|
_test_xfs_logprint()
|
|
{
|
|
TEST_OPTIONS=""
|
|
[ "$USE_EXTERNAL" = yes -a ! -z "$TEST_LOGDEV" ] && \
|
|
TEST_OPTIONS="-l$TEST_LOGDEV"
|
|
$XFS_LOGPRINT_PROG $TEST_OPTIONS $* $TEST_DEV
|
|
}
|
|
|
|
_scratch_xfs_check()
|
|
{
|
|
SCRATCH_OPTIONS=""
|
|
[ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_LOGDEV" ] && \
|
|
SCRATCH_OPTIONS="-l $SCRATCH_LOGDEV"
|
|
[ "$LARGE_SCRATCH_DEV" = yes ] && \
|
|
SCRATCH_OPTIONS=$SCRATCH_OPTIONS" -t"
|
|
_xfs_check $SCRATCH_OPTIONS $* $SCRATCH_DEV
|
|
}
|
|
|
|
_scratch_xfs_repair()
|
|
{
|
|
SCRATCH_OPTIONS=""
|
|
[ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_LOGDEV" ] && \
|
|
SCRATCH_OPTIONS="-l$SCRATCH_LOGDEV"
|
|
[ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_RTDEV" ] && \
|
|
SCRATCH_OPTIONS=$SCRATCH_OPTIONS" -r$SCRATCH_RTDEV"
|
|
$XFS_REPAIR_PROG $SCRATCH_OPTIONS $* $SCRATCH_DEV
|
|
}
|
|
|
|
# this test requires the projid32bit feature to be available in mkfs.xfs.
|
|
#
|
|
_require_projid32bit()
|
|
{
|
|
_scratch_mkfs_xfs_supported -i projid32bit=1 >/dev/null 2>&1 \
|
|
|| _notrun "mkfs.xfs doesn't have projid32bit feature"
|
|
}
|
|
|
|
_require_projid16bit()
|
|
{
|
|
_scratch_mkfs_xfs_supported -i projid32bit=0 >/dev/null 2>&1 \
|
|
|| _notrun "16 bit project IDs not supported on $SCRATCH_DEV"
|
|
}
|
|
|
|
# this test requires the crc feature to be available in mkfs.xfs
|
|
#
|
|
_require_xfs_mkfs_crc()
|
|
{
|
|
_scratch_mkfs_xfs_supported -m crc=1 >/dev/null 2>&1 \
|
|
|| _notrun "mkfs.xfs doesn't have crc feature"
|
|
}
|
|
|
|
# this test requires the xfs kernel support crc feature
|
|
#
|
|
_require_xfs_crc()
|
|
{
|
|
_scratch_mkfs_xfs -m crc=1 >/dev/null 2>&1
|
|
_try_scratch_mount >/dev/null 2>&1 \
|
|
|| _notrun "Kernel doesn't support crc feature"
|
|
_scratch_unmount
|
|
}
|
|
|
|
# this test requires the xfs kernel support crc feature on scratch device
|
|
#
|
|
_require_scratch_xfs_crc()
|
|
{
|
|
_scratch_mkfs_xfs >/dev/null 2>&1
|
|
_try_scratch_mount >/dev/null 2>&1 \
|
|
|| _notrun "Kernel doesn't support crc feature"
|
|
$XFS_INFO_PROG $SCRATCH_MNT | grep -q 'crc=1' || _notrun "crc feature not supported by this filesystem"
|
|
_scratch_unmount
|
|
}
|
|
|
|
# this test requires the finobt feature to be available in mkfs.xfs
|
|
#
|
|
_require_xfs_mkfs_finobt()
|
|
{
|
|
_scratch_mkfs_xfs_supported -m crc=1,finobt=1 >/dev/null 2>&1 \
|
|
|| _notrun "mkfs.xfs doesn't have finobt feature"
|
|
}
|
|
|
|
# this test requires the xfs kernel support finobt feature
|
|
#
|
|
_require_xfs_finobt()
|
|
{
|
|
_scratch_mkfs_xfs -m crc=1,finobt=1 >/dev/null 2>&1
|
|
_try_scratch_mount >/dev/null 2>&1 \
|
|
|| _notrun "Kernel doesn't support finobt feature"
|
|
_scratch_unmount
|
|
}
|
|
|
|
# this test requires xfs sysfs attribute support
|
|
#
|
|
_require_xfs_sysfs()
|
|
{
|
|
attr=$1
|
|
sysfsdir=/sys/fs/xfs
|
|
|
|
if [ ! -e $sysfsdir ]; then
|
|
_notrun "no kernel support for XFS sysfs attributes"
|
|
fi
|
|
|
|
if [ ! -z $1 ] && [ ! -e $sysfsdir/$attr ]; then
|
|
_notrun "sysfs attribute '$attr' is not supported"
|
|
fi
|
|
}
|
|
|
|
# this test requires the xfs sparse inode feature
|
|
#
|
|
_require_xfs_sparse_inodes()
|
|
{
|
|
_scratch_mkfs_xfs_supported -m crc=1 -i sparse > /dev/null 2>&1 \
|
|
|| _notrun "mkfs.xfs does not support sparse inodes"
|
|
_scratch_mkfs_xfs -m crc=1 -i sparse > /dev/null 2>&1
|
|
_try_scratch_mount >/dev/null 2>&1 \
|
|
|| _notrun "kernel does not support sparse inodes"
|
|
_scratch_unmount
|
|
}
|
|
|
|
# check that xfs_db supports a specific command
|
|
_require_xfs_db_command()
|
|
{
|
|
if [ $# -ne 1 ]; then
|
|
echo "Usage: _require_xfs_db_command command" 1>&2
|
|
exit 1
|
|
fi
|
|
command=$1
|
|
|
|
_scratch_mkfs_xfs >/dev/null 2>&1
|
|
_scratch_xfs_db -x -c "help" | grep $command > /dev/null || \
|
|
_notrun "xfs_db $command support is missing"
|
|
}
|
|
|
|
# Does the filesystem mounted from a particular device support scrub?
|
|
_supports_xfs_scrub()
|
|
{
|
|
local mountpoint="$1"
|
|
local device="$2"
|
|
|
|
if [ -z "$device" ] || [ -z "$mountpoint" ]; then
|
|
echo "Usage: _supports_xfs_scrub mountpoint device"
|
|
return 1
|
|
fi
|
|
|
|
if [ ! -b "$device" ] || [ ! -e "$mountpoint" ]; then
|
|
return 1
|
|
fi
|
|
|
|
test "$FSTYP" = "xfs" || return 1
|
|
test -x "$XFS_SCRUB_PROG" || return 1
|
|
|
|
# Probe for kernel support...
|
|
$XFS_IO_PROG -c 'help scrub' 2>&1 | grep -q 'types are:.*probe' || return 1
|
|
$XFS_IO_PROG -c "scrub probe" "$mountpoint" 2>&1 | grep -q "Inappropriate ioctl" && return 1
|
|
|
|
# Scrub can't run on norecovery mounts
|
|
_fs_options "$device" | grep -q "norecovery" && return 1
|
|
|
|
return 0
|
|
}
|
|
|
|
# run xfs_check and friends on a FS.
|
|
_check_xfs_filesystem()
|
|
{
|
|
if [ $# -ne 3 ]; then
|
|
echo "Usage: _check_xfs_filesystem device <logdev>|none <rtdev>|none" 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
extra_mount_options=""
|
|
extra_log_options=""
|
|
extra_options=""
|
|
device=$1
|
|
if [ -f $device ]; then
|
|
extra_options="-f"
|
|
fi
|
|
|
|
if [ "$2" != "none" ]; then
|
|
extra_log_options="-l$2"
|
|
extra_mount_options="-ologdev=$2"
|
|
fi
|
|
|
|
if [ "$3" != "none" ]; then
|
|
extra_rt_options="-r$3"
|
|
extra_mount_options=$extra_mount_options" -ortdev=$3"
|
|
fi
|
|
extra_mount_options=$extra_mount_options" $MOUNT_OPTIONS"
|
|
|
|
[ "$FSTYP" != xfs ] && return 0
|
|
|
|
type=`_fs_type $device`
|
|
ok=1
|
|
|
|
# Run online scrub if we can.
|
|
mntpt="$(_is_dev_mounted $device)"
|
|
if [ -n "$mntpt" ] && _supports_xfs_scrub "$mntpt" "$device"; then
|
|
"$XFS_SCRUB_PROG" $scrubflag -v -d -n $mntpt > $tmp.scrub 2>&1
|
|
if [ $? -ne 0 ]; then
|
|
_log_err "_check_xfs_filesystem: filesystem on $device failed scrub"
|
|
echo "*** xfs_scrub $scrubflag -v -d -n output ***" >> $seqres.full
|
|
cat $tmp.scrub >> $seqres.full
|
|
echo "*** end xfs_scrub output" >> $serqres.full
|
|
ok=0
|
|
fi
|
|
rm -f $tmp.scrub
|
|
fi
|
|
|
|
if [ "$type" = "xfs" ]; then
|
|
# mounted ...
|
|
mountpoint=`_umount_or_remount_ro $device`
|
|
fi
|
|
|
|
$XFS_LOGPRINT_PROG -t $extra_log_options $device 2>&1 \
|
|
| tee $tmp.logprint | grep -q "<CLEAN>"
|
|
if [ $? -ne 0 -a "$HOSTOS" = "Linux" ]; then
|
|
_log_err "_check_xfs_filesystem: filesystem on $device has dirty log"
|
|
echo "*** xfs_logprint -t output ***" >>$seqres.full
|
|
cat $tmp.logprint >>$seqres.full
|
|
echo "*** end xfs_logprint output" >>$seqres.full
|
|
|
|
ok=0
|
|
fi
|
|
|
|
# xfs_check runs out of memory on large files, so even providing the test
|
|
# option (-t) to avoid indexing the free space trees doesn't make it pass on
|
|
# large filesystems. Avoid it.
|
|
if [ "$LARGE_SCRATCH_DEV" != yes ]; then
|
|
_xfs_check $extra_log_options $device 2>&1 > $tmp.fs_check
|
|
fi
|
|
if [ -s $tmp.fs_check ]; then
|
|
_log_err "_check_xfs_filesystem: filesystem on $device is inconsistent (c)"
|
|
echo "*** xfs_check output ***" >>$seqres.full
|
|
cat $tmp.fs_check >>$seqres.full
|
|
echo "*** end xfs_check output" >>$seqres.full
|
|
|
|
ok=0
|
|
fi
|
|
|
|
$XFS_REPAIR_PROG -n $extra_options $extra_log_options $extra_rt_options $device >$tmp.repair 2>&1
|
|
if [ $? -ne 0 ]; then
|
|
_log_err "_check_xfs_filesystem: filesystem on $device is inconsistent (r)"
|
|
echo "*** xfs_repair -n output ***" >>$seqres.full
|
|
cat $tmp.repair >>$seqres.full
|
|
echo "*** end xfs_repair output" >>$seqres.full
|
|
|
|
ok=0
|
|
fi
|
|
rm -f $tmp.fs_check $tmp.logprint $tmp.repair
|
|
|
|
# Optionally test the index rebuilding behavior.
|
|
if [ -n "$TEST_XFS_REPAIR_REBUILD" ]; then
|
|
$XFS_REPAIR_PROG $extra_options $extra_log_options $extra_rt_options $device >$tmp.repair 2>&1
|
|
if [ $? -ne 0 ]; then
|
|
_log_err "_check_xfs_filesystem: filesystem on $device is inconsistent (rebuild)"
|
|
echo "*** xfs_repair output ***" >>$seqres.full
|
|
cat $tmp.repair >>$seqres.full
|
|
echo "*** end xfs_repair output" >>$seqres.full
|
|
|
|
ok=0
|
|
fi
|
|
rm -f $tmp.repair
|
|
|
|
$XFS_REPAIR_PROG -n $extra_options $extra_log_options $extra_rt_options $device >$tmp.repair 2>&1
|
|
if [ $? -ne 0 ]; then
|
|
_log_err "_check_xfs_filesystem: filesystem on $device is inconsistent (rebuild-reverify)"
|
|
echo "*** xfs_repair -n output ***" >>$seqres.full
|
|
cat $tmp.repair >>$seqres.full
|
|
echo "*** end xfs_repair output" >>$seqres.full
|
|
|
|
ok=0
|
|
fi
|
|
rm -f $tmp.repair
|
|
fi
|
|
|
|
if [ $ok -eq 0 ]; then
|
|
echo "*** mount output ***" >>$seqres.full
|
|
_mount >>$seqres.full
|
|
echo "*** end mount output" >>$seqres.full
|
|
elif [ "$type" = "xfs" ]; then
|
|
_mount_or_remount_rw "$extra_mount_options" $device $mountpoint
|
|
fi
|
|
|
|
if [ $ok -eq 0 ]; then
|
|
status=1
|
|
if [ "$iam" != "check" ]; then
|
|
exit 1
|
|
fi
|
|
return 1
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
_check_xfs_test_fs()
|
|
{
|
|
TEST_LOG="none"
|
|
TEST_RT="none"
|
|
[ "$USE_EXTERNAL" = yes -a ! -z "$TEST_LOGDEV" ] && \
|
|
TEST_LOG="$TEST_LOGDEV"
|
|
|
|
[ "$USE_EXTERNAL" = yes -a ! -z "$TEST_RTDEV" ] && \
|
|
TEST_RT="$TEST_RTDEV"
|
|
|
|
_check_xfs_filesystem $TEST_DEV $TEST_LOG $TEST_RT
|
|
return $?
|
|
}
|
|
|
|
_require_xfs_test_rmapbt()
|
|
{
|
|
_require_test
|
|
|
|
if [ "$($XFS_INFO_PROG "$TEST_DIR" | grep -c "rmapbt=1")" -ne 1 ]; then
|
|
_notrun "rmapbt not supported by test filesystem type: $FSTYP"
|
|
fi
|
|
}
|
|
|
|
_require_xfs_scratch_rmapbt()
|
|
{
|
|
_require_scratch
|
|
|
|
_scratch_mkfs > /dev/null
|
|
_scratch_mount
|
|
if [ "$($XFS_INFO_PROG "$SCRATCH_MNT" | grep -c "rmapbt=1")" -ne 1 ]; then
|
|
_scratch_unmount
|
|
_notrun "rmapbt not supported by scratch filesystem type: $FSTYP"
|
|
fi
|
|
_scratch_unmount
|
|
}
|
|
|
|
_xfs_bmapx_find()
|
|
{
|
|
case "$1" in
|
|
"attr")
|
|
param="a"
|
|
;;
|
|
"cow")
|
|
param="c"
|
|
;;
|
|
*)
|
|
param="e"
|
|
;;
|
|
esac
|
|
shift
|
|
file="$1"
|
|
shift
|
|
|
|
$XFS_IO_PROG -c "bmap -${param}lpv" "$file" | grep -c "$@"
|
|
}
|
|
|
|
# Reset all xfs error handling attributes, set them to original
|
|
# status.
|
|
#
|
|
# Only one argument, and it's mandatory:
|
|
# - dev: device name, e.g. $SCRATCH_DEV
|
|
#
|
|
# Note: this function only works for XFS
|
|
_reset_xfs_sysfs_error_handling()
|
|
{
|
|
local dev=$1
|
|
|
|
if [ ! -b "$dev" -o "$FSTYP" != "xfs" ]; then
|
|
_fail "Usage: reset_xfs_sysfs_error_handling <device>"
|
|
fi
|
|
|
|
_set_fs_sysfs_attr $dev error/fail_at_unmount 1
|
|
echo -n "error/fail_at_unmount="
|
|
_get_fs_sysfs_attr $dev error/fail_at_unmount
|
|
|
|
# Make sure all will be configured to retry forever by default, except
|
|
# for ENODEV, which is an unrecoverable error, so it will be configured
|
|
# to not retry on error by default.
|
|
for e in default EIO ENOSPC; do
|
|
_set_fs_sysfs_attr $dev \
|
|
error/metadata/${e}/max_retries -1
|
|
echo -n "error/metadata/${e}/max_retries="
|
|
_get_fs_sysfs_attr $dev error/metadata/${e}/max_retries
|
|
|
|
_set_fs_sysfs_attr $dev \
|
|
error/metadata/${e}/retry_timeout_seconds 0
|
|
echo -n "error/metadata/${e}/retry_timeout_seconds="
|
|
_get_fs_sysfs_attr $dev \
|
|
error/metadata/${e}/retry_timeout_seconds
|
|
done
|
|
}
|
|
|
|
# Skip if we are running an older binary without the stricter input checks.
|
|
# Make multiple checks to be sure that there is no regression on the one
|
|
# selected feature check, which would skew the result.
|
|
#
|
|
# At first, make a common function that runs the tests and returns
|
|
# number of failed cases.
|
|
_xfs_mkfs_validation_check()
|
|
{
|
|
local tmpfile=`mktemp`
|
|
local cmd="$MKFS_XFS_PROG -f -N -d file,name=$tmpfile,size=1g"
|
|
|
|
$cmd -s size=8s >/dev/null 2>&1
|
|
local sum=$?
|
|
|
|
$cmd -l version=2,su=260k >/dev/null 2>&1
|
|
sum=`expr $sum + $?`
|
|
|
|
rm -f $tmpfile
|
|
return $sum
|
|
}
|
|
|
|
# Skip the test if all calls passed - mkfs accepts invalid input
|
|
_require_xfs_mkfs_validation()
|
|
{
|
|
_xfs_mkfs_validation_check
|
|
if [ "$?" -eq 0 ]; then
|
|
_notrun "Requires newer mkfs with stricter input checks: the oldest supported version of xfsprogs is 4.7."
|
|
fi
|
|
}
|
|
|
|
# The opposite of _require_xfs_mkfs_validation.
|
|
_require_xfs_mkfs_without_validation()
|
|
{
|
|
_xfs_mkfs_validation_check
|
|
if [ "$?" -ne 0 ]; then
|
|
_notrun "Requires older mkfs without strict input checks: the last supported version of xfsprogs is 4.5."
|
|
fi
|
|
}
|
|
|
|
# XFS ability to change UUIDs on V5/CRC filesystems
|
|
#
|
|
_require_meta_uuid()
|
|
{
|
|
# This will create a crc fs on $SCRATCH_DEV
|
|
_require_xfs_crc
|
|
|
|
_scratch_xfs_db -x -c "uuid restore" 2>&1 \
|
|
| grep -q "invalid UUID\|supported on V5 fs" \
|
|
&& _notrun "Userspace doesn't support meta_uuid feature"
|
|
|
|
_scratch_xfs_db -x -c "uuid generate" >/dev/null 2>&1
|
|
|
|
_try_scratch_mount >/dev/null 2>&1 \
|
|
|| _notrun "Kernel doesn't support meta_uuid feature"
|
|
_scratch_unmount
|
|
}
|
|
|
|
# this test requires mkfs.xfs have case-insensitive naming support
|
|
_require_xfs_mkfs_ciname()
|
|
{
|
|
_scratch_mkfs_xfs_supported -n version=ci >/dev/null 2>&1 \
|
|
|| _notrun "need case-insensitive naming support in mkfs.xfs"
|
|
}
|
|
|
|
# XFS_DEBUG requirements
|
|
_require_xfs_debug()
|
|
{
|
|
if grep -q "debug 0" /proc/fs/xfs/stat; then
|
|
_notrun "Require XFS built with CONFIG_XFS_DEBUG"
|
|
fi
|
|
}
|
|
_require_no_xfs_debug()
|
|
{
|
|
if grep -q "debug 1" /proc/fs/xfs/stat; then
|
|
_notrun "Require XFS built without CONFIG_XFS_DEBUG"
|
|
fi
|
|
}
|
|
|
|
# Require that assertions will not crash the system.
|
|
#
|
|
# Assertions would always crash the system if XFS assert fatal was enabled
|
|
# (CONFIG_XFS_ASSERT_FATAL=y). If a test is designed to trigger an assertion,
|
|
# skip the test on a CONFIG_XFS_ASSERT_FATAL built XFS by default. Note:
|
|
# CONFIG_XFS_ASSERT_FATAL can be disabled by setting bug_on_assert to zero if
|
|
# we want test to run.
|
|
_require_no_xfs_bug_on_assert()
|
|
{
|
|
if [ -f /sys/fs/xfs/debug/bug_on_assert ]; then
|
|
grep -q "1" /sys/fs/xfs/debug/bug_on_assert && \
|
|
_notrun "test requires XFS bug_on_assert to be off, turn it off to run the test"
|
|
else
|
|
# Note: Prior to the creation of CONFIG_XFS_ASSERT_FATAL (and
|
|
# the sysfs knob bug_on_assert), assertions would always crash
|
|
# the system if XFS debug was enabled (CONFIG_XFS_DEBUG=y). If
|
|
# a test is designed to trigger an assertion and the test
|
|
# designer does not want to hang fstests, skip the test.
|
|
_require_no_xfs_debug
|
|
fi
|
|
}
|
|
|
|
# Get a metadata field
|
|
# The first arg is the field name
|
|
# The rest of the arguments are xfs_db commands to find the metadata.
|
|
_scratch_xfs_get_metadata_field()
|
|
{
|
|
local key="$1"
|
|
shift
|
|
|
|
local grep_key="$(echo "${key}" | tr '[]()' '....')"
|
|
local cmds=()
|
|
local arg
|
|
for arg in "$@"; do
|
|
cmds+=("-c" "${arg}")
|
|
done
|
|
_scratch_xfs_db "${cmds[@]}" -c "print ${key}" | grep "^${grep_key}" | \
|
|
sed -e 's/^.* = //g'
|
|
}
|
|
|
|
# Set a metadata field
|
|
# The first arg is the field name
|
|
# The second arg is the new value
|
|
# The rest of the arguments are xfs_db commands to find the metadata.
|
|
_scratch_xfs_set_metadata_field()
|
|
{
|
|
local key="$1"
|
|
local value="$2"
|
|
shift; shift
|
|
|
|
local cmds=()
|
|
local arg
|
|
for arg in "$@"; do
|
|
cmds+=("-c" "${arg}")
|
|
done
|
|
|
|
local wr_cmd="write"
|
|
_scratch_xfs_db -x -c "help write" | egrep -q "(-c|-d)" && value="-- ${value}"
|
|
_scratch_xfs_db -x -c "help write" | egrep -q "(-d)" && wr_cmd="${wr_cmd} -d"
|
|
_scratch_xfs_db -x "${cmds[@]}" -c "${wr_cmd} ${key} ${value}"
|
|
}
|
|
|
|
_scratch_xfs_get_sb_field()
|
|
{
|
|
_scratch_xfs_get_metadata_field "$1" "sb 0"
|
|
}
|
|
|
|
_scratch_xfs_set_sb_field()
|
|
{
|
|
_scratch_xfs_set_metadata_field "$1" "$2" "sb 0"
|
|
}
|
|
|
|
# Before xfsprogs commit 4222d000ed("db: write via array indexing doesn't
|
|
# work"), xfs_db command to write a specific AGFL index doesn't work. It's a
|
|
# bug in a diagnostic tool that is only used by XFS developers as a test
|
|
# infrastructure, so it's fine to treat it as a infrastructure dependency as
|
|
# all other _require rules.
|
|
_require_xfs_db_write_array()
|
|
{
|
|
local supported=0
|
|
|
|
_require_test
|
|
touch $TEST_DIR/$seq.img
|
|
$MKFS_XFS_PROG -d file,name=$TEST_DIR/$seq.img,size=512m >/dev/null 2>&1
|
|
$XFS_DB_PROG -x -c "agfl 0" -c "write bno[32] 78" $TEST_DIR/$seq.img \
|
|
>/dev/null 2>&1
|
|
$XFS_DB_PROG -x -c "agfl 0" -c "print bno[32]" $TEST_DIR/$seq.img \
|
|
| grep -q "bno\[32\] = 78" && supported=1
|
|
rm -f $TEST_DIR/$seq.img
|
|
[ $supported -eq 0 ] && _notrun "xfs_db write can't support array"
|
|
}
|
|
|
|
_require_xfs_spaceman_command()
|
|
{
|
|
if [ -z "$1" ]; then
|
|
echo "Usage: _require_xfs_spaceman_command command [switch]" 1>&2
|
|
exit 1
|
|
fi
|
|
local command=$1
|
|
shift
|
|
local param="$*"
|
|
local param_checked=0
|
|
local opts=""
|
|
|
|
_require_command "$XFS_SPACEMAN_PROG" "xfs_spaceman"
|
|
|
|
testfile=$TEST_DIR/$$.xfs_spaceman
|
|
case $command in
|
|
*)
|
|
testio=`$XFS_SPACEMAN_PROG -c "help $command" $TEST_DIR 2>&1`
|
|
esac
|
|
|
|
rm -f $testfile 2>&1 > /dev/null
|
|
echo $testio | grep -q "not found" && \
|
|
_notrun "xfs_spaceman $command support is missing"
|
|
echo $testio | grep -q "Operation not supported" && \
|
|
_notrun "xfs_spaceman $command failed (old kernel/wrong fs?)"
|
|
echo $testio | grep -q "Invalid" && \
|
|
_notrun "xfs_spaceman $command failed (old kernel/wrong fs/bad args?)"
|
|
echo $testio | grep -q "foreign file active" && \
|
|
_notrun "xfs_spaceman $command not supported on $FSTYP"
|
|
echo $testio | grep -q "Function not implemented" && \
|
|
_notrun "xfs_spaceman $command support is missing (missing syscall?)"
|
|
|
|
[ -n "$param" ] || return
|
|
|
|
if [ $param_checked -eq 0 ]; then
|
|
$XFS_SPACEMAN_PROG -c "help $command" | grep -q "^ $param --" || \
|
|
_notrun "xfs_spaceman $command doesn't support $param"
|
|
fi
|
|
}
|
|
|
|
_scratch_get_sfdir_prefix() {
|
|
local dir_ino="$1"
|
|
|
|
for prefix in "u.sfdir3" "u.sfdir2" "u3.sfdir3"; do
|
|
if [ -n "$(_scratch_xfs_get_metadata_field \
|
|
"${prefix}.hdr.parent.i4" \
|
|
"inode ${dir_ino}")" ]; then
|
|
echo "${prefix}"
|
|
return 0
|
|
fi
|
|
done
|
|
_scratch_xfs_db -c "inode ${dir_ino}" -c 'p' >> $seqres.full
|
|
return 1
|
|
}
|
|
|
|
_scratch_get_bmx_prefix() {
|
|
local ino="$1"
|
|
|
|
for prefix in "u3.bmx" "u.bmx"; do
|
|
if [ -n "$(_scratch_xfs_get_metadata_field \
|
|
"${prefix}[0].startblock" \
|
|
"inode ${ino}")" ]; then
|
|
echo "${prefix}"
|
|
return 0
|
|
fi
|
|
done
|
|
_scratch_xfs_db -c "inode ${ino}" -c 'p' >> $seqres.full
|
|
return 1
|
|
}
|
|
|
|
#
|
|
# Ensures that we don't pass any mount options incompatible with XFS v4
|
|
#
|
|
_force_xfsv4_mount_options()
|
|
{
|
|
local gquota=0
|
|
local pquota=0
|
|
|
|
# Can't have group and project quotas in XFS v4
|
|
echo "$MOUNT_OPTIONS" | egrep -q "(gquota|grpquota|grpjquota=|gqnoenforce)" && gquota=1
|
|
echo "$MOUNT_OPTIONS" | egrep -q "(\bpquota|prjquota|pqnoenforce)" && pquota=1
|
|
|
|
if [ $gquota -gt 0 ] && [ $pquota -gt 0 ]; then
|
|
export MOUNT_OPTIONS=$(echo $MOUNT_OPTIONS \
|
|
| sed -e 's/gquota/QUOTA/g' \
|
|
-e 's/grpquota/QUOTA/g' \
|
|
-e 's/grpjquota=[^, ]/QUOTA/g' \
|
|
-e 's/gqnoenforce/QUOTA/g' \
|
|
-e "s/QUOTA/defaults/g")
|
|
fi
|
|
echo "MOUNT_OPTIONS = $MOUNT_OPTIONS" >>$seqres.full
|
|
}
|