Files
apfstests/common/xfs
T
zhangyi (F) 69f7669ef6 common/rc: improve dev mounted check helper
There is a problem of missing fstype check in _is_mounted() helper,
it will return the mountpoint if only the device arguments matches.

For example:
  Base mounted filesystem:
    /dev/sda2 on /boot type ext4 (rw,relatime,data=ordered)

  FSTYPE=xfs
  mountpoint=`_is_mounted /dev/sda1`
  echo "$mountpoint"

  Output: /boot

This patch rename _is_mounted to _is_dev_mounted because it check
the given device only (not mount dir), and add an optional "fstype"
parameter, let user specify file system type instead of default
FSTYPE. Finally, use findmnt instead of mount to avoid complex
processing of mount info and fix this problem simply.

Signed-off-by: zhangyi (F) <yi.zhang@huawei.com>
Reviewed-by: Eryu Guan <guaneryu@gmail.com>
Signed-off-by: Eryu Guan <guaneryu@gmail.com>
2018-03-01 23:00:05 +08:00

700 lines
18 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
}
_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=$?
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"
[ "$LARGE_SCRATCH_DEV" = yes ] && SCRATCH_OPTIONS=$SCRATCH_OPTIONS" -t"
$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 $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_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 [ ! -b "$device" ] || [ ! -e "$mountpoint" ]; then
echo "Usage: _supports_xfs_scrub mountpoint device"
exit 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 $device > $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 |\
_fix_malloc >$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 | _fix_malloc >>$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 | _fix_malloc >>$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 | _fix_malloc >>$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 "$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 "$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"
}