mirror of
https://github.com/linux-apfs/apfstests.git
synced 2026-05-01 15:01:44 -07:00
f170290a83
Changes in the XFS logging code have lead to small leaks in the log grant heads that consume log space slowly over time. Such problems have gone undetected for an unnecessarily long time due to code complexity and potential for very subtle problems. Losing only a few bytes per logged item on a reasonably large enough fs (10s of GB) means only the most continuously stressful workloads will cause a severe enough failure (deadlock due to log reservation exhaustion) quickly enough to indicate something is seriously wrong. Recent changes in XFS export the state of the various log heads through sysfs to aid in userspace/runtime analysis of the log. This test runs a workload against an XFS filesystem, quiesces the fs and verifies that the log reserve and write grant heads have not leaked any space with respect to the current head of the physical log. Signed-off-by: Brian Foster <bfoster@redhat.com> Reviewed-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Dave Chinner <david@fromorbit.com>
2283 lines
51 KiB
Plaintext
2283 lines
51 KiB
Plaintext
##/bin/bash
|
|
#-----------------------------------------------------------------------
|
|
# Copyright (c) 2000-2006 Silicon Graphics, Inc. All Rights Reserved.
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
|
# USA
|
|
#
|
|
# Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
|
|
# Mountain View, CA 94043, USA, or: http://www.sgi.com
|
|
#-----------------------------------------------------------------------
|
|
|
|
BC=$(which bc 2> /dev/null) || BC=
|
|
|
|
_require_math()
|
|
{
|
|
if [ -z "$BC" ]; then
|
|
_notrun "this test requires 'bc' tool for doing math operations"
|
|
fi
|
|
}
|
|
|
|
_math()
|
|
{
|
|
[ $# -le 0 ] && return
|
|
if [ "$BC" ]; then
|
|
result=$(LANG=C echo "scale=0; $@" | "$BC" -q 2> /dev/null)
|
|
else
|
|
_notrun "this test requires 'bc' tool for doing math operations"
|
|
fi
|
|
echo "$result"
|
|
}
|
|
|
|
dd()
|
|
{
|
|
if [ "$HOSTOS" == "Linux" ]
|
|
then
|
|
command dd --help | grep noxfer > /dev/null 2>&1
|
|
|
|
if [ "$?" -eq 0 ]
|
|
then
|
|
command dd status=noxfer $@
|
|
else
|
|
command dd $@
|
|
fi
|
|
else
|
|
command dd $@
|
|
fi
|
|
}
|
|
|
|
_btrfs_get_subvolid()
|
|
{
|
|
mnt=$1
|
|
name=$2
|
|
|
|
$BTRFS_UTIL_PROG sub list $mnt | grep $name | awk '{ print $2 }'
|
|
}
|
|
|
|
# Prints the md5 checksum of a given file
|
|
_md5_checksum()
|
|
{
|
|
md5sum $1 | cut -d ' ' -f1
|
|
}
|
|
|
|
|
|
# ls -l w/ selinux sometimes puts a dot at the end:
|
|
# -rwxrw-r--. id1 id2 file1
|
|
# Also filter out lost+found directory on extN file system if present
|
|
|
|
_ls_l()
|
|
{
|
|
ls -l $* | sed "s/\(^[-rwxdlbcpsStT]*\)\. /\1 /" | grep -v 'lost+found'
|
|
}
|
|
|
|
# we need common/config
|
|
if [ "$iam" != "check" ]
|
|
then
|
|
if ! . ./common/config
|
|
then
|
|
echo "$iam: failed to source common/config"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# check for correct setup
|
|
case "$FSTYP" in
|
|
xfs)
|
|
[ "$XFS_LOGPRINT_PROG" = "" ] && _fatal "xfs_logprint not found"
|
|
[ "$XFS_REPAIR_PROG" = "" ] && _fatal "xfs_repair not found"
|
|
[ "$XFS_DB_PROG" = "" ] && _fatal "xfs_db not found"
|
|
[ "$MKFS_XFS_PROG" = "" ] && _fatal "mkfs_xfs not found"
|
|
;;
|
|
udf)
|
|
[ "$MKFS_UDF_PROG" = "" ] && _fatal "mkfs_udf/mkudffs not found"
|
|
;;
|
|
btrfs)
|
|
[ "$MKFS_BTRFS_PROG" = "" ] && _fatal "mkfs.btrfs not found"
|
|
;;
|
|
nfs)
|
|
;;
|
|
esac
|
|
|
|
# make sure we have a standard umask
|
|
umask 022
|
|
|
|
_mount()
|
|
{
|
|
$MOUNT_PROG `_mount_ops_filter $*`
|
|
}
|
|
|
|
_scratch_options()
|
|
{
|
|
type=$1
|
|
SCRATCH_OPTIONS=""
|
|
|
|
if [ "$FSTYP" != "xfs" ]; then
|
|
return
|
|
fi
|
|
|
|
case $type in
|
|
mkfs)
|
|
[ "$HOSTOS" != "IRIX" ] && SCRATCH_OPTIONS="$SCRATCH_OPTIONS -f"
|
|
rt_opt="-r"
|
|
log_opt="-l"
|
|
;;
|
|
mount)
|
|
rt_opt="-o"
|
|
log_opt="-o"
|
|
;;
|
|
esac
|
|
[ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_RTDEV" ] && \
|
|
SCRATCH_OPTIONS="$SCRATCH_OPTIONS ${rt_opt}rtdev=$SCRATCH_RTDEV"
|
|
[ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_LOGDEV" ] && \
|
|
SCRATCH_OPTIONS="$SCRATCH_OPTIONS ${log_opt}logdev=$SCRATCH_LOGDEV"
|
|
}
|
|
|
|
_test_options()
|
|
{
|
|
type=$1
|
|
TEST_OPTIONS=""
|
|
|
|
if [ "$FSTYP" != "xfs" ]; then
|
|
return
|
|
fi
|
|
|
|
case $type in
|
|
mkfs)
|
|
rt_opt="-r"
|
|
log_opt="-l"
|
|
;;
|
|
mount)
|
|
rt_opt="-o"
|
|
log_opt="-o"
|
|
;;
|
|
esac
|
|
[ "$USE_EXTERNAL" = yes -a ! -z "$TEST_RTDEV" ] && \
|
|
TEST_OPTIONS="$TEST_OPTIONS ${rt_opt}rtdev=$TEST_RTDEV"
|
|
[ "$USE_EXTERNAL" = yes -a ! -z "$TEST_LOGDEV" ] && \
|
|
TEST_OPTIONS="$TEST_OPTIONS ${log_opt}logdev=$TEST_LOGDEV"
|
|
}
|
|
|
|
_mount_ops_filter()
|
|
{
|
|
params="$*"
|
|
|
|
#get mount point to handle dmapi mtpt option correctly
|
|
let last_index=$#-1
|
|
[ $last_index -gt 0 ] && shift $last_index
|
|
FS_ESCAPED=$1
|
|
|
|
# irix is fussy about how it is fed its mount options
|
|
# - multiple -o's are not allowed
|
|
# - no spaces between comma delimitered options
|
|
# the sed script replaces all -o's (except the first) with a comma
|
|
# not required for linux, but won't hurt
|
|
|
|
echo $params | sed -e 's/[[:space:]]\+-o[[:space:]]*/UnIqUe/1; s/[[:space:]]\+-o[[:space:]]*/,/g; s/UnIqUe/ -o /1' \
|
|
| sed -e 's/dmapi/dmi/' \
|
|
| $PERL_PROG -ne "s#mtpt=[^,|^\n|^\s]*#mtpt=$FS_ESCAPED\1\2#; print;"
|
|
|
|
}
|
|
|
|
_scratch_mount_options()
|
|
{
|
|
_scratch_options mount
|
|
|
|
echo $SCRATCH_OPTIONS $MOUNT_OPTIONS $SELINUX_MOUNT_OPTIONS $* $SCRATCH_DEV $SCRATCH_MNT
|
|
}
|
|
|
|
_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 $SELINUX_MOUNT_OPTIONS $* $TEST_DEV $TEST_DIR
|
|
}
|
|
|
|
_scratch_mkfs_options()
|
|
{
|
|
_scratch_options mkfs
|
|
echo $SCRATCH_OPTIONS $MKFS_OPTIONS $* $SCRATCH_DEV
|
|
}
|
|
|
|
_scratch_metadump()
|
|
{
|
|
dumpfile=$1
|
|
options=
|
|
|
|
[ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_LOGDEV" ] && \
|
|
options="-l $SCRATCH_LOGDEV"
|
|
|
|
xfs_metadump $options $SCRATCH_DEV $dumpfile
|
|
}
|
|
|
|
_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
|
|
_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=$?
|
|
umount $SCRATCH_MNT
|
|
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=$*
|
|
|
|
_scratch_options mkfs
|
|
|
|
$MKFS_XFS_PROG $SCRATCH_OPTIONS $mkfs_opts $SCRATCH_DEV
|
|
}
|
|
|
|
|
|
_scratch_mkfs_xfs_supported()
|
|
{
|
|
mkfs_opts=$*
|
|
|
|
_scratch_options mkfs
|
|
|
|
$MKFS_XFS_PROG -N $MKFS_OPTIONS $SCRATCH_OPTIONS $mkfs_opts $SCRATCH_DEV
|
|
}
|
|
|
|
_scratch_mkfs_xfs()
|
|
{
|
|
# extra mkfs options can be added by tests
|
|
local extra_mkfs_options=$*
|
|
|
|
local tmp_dir=/tmp/
|
|
|
|
# save mkfs output in case conflict means we need to run again.
|
|
# only the output for the mkfs that applies should be shown
|
|
_scratch_mkfs_xfs_opts $MKFS_OPTIONS $extra_mkfs_options \
|
|
2>$tmp_dir.mkfserr 1>$tmp_dir.mkfsstd
|
|
local mkfs_status=$?
|
|
|
|
|
|
# a mkfs failure may be caused by conflicts between
|
|
# $MKFS_OPTIONS and $extra_mkfs_options
|
|
if [ $mkfs_status -ne 0 -a ! -z "$extra_mkfs_options" ]; then
|
|
(
|
|
echo -n "** mkfs failed with extra mkfs options "
|
|
echo "added to \"$MKFS_OPTIONS\" by test $seq **"
|
|
echo -n "** attempting to mkfs using only test $seq "
|
|
echo "options: $extra_mkfs_options **"
|
|
) >> $seqres.full
|
|
|
|
# running mkfs again. overwrite previous mkfs output files
|
|
_scratch_mkfs_xfs_opts $extra_mkfs_options \
|
|
2>$tmp_dir.mkfserr 1>$tmp_dir.mkfsstd
|
|
local mkfs_status=$?
|
|
fi
|
|
|
|
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_dir.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 stored mkfs output
|
|
cat $tmp_dir.mkfserr >&2
|
|
cat $tmp_dir.mkfsstd
|
|
rm -f $tmp_dir.mkfserr $tmp_dir.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"
|
|
|
|
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
|
|
}
|
|
|
|
_setup_large_ext4_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
|
|
|
|
# Default free space in the FS is 50GB, but you can specify more via
|
|
# SCRATCH_DEV_EMPTY_SPACE
|
|
space_to_consume=$(($fs_size - 50*1024*1024*1024 - $SCRATCH_DEV_EMPTY_SPACE))
|
|
|
|
# mount the filesystem and create 16TB - 4KB files until we consume
|
|
# all the necessary space.
|
|
_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
|
|
|
|
file_size=$((16*1024*1024*1024*1024 - 4096))
|
|
nfiles=0
|
|
while [ $space_to_consume -gt $file_size ]; do
|
|
|
|
xfs_io -F -f \
|
|
-c "truncate $file_size" \
|
|
-c "falloc -k 0 $file_size" \
|
|
$SCRATCH_MNT/.use_space.$nfiles 2>&1
|
|
status=$?
|
|
if [ $status -ne 0 ]; then
|
|
break;
|
|
fi
|
|
|
|
space_to_consume=$(( $space_to_consume - $file_size ))
|
|
nfiles=$(($nfiles + 1))
|
|
done
|
|
|
|
# consume the remaining space.
|
|
if [ $space_to_consume -gt 0 ]; then
|
|
xfs_io -F -f \
|
|
-c "truncate $space_to_consume" \
|
|
-c "falloc -k 0 $space_to_consume" \
|
|
$SCRATCH_MNT/.use_space.$nfiles 2>&1
|
|
status=$?
|
|
fi
|
|
export NUM_SPACE_FILES=$nfiles
|
|
|
|
umount $SCRATCH_MNT
|
|
if [ $status -ne 0 ]; then
|
|
echo "large file prealloc failed"
|
|
cat $tmp_dir/mnt.err >&2
|
|
return $status
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
_scratch_mkfs_ext4()
|
|
{
|
|
local tmp_dir=/tmp/
|
|
|
|
/sbin/mkfs -t $FSTYP -- -F $MKFS_OPTIONS $* $SCRATCH_DEV \
|
|
2>$tmp_dir.mkfserr 1>$tmp_dir.mkfsstd
|
|
local 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
|
|
fs_size=`cat $tmp_dir.mkfsstd | awk ' \
|
|
/^Block size/ { split($2, a, "="); bs = a[2] ; } \
|
|
/ inodes, / { blks = $3 } \
|
|
/reserved for the super user/ { resv = $1 } \
|
|
END { fssize = bs * blks - resv; print fssize }'`
|
|
|
|
_setup_large_ext4_fs $fs_size
|
|
mkfs_status=$?
|
|
fi
|
|
|
|
# output stored mkfs output
|
|
cat $tmp_dir.mkfserr >&2
|
|
cat $tmp_dir.mkfsstd
|
|
rm -f $tmp_dir.mkfserr $tmp_dir.mkfsstd
|
|
|
|
return $mkfs_status
|
|
}
|
|
|
|
_test_mkfs()
|
|
{
|
|
case $FSTYP in
|
|
nfs*)
|
|
# do nothing for nfs
|
|
;;
|
|
udf)
|
|
$MKFS_UDF_PROG $MKFS_OPTIONS $* $TEST_DEV > /dev/null
|
|
;;
|
|
btrfs)
|
|
$MKFS_BTRFS_PROG $MKFS_OPTIONS $* $TEST_DEV > /dev/null
|
|
;;
|
|
*)
|
|
yes | $MKFS_PROG -t $FSTYP -- $MKFS_OPTIONS $* $TEST_DEV
|
|
;;
|
|
esac
|
|
}
|
|
|
|
_scratch_mkfs()
|
|
{
|
|
case $FSTYP in
|
|
xfs)
|
|
_scratch_mkfs_xfs $*
|
|
;;
|
|
nfs*)
|
|
# do nothing for nfs
|
|
;;
|
|
udf)
|
|
$MKFS_UDF_PROG $MKFS_OPTIONS $* $SCRATCH_DEV > /dev/null
|
|
;;
|
|
btrfs)
|
|
$MKFS_BTRFS_PROG $MKFS_OPTIONS $* $SCRATCH_DEV > /dev/null
|
|
;;
|
|
ext4)
|
|
_scratch_mkfs_ext4 $*
|
|
;;
|
|
tmpfs)
|
|
# do nothing for tmpfs
|
|
;;
|
|
*)
|
|
yes | $MKFS_PROG -t $FSTYP -- $MKFS_OPTIONS $* $SCRATCH_DEV
|
|
;;
|
|
esac
|
|
}
|
|
|
|
_scratch_pool_mkfs()
|
|
{
|
|
case $FSTYP in
|
|
btrfs)
|
|
$MKFS_BTRFS_PROG $MKFS_OPTIONS $* $SCRATCH_DEV_POOL > /dev/null
|
|
;;
|
|
*)
|
|
echo "_scratch_pool_mkfs is not implemented for $FSTYP" 1>&2
|
|
;;
|
|
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
|
|
|
|
re='^[0-9]+$'
|
|
if ! [[ $fssize =~ $re ]] ; then
|
|
_notrun "error: _scratch_mkfs_sized: fs size \"$fssize\" not an integer."
|
|
fi
|
|
if ! [[ $blocksize =~ $re ]] ; then
|
|
_notrun "error: _scratch_mkfs_sized: block size \"$blocksize\" not an integer."
|
|
fi
|
|
|
|
blocks=`expr $fssize / $blocksize`
|
|
|
|
if [ "$HOSTOS" == "Linux" ]; then
|
|
devsize=`blockdev --getsize64 $SCRATCH_DEV`
|
|
[ "$fssize" -gt "$devsize" ] && _notrun "Scratch device too small"
|
|
fi
|
|
|
|
case $FSTYP in
|
|
xfs)
|
|
# don't override MKFS_OPTIONS that set a block size.
|
|
echo $MKFS_OPTIONS |egrep -q "b?size="
|
|
if [ $? -eq 0 ]; then
|
|
_scratch_mkfs_xfs -d size=$fssize
|
|
else
|
|
_scratch_mkfs_xfs -d size=$fssize -b size=$blocksize
|
|
fi
|
|
;;
|
|
ext2|ext3|ext4|ext4dev)
|
|
yes | ${MKFS_PROG}.$FSTYP $MKFS_OPTIONS -b $blocksize $SCRATCH_DEV $blocks
|
|
;;
|
|
udf)
|
|
$MKFS_UDF_PROG $MKFS_OPTIONS -b $blocksize $SCRATCH_DEV $blocks
|
|
;;
|
|
btrfs)
|
|
$MKFS_BTRFS_PROG $MKFS_OPTIONS -b $fssize $SCRATCH_DEV
|
|
;;
|
|
*)
|
|
_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|ext4dev)
|
|
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=""
|
|
[ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_LOGDEV" ] && \
|
|
SCRATCH_OPTIONS="-l$SCRATCH_LOGDEV"
|
|
echo $SCRATCH_OPTIONS $* $SCRATCH_DEV
|
|
}
|
|
|
|
_scratch_xfs_logprint()
|
|
{
|
|
SCRATCH_OPTIONS=""
|
|
[ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_LOGDEV" ] && \
|
|
SCRATCH_OPTIONS="-l$SCRATCH_LOGDEV"
|
|
$XFS_LOGPRINT_PROG $SCRATCH_OPTIONS $* $SCRATCH_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
|
|
}
|
|
|
|
_get_pids_by_name()
|
|
{
|
|
if [ $# -ne 1 ]
|
|
then
|
|
echo "Usage: _get_pids_by_name process-name" 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
# Algorithm ... all ps(1) variants have a time of the form MM:SS or
|
|
# HH:MM:SS before the psargs field, use this as the search anchor.
|
|
#
|
|
# Matches with $1 (process-name) occur if the first psarg is $1
|
|
# or ends in /$1 ... the matching uses sed's regular expressions,
|
|
# so passing a regex into $1 will work.
|
|
|
|
ps $PS_ALL_FLAGS \
|
|
| sed -n \
|
|
-e 's/$/ /' \
|
|
-e 's/[ ][ ]*/ /g' \
|
|
-e 's/^ //' \
|
|
-e 's/^[^ ]* //' \
|
|
-e "/[0-9]:[0-9][0-9] *[^ ]*\/$1 /s/ .*//p" \
|
|
-e "/[0-9]:[0-9][0-9] *$1 /s/ .*//p"
|
|
}
|
|
|
|
# fix malloc libs output
|
|
#
|
|
_fix_malloc()
|
|
{
|
|
# filter out the Electric Fence notice
|
|
$PERL_PROG -e '
|
|
while (<>) {
|
|
if (defined $o && /^\s+Electric Fence/) {
|
|
chomp($o);
|
|
print "$o";
|
|
undef $o;
|
|
next;
|
|
}
|
|
print $o if (defined $o);
|
|
|
|
$o=$_;
|
|
}
|
|
print $o if (defined $o);
|
|
'
|
|
}
|
|
|
|
# check if run as root
|
|
#
|
|
_need_to_be_root()
|
|
{
|
|
id=`id | $SED_PROG -e 's/(.*//' -e 's/.*=//'`
|
|
if [ "$id" -ne 0 ]
|
|
then
|
|
echo "Arrgh ... you need to be root (not uid=$id) to run this test"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
|
|
#
|
|
# _df_device : get an IRIX style df line for a given device
|
|
#
|
|
# - returns "" if not mounted
|
|
# - returns fs type in field two (ala IRIX)
|
|
# - joins line together if split by fancy df formatting
|
|
# - strips header etc
|
|
#
|
|
|
|
_df_device()
|
|
{
|
|
if [ $# -ne 1 ]
|
|
then
|
|
echo "Usage: _df_device device" 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
$DF_PROG 2>/dev/null | $AWK_PROG -v what=$1 '
|
|
match($1,what) && NF==1 {
|
|
v=$1
|
|
getline
|
|
print v, $0
|
|
exit
|
|
}
|
|
match($1,what) {
|
|
print
|
|
exit
|
|
}
|
|
'
|
|
}
|
|
|
|
#
|
|
# _df_dir : get an IRIX style df line for device where a directory resides
|
|
#
|
|
# - returns fs type in field two (ala IRIX)
|
|
# - joins line together if split by fancy df formatting
|
|
# - strips header etc
|
|
#
|
|
|
|
_df_dir()
|
|
{
|
|
if [ $# -ne 1 ]
|
|
then
|
|
echo "Usage: _df_dir device" 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
$DF_PROG $1 2>/dev/null | $AWK_PROG -v what=$1 '
|
|
NR == 2 && NF==1 {
|
|
v=$1
|
|
getline
|
|
print v, $0;
|
|
exit 0
|
|
}
|
|
NR == 2 {
|
|
print;
|
|
exit 0
|
|
}
|
|
{}
|
|
'
|
|
# otherwise, nada
|
|
}
|
|
|
|
# return percentage used disk space for mounted device
|
|
|
|
_used()
|
|
{
|
|
if [ $# -ne 1 ]
|
|
then
|
|
echo "Usage: _used device" 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
_df_device $1 | $AWK_PROG '{ sub("%", "") ; print $6 }'
|
|
}
|
|
|
|
# return the FS type of a mounted device
|
|
#
|
|
_fs_type()
|
|
{
|
|
if [ $# -ne 1 ]
|
|
then
|
|
echo "Usage: _fs_type device" 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
#
|
|
# The Linux kernel shows NFSv4 filesystems in df output as
|
|
# filesystem type nfs4, although we mounted it as nfs earlier.
|
|
# Fix the filesystem type up here so that the callers don't
|
|
# have to bother with this quirk.
|
|
#
|
|
_df_device $1 | $AWK_PROG '{ print $2 }' | sed -e 's/nfs4/nfs/'
|
|
}
|
|
|
|
# return the FS mount options of a mounted device
|
|
#
|
|
# should write a version which just parses the output of mount for IRIX
|
|
# compatibility, but since this isn't used at all, at the moment I'll leave
|
|
# this for now
|
|
#
|
|
_fs_options()
|
|
{
|
|
if [ $# -ne 1 ]
|
|
then
|
|
echo "Usage: _fs_options device" 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
$AWK_PROG -v dev=$1 '
|
|
match($1,dev) { print $4 }
|
|
' </proc/mounts
|
|
}
|
|
|
|
# returns device number if a file is a block device
|
|
#
|
|
_is_block_dev()
|
|
{
|
|
if [ $# -ne 1 ]
|
|
then
|
|
echo "Usage: _is_block_dev dev" 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
_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 $seqres.full, optionally test return status
|
|
# and die if command fails. If called with one argument _do executes the
|
|
# command, logs it, and returns its exit status. With two arguments _do
|
|
# first prints the message passed in the first argument, and then "done"
|
|
# or "fail" depending on the return status of the command passed in the
|
|
# second argument. If the command fails and the variable _do_die_on_error
|
|
# is set to "always" or the two argument form is used and _do_die_on_error
|
|
# is set to "message_only" _do will print an error message to
|
|
# $seqres.out and exit.
|
|
|
|
_do()
|
|
{
|
|
if [ $# -eq 1 ]; then
|
|
_cmd=$1
|
|
elif [ $# -eq 2 ]; then
|
|
_note=$1
|
|
_cmd=$2
|
|
echo -n "$_note... "
|
|
else
|
|
echo "Usage: _do [note] cmd" 1>&2
|
|
status=1; exit
|
|
fi
|
|
|
|
(eval "echo '---' \"$_cmd\"") >>$seqres.full
|
|
(eval "$_cmd") >$tmp._out 2>&1; ret=$?
|
|
cat $tmp._out | _fix_malloc >>$seqres.full
|
|
if [ $# -eq 2 ]; then
|
|
if [ $ret -eq 0 ]; then
|
|
echo "done"
|
|
else
|
|
echo "fail"
|
|
fi
|
|
fi
|
|
if [ $ret -ne 0 ] \
|
|
&& [ "$_do_die_on_error" = "always" \
|
|
-o \( $# -eq 2 -a "$_do_die_on_error" = "message_only" \) ]
|
|
then
|
|
[ $# -ne 2 ] && echo
|
|
eval "echo \"$_cmd\" failed \(returned $ret\): see $seqres.full"
|
|
status=1; exit
|
|
fi
|
|
|
|
return $ret
|
|
}
|
|
|
|
# bail out, setting up .notrun file
|
|
#
|
|
_notrun()
|
|
{
|
|
echo "$*" > $seqres.notrun
|
|
echo "$seq not run: $*"
|
|
status=0
|
|
exit
|
|
}
|
|
|
|
# just plain bail out
|
|
#
|
|
_fail()
|
|
{
|
|
echo "$*" | tee -a $seqres.full
|
|
echo "(see $seqres.full for details)"
|
|
status=1
|
|
exit 1
|
|
}
|
|
|
|
# tests whether $FSTYP is one of the supported filesystems for a test
|
|
#
|
|
_supported_fs()
|
|
{
|
|
for f
|
|
do
|
|
if [ "$f" = "$FSTYP" -o "$f" = "generic" ]
|
|
then
|
|
return
|
|
fi
|
|
done
|
|
|
|
_notrun "not suitable for this filesystem type: $FSTYP"
|
|
}
|
|
|
|
|
|
# tests whether $FSTYP is one of the supported OSes for a test
|
|
#
|
|
_supported_os()
|
|
{
|
|
for h
|
|
do
|
|
if [ "$h" = "$HOSTOS" ]
|
|
then
|
|
return
|
|
fi
|
|
done
|
|
|
|
_notrun "not suitable for this OS: $HOSTOS"
|
|
}
|
|
|
|
# this test needs a scratch partition - check we're ok & unmount it
|
|
#
|
|
_require_scratch()
|
|
{
|
|
case "$FSTYP" in
|
|
nfs*)
|
|
_notrun "requires a scratch device"
|
|
;;
|
|
tmpfs)
|
|
if [ -z "$SCRATCH_DEV" -o ! -d "$SCRATCH_MNT" ];
|
|
then
|
|
_notrun "this test requires a valid \$SCRATCH_MNT and unique $SCRATCH_DEV"
|
|
fi
|
|
;;
|
|
*)
|
|
if [ -z "$SCRATCH_DEV" -o "`_is_block_dev $SCRATCH_DEV`" = "" ]
|
|
then
|
|
_notrun "this test requires a valid \$SCRATCH_DEV"
|
|
fi
|
|
if [ "`_is_block_dev $SCRATCH_DEV`" = "`_is_block_dev $TEST_DEV`" ]
|
|
then
|
|
_notrun "this test requires a valid \$SCRATCH_DEV"
|
|
fi
|
|
if [ ! -d "$SCRATCH_MNT" ]
|
|
then
|
|
_notrun "this test requires a valid \$SCRATCH_MNT"
|
|
fi
|
|
;;
|
|
esac
|
|
|
|
# mounted?
|
|
if _mount | grep -q $SCRATCH_DEV
|
|
then
|
|
# if it's mounted, make sure its on $SCRATCH_MNT
|
|
if ! _mount | grep $SCRATCH_DEV | grep -q $SCRATCH_MNT
|
|
then
|
|
echo "\$SCRATCH_DEV is mounted but not on \$SCRATCH_MNT - aborting"
|
|
exit 1
|
|
fi
|
|
# and then unmount it
|
|
if ! $UMOUNT_PROG $SCRATCH_DEV
|
|
then
|
|
echo "failed to unmount $SCRATCH_DEV"
|
|
exit 1
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# this test needs a logdev
|
|
#
|
|
_require_logdev()
|
|
{
|
|
[ -z "$SCRATCH_LOGDEV" -o ! -b "$SCRATCH_LOGDEV" ] && \
|
|
_notrun "This test requires a valid \$SCRATCH_LOGDEV"
|
|
[ "$USE_EXTERNAL" != yes ] && \
|
|
_notrun "This test requires USE_EXTERNAL to be enabled"
|
|
|
|
# ensure its not mounted
|
|
$UMOUNT_PROG $SCRATCH_LOGDEV 2>/dev/null
|
|
}
|
|
|
|
# this test requires loopback device support
|
|
#
|
|
_require_loop()
|
|
{
|
|
if [ "$HOSTOS" != "Linux" ]
|
|
then
|
|
_notrun "This test requires linux for loopback device support"
|
|
fi
|
|
|
|
modprobe loop >/dev/null 2>&1
|
|
if grep loop /proc/devices >/dev/null 2>&1
|
|
then
|
|
:
|
|
else
|
|
_notrun "This test requires loopback device support"
|
|
fi
|
|
}
|
|
|
|
# this test requires ext2 filesystem support
|
|
#
|
|
_require_ext2()
|
|
{
|
|
if [ "$HOSTOS" != "Linux" ]
|
|
then
|
|
_notrun "This test requires linux for ext2 filesystem support"
|
|
fi
|
|
|
|
modprobe ext2 >/dev/null 2>&1
|
|
if grep ext2 /proc/filesystems >/dev/null 2>&1
|
|
then
|
|
:
|
|
else
|
|
_notrun "This test requires ext2 filesystem support"
|
|
fi
|
|
}
|
|
|
|
# this test requires that (large) loopback device files are not in use
|
|
#
|
|
_require_no_large_scratch_dev()
|
|
{
|
|
[ "$LARGE_SCRATCH_DEV" = yes ] && \
|
|
_notrun "Large filesystem testing in progress, skipped this test"
|
|
}
|
|
|
|
# this test requires that a realtime subvolume is in use, and
|
|
# that the kernel supports realtime as well.
|
|
#
|
|
_require_realtime()
|
|
{
|
|
[ "$USE_EXTERNAL" = yes ] || \
|
|
_notrun "External volumes not in use, skipped this test"
|
|
[ "$SCRATCH_RTDEV" = "" ] && \
|
|
_notrun "Realtime device required, skipped this test"
|
|
}
|
|
|
|
# this test requires that a specified command (executable) exists
|
|
# $1 - command, $2 - name for error message
|
|
#
|
|
_require_command()
|
|
{
|
|
[ -n "$1" ] && _cmd="$1" || _cmd="$2"
|
|
[ -n "$1" -a -x "$1" ] || _notrun "$_cmd utility required, skipped this test"
|
|
}
|
|
|
|
# this test requires the device mapper flakey target
|
|
#
|
|
_require_dm_flakey()
|
|
{
|
|
_require_command $DMSETUP_PROG
|
|
|
|
modprobe dm-flakey >/dev/null 2>&1
|
|
$DMSETUP_PROG targets | grep flakey >/dev/null 2>&1
|
|
if [ $? -eq 0 ]
|
|
then
|
|
:
|
|
else
|
|
_notrun "This test requires dm flakey support"
|
|
fi
|
|
}
|
|
|
|
# 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
|
|
_scratch_mount >/dev/null 2>&1 \
|
|
|| _notrun "Kernel doesn't support crc feature"
|
|
umount $SCRATCH_MNT
|
|
}
|
|
|
|
# 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
|
|
_scratch_mount >/dev/null 2>&1 \
|
|
|| _notrun "Kernel doesn't support finobt feature"
|
|
umount $SCRATCH_MNT
|
|
}
|
|
|
|
# this test requires xfs sysfs attribute support
|
|
#
|
|
_require_xfs_sysfs()
|
|
{
|
|
attr=$1
|
|
sysfsdir=/sys/fs/xfs
|
|
testdev=`_short_dev $TEST_DEV`
|
|
|
|
if [ ! -e $sysfsdir ]; then
|
|
_notrun "no kernel support for XFS sysfs attributes"
|
|
fi
|
|
|
|
if [ ! -z $1 ] && [ ! -e $sysfsdir/$testdev/$attr ]; then
|
|
_notrun "sysfs attribute '$attr' is not supported"
|
|
fi
|
|
}
|
|
|
|
# this test requires that external log/realtime devices are not in use
|
|
#
|
|
_require_nonexternal()
|
|
{
|
|
[ "$USE_EXTERNAL" = yes ] && \
|
|
_notrun "External device testing in progress, skipped this test"
|
|
}
|
|
|
|
# this test requires that a (specified) aio-dio executable exists
|
|
# $1 - command (optional)
|
|
#
|
|
_require_aiodio()
|
|
{
|
|
if [ -z "$1" ]
|
|
then
|
|
AIO_TEST=src/aio-dio-regress/aiodio_sparse2
|
|
[ -x $AIO_TEST ] || _notrun "aio-dio utilities required"
|
|
else
|
|
AIO_TEST=src/aio-dio-regress/$1
|
|
[ -x $AIO_TEST ] || _notrun "$AIO_TEST not built"
|
|
fi
|
|
}
|
|
|
|
# run an aio-dio program
|
|
# $1 - command
|
|
_run_aiodio()
|
|
{
|
|
if [ -z "$1" ]
|
|
then
|
|
echo "usage: _run_aiodio command_name" 2>&1
|
|
status=1; exit 1
|
|
fi
|
|
|
|
_require_aiodio $1
|
|
|
|
local testtemp=$TEST_DIR/aio-testfile
|
|
rm -f $testtemp
|
|
$AIO_TEST $testtemp 2>&1
|
|
status=$?
|
|
rm -f $testtemp
|
|
|
|
return $status
|
|
}
|
|
|
|
# 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_passwd | grep -q $qa_user
|
|
[ "$?" == "0" ] || _notrun "$qa_user user not defined."
|
|
echo /bin/true | su $qa_user
|
|
[ "$?" == "0" ] || _notrun "$qa_user cannot execute commands."
|
|
}
|
|
|
|
# check for the fsgqa group on the machine
|
|
#
|
|
_require_group()
|
|
{
|
|
qa_group=fsgqa
|
|
_cat_group | grep -q $qa_group
|
|
[ "$?" == "0" ] || _notrun "$qa_group user not defined."
|
|
}
|
|
|
|
_filter_user_do()
|
|
{
|
|
perl -ne "
|
|
s,.*Permission\sdenied.*,Permission denied,;
|
|
s,.*no\saccess\sto\stty.*,,;
|
|
s,.*no\sjob\scontrol\sin\sthis\sshell.*,,;
|
|
s,^\s*$,,;
|
|
print;"
|
|
}
|
|
|
|
_user_do()
|
|
{
|
|
if [ "$HOSTOS" == "IRIX" ]
|
|
then
|
|
echo $1 | /bin/bash "su $qa_user 2>&1" | _filter_user_do
|
|
else
|
|
echo $1 | su $qa_user 2>&1 | _filter_user_do
|
|
fi
|
|
}
|
|
|
|
_require_xfs_io_command()
|
|
{
|
|
if [ $# -ne 1 ]
|
|
then
|
|
echo "Usage: _require_xfs_io_command command" 1>&2
|
|
exit 1
|
|
fi
|
|
command=$1
|
|
|
|
testfile=$TEST_DIR/$$.xfs_io
|
|
case $command in
|
|
"falloc" )
|
|
testio=`$XFS_IO_PROG -F -f -c "falloc 0 1m" $testfile 2>&1`
|
|
;;
|
|
"fpunch" | "fcollapse" | "zero" | "fzero" )
|
|
testio=`$XFS_IO_PROG -F -f -c "pwrite 0 20k" -c "fsync" \
|
|
-c "$command 4k 8k" $testfile 2>&1`
|
|
;;
|
|
"fiemap")
|
|
testio=`$XFS_IO_PROG -F -f -c "pwrite 0 20k" -c "fsync" \
|
|
-c "fiemap -v" $testfile 2>&1`
|
|
;;
|
|
"flink" )
|
|
testio=`$XFS_IO_PROG -T -F -c "flink $testfile" \
|
|
$TEST_DIR 2>&1`
|
|
echo $testio | egrep -q "invalid option|Is a directory" && \
|
|
_notrun "xfs_io $command support is missing"
|
|
;;
|
|
*)
|
|
testio=`$XFS_IO_PROG -c "$command help" 2>&1`
|
|
esac
|
|
|
|
rm -f $testfile 2>&1 > /dev/null
|
|
echo $testio | grep -q "not found" && \
|
|
_notrun "xfs_io $command support is missing"
|
|
echo $testio | grep -q "Operation not supported" && \
|
|
_notrun "xfs_io $command failed (old kernel/wrong fs?)"
|
|
}
|
|
|
|
# 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
|
|
}
|
|
|
|
_require_debugfs()
|
|
{
|
|
#boot_params always present in debugfs
|
|
[ -d "$DEBUGFS_MNT/boot_params" ] || _notrun "Debugfs not mounted"
|
|
}
|
|
|
|
_require_fail_make_request()
|
|
{
|
|
[ -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"
|
|
}
|
|
|
|
#
|
|
# Check if the file system supports seek_data/hole
|
|
#
|
|
_require_seek_data_hole()
|
|
{
|
|
testfile=$TEST_DIR/$$.seek
|
|
testseek=`$here/src/seek_sanity_test -t $testfile 2>&1`
|
|
rm -f $testfile &>/dev/null
|
|
echo $testseek | grep -q "Kernel does not support" && \
|
|
_notrun "File system does not support llseek(2) SEEK_DATA/HOLE"
|
|
}
|
|
|
|
# check that a FS on a device is mounted
|
|
# if so, return mount point
|
|
#
|
|
_is_mounted()
|
|
{
|
|
if [ $# -ne 1 ]
|
|
then
|
|
echo "Usage: _is_mounted device" 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
device=$1
|
|
|
|
if _mount | grep "$device " | $AWK_PROG -v pattern="type $FSTYP" '
|
|
pattern { print $3 ; exit 0 }
|
|
END { exit 1 }
|
|
'
|
|
then
|
|
echo "_is_mounted: $device is not a mounted $FSTYP FS"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# remount a FS to a new mode (ro or rw)
|
|
#
|
|
_remount()
|
|
{
|
|
if [ $# -ne 2 ]
|
|
then
|
|
echo "Usage: _remount device ro/rw" 1>&2
|
|
exit 1
|
|
fi
|
|
device=$1
|
|
mode=$2
|
|
|
|
if ! mount -o remount,$mode $device
|
|
then
|
|
echo "_remount: failed to remount filesystem on $device as $mode"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# 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 $seqres.full)"
|
|
|
|
echo "_check_generic filesystem: filesystem on $device is inconsistent" >>$seqres.full
|
|
echo "*** fsck.$FSTYP output ***" >>$seqres.full
|
|
cat $tmp.fsck >>$seqres.full
|
|
echo "*** end fsck.$FSTYP output" >>$seqres.full
|
|
|
|
ok=0
|
|
fi
|
|
rm -f $tmp.fsck
|
|
|
|
if [ $ok -eq 0 ]
|
|
then
|
|
echo "*** mount output ***" >>$seqres.full
|
|
_mount >>$seqres.full
|
|
echo "*** end mount output" >>$seqres.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 ]
|
|
then
|
|
echo "Usage: _check_xfs_filesystem device <logdev>|none <rtdev>|none" 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
extra_mount_options=""
|
|
device=$1
|
|
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
|
|
|
|
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
|
|
echo "_check_xfs_filesystem: filesystem on $device has dirty log (see $seqres.full)"
|
|
|
|
echo "_check_xfs_filesystem: filesystem on $device has dirty log" >>$seqres.full
|
|
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
|
|
echo "_check_xfs_filesystem: filesystem on $device is inconsistent (c) (see $seqres.full)"
|
|
|
|
echo "_check_xfs_filesystem: filesystem on $device is inconsistent" >>$seqres.full
|
|
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_log_options $extra_rt_options $device >$tmp.repair 2>&1
|
|
if [ $? -ne 0 ]
|
|
then
|
|
echo "_check_xfs_filesystem: filesystem on $device is inconsistent (r) (see $seqres.full)"
|
|
|
|
echo "_check_xfs_filesystem: filesystem on $device is inconsistent" >>$seqres.full
|
|
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
|
|
|
|
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
|
|
exit 1
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
# Filter the knowen errors the UDF Verifier reports.
|
|
_udf_test_known_error_filter()
|
|
{
|
|
egrep -v "PVD 60 Error: Interchange Level: 1, Maximum Interchange Level: 0|FSD 28 Error: Interchange Level: 1, Maximum Interchange Level: 1,|PVD 72 Warning: Volume Set Identifier: \"\*IRIX UDF\",|Warning: [0-9]+ unused blocks NOT marked as unallocated."
|
|
|
|
}
|
|
|
|
_check_udf_filesystem()
|
|
{
|
|
[ "$DISABLE_UDF_TEST" == "1" ] && return
|
|
|
|
if [ $# -ne 1 -a $# -ne 2 ]
|
|
then
|
|
echo "Usage: _check_udf_filesystem device [last_block]" 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
if [ ! -x $here/src/udf_test ]
|
|
then
|
|
echo "udf_test not installed, please download and build the Philips"
|
|
echo "UDF Verification Software from http://www.extra.research.philips.com/udf/."
|
|
echo "Then copy the udf_test binary to $here/src/."
|
|
echo "If you do not wish to run udf_test then set environment variable DISABLE_UDF_TEST"
|
|
echo "to 1."
|
|
return
|
|
fi
|
|
|
|
device=$1
|
|
if [ $# -eq 2 ];
|
|
then
|
|
LAST_BLOCK=`expr \( $2 - 1 \)`
|
|
OPT_ARG="-lastvalidblock $LAST_BLOCK"
|
|
fi
|
|
|
|
rm -f $seqres.checkfs
|
|
sleep 1 # Due to a problem with time stamps in udf_test
|
|
$here/src/udf_test $OPT_ARG $device | tee $seqres.checkfs | egrep "Error|Warning" | \
|
|
_udf_test_known_error_filter | \
|
|
egrep -iv "Error count:.*[0-9]+.*total occurrences:.*[0-9]+|Warning count:.*[0-9]+.*total occurrences:.*[0-9]+" && \
|
|
echo "Warning UDF Verifier reported errors see $seqres.checkfs."
|
|
}
|
|
|
|
_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
|
|
|
|
# check for ipath consistency
|
|
if $XFS_GROWFS_PROG -n $TEST_DIR | grep -q 'inode-paths=1'; then
|
|
# errors go to stderr
|
|
xfs_check_ipaths $TEST_DIR >/dev/null
|
|
xfs_repair_ipaths -n $TEST_DIR >/dev/null
|
|
fi
|
|
}
|
|
|
|
_check_btrfs_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
|
|
|
|
btrfsck $device >$tmp.fsck 2>&1
|
|
if [ $? -ne 0 ]
|
|
then
|
|
echo "_check_btrfs_filesystem: filesystem on $device is inconsistent (see $seqres.full)"
|
|
|
|
echo "_check_btrfs_filesystem: filesystem on $device is inconsistent" >>$seqres.full
|
|
echo "*** fsck.$FSTYP output ***" >>$seqres.full
|
|
cat $tmp.fsck >>$seqres.full
|
|
echo "*** end fsck.$FSTYP output" >>$seqres.full
|
|
|
|
ok=0
|
|
fi
|
|
rm -f $tmp.fsck
|
|
|
|
if [ $ok -eq 0 ]
|
|
then
|
|
echo "*** mount output ***" >>$seqres.full
|
|
_mount >>$seqres.full
|
|
echo "*** end mount output" >>$seqres.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
|
|
}
|
|
|
|
_check_test_fs()
|
|
{
|
|
case $FSTYP in
|
|
xfs)
|
|
_check_xfs_test_fs
|
|
;;
|
|
nfs)
|
|
# no way to check consistency for nfs
|
|
;;
|
|
udf)
|
|
# do nothing for now
|
|
;;
|
|
btrfs)
|
|
_check_btrfs_filesystem $TEST_DEV
|
|
;;
|
|
tmpfs)
|
|
# no way to check consistency for tmpfs
|
|
;;
|
|
*)
|
|
_check_generic_filesystem $TEST_DEV
|
|
;;
|
|
esac
|
|
}
|
|
|
|
_check_scratch_fs()
|
|
{
|
|
device=$SCRATCH_DEV
|
|
[ $# -eq 1 ] && device=$1
|
|
|
|
case $FSTYP in
|
|
xfs)
|
|
SCRATCH_LOG="none"
|
|
SCRATCH_RT="none"
|
|
[ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_LOGDEV" ] && \
|
|
SCRATCH_LOG="$SCRATCH_LOGDEV"
|
|
|
|
[ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_RTDEV" ] && \
|
|
SCRATCH_RT="$SCRATCH_RTDEV"
|
|
|
|
_check_xfs_filesystem $device $SCRATCH_LOG $SCRATCH_RT
|
|
;;
|
|
udf)
|
|
_check_udf_filesystem $device $udf_fsize
|
|
;;
|
|
nfs*)
|
|
# Don't know how to check an NFS filesystem, yet.
|
|
;;
|
|
btrfs)
|
|
_check_btrfs_filesystem $device
|
|
;;
|
|
tmpfs)
|
|
# no way to check consistency for tmpfs
|
|
;;
|
|
*)
|
|
_check_generic_filesystem $device
|
|
;;
|
|
esac
|
|
}
|
|
|
|
_full_fstyp_details()
|
|
{
|
|
[ -z "$FSTYP" ] && FSTYP=xfs
|
|
if [ $FSTYP = xfs ]; then
|
|
if [ -d /proc/fs/xfs ]; then
|
|
if grep -q 'debug 0' /proc/fs/xfs/stat; then
|
|
FSTYP="$FSTYP (non-debug)"
|
|
elif grep -q 'debug 1' /proc/fs/xfs/stat; then
|
|
FSTYP="$FSTYP (debug)"
|
|
fi
|
|
else
|
|
if uname -a | grep -qi 'debug'; then
|
|
FSTYP="$FSTYP (debug)"
|
|
else
|
|
FSTYP="$FSTYP (non-debug)"
|
|
fi
|
|
fi
|
|
fi
|
|
echo $FSTYP
|
|
}
|
|
|
|
_full_platform_details()
|
|
{
|
|
os=`uname -s`
|
|
host=`hostname -s`
|
|
kernel=`uname -r`
|
|
platform=`uname -m`
|
|
echo "$os/$platform $host $kernel"
|
|
}
|
|
|
|
_link_out_file()
|
|
{
|
|
if [ -z "$1" -o -z "$2" ]; then
|
|
echo Error must pass src and dst.
|
|
exit
|
|
fi
|
|
rm -f $2
|
|
if [ "`uname`" == "IRIX64" ] || [ "`uname`" == "IRIX" ]; then
|
|
ln -s $1.irix $2
|
|
elif [ "`uname`" == "Linux" ]; then
|
|
ln -s $1.linux $2
|
|
else
|
|
echo Error test $seq does not run on the operating system: `uname`
|
|
exit
|
|
fi
|
|
}
|
|
|
|
_die()
|
|
{
|
|
echo $@
|
|
exit 1
|
|
}
|
|
|
|
#takes files, randomdata
|
|
_nfiles()
|
|
{
|
|
f=0
|
|
while [ $f -lt $1 ]
|
|
do
|
|
file=f$f
|
|
echo > $file
|
|
if [ $size -gt 0 ]; then
|
|
if [ "$2" == "false" ]; then
|
|
dd if=/dev/zero of=$file bs=1024 count=$size 2>&1 | _filter_dd
|
|
else
|
|
dd if=/dev/urandom of=$file bs=1024 count=$size 2>&1 | _filter_dd
|
|
fi
|
|
fi
|
|
let f=$f+1
|
|
done
|
|
}
|
|
|
|
# takes dirname, depth, randomdata
|
|
_descend()
|
|
{
|
|
dirname=$1; depth=$2; randomdata=$3
|
|
mkdir $dirname || die "mkdir $dirname failed"
|
|
cd $dirname
|
|
|
|
_nfiles $files $randomdata # files for this dir and data type
|
|
|
|
[ $depth -eq 0 ] && return
|
|
let deep=$depth-1 # go 1 down
|
|
|
|
[ $verbose = true ] && echo "descending, depth from leaves = $deep"
|
|
|
|
d=0
|
|
while [ $d -lt $dirs ]
|
|
do
|
|
_descend d$d $deep &
|
|
let d=$d+1
|
|
wait
|
|
done
|
|
}
|
|
|
|
# Populate a filesystem with inodes for performance experiments
|
|
#
|
|
# usage: populate [-v] [-n ndirs] [-f nfiles] [-d depth] [-r root] [-s size] [-x]
|
|
#
|
|
_populate_fs()
|
|
{
|
|
here=`pwd`
|
|
dirs=5 # ndirs in each subdir till leaves
|
|
size=0 # sizeof files in K
|
|
files=100 # num files in _each_ subdir
|
|
depth=2 # depth of tree from root to leaves
|
|
verbose=false
|
|
root=root # path of initial root of directory tree
|
|
randomdata=false # -x data type urandom or zero
|
|
|
|
OPTIND=1
|
|
while getopts "d:f:n:r:s:v:x" c
|
|
do
|
|
case $c in
|
|
d) depth=$OPTARG;;
|
|
n) dirs=$OPTARG;;
|
|
f) files=$OPTARG;;
|
|
s) size=$OPTARG;;
|
|
v) verbose=true;;
|
|
r) root=$OPTARG;;
|
|
x) randomdata=true;;
|
|
esac
|
|
done
|
|
|
|
_descend $root $depth $randomdata
|
|
wait
|
|
|
|
cd $here
|
|
|
|
[ $verbose = true ] && echo done
|
|
}
|
|
|
|
# query whether the given file has the given inode flag set
|
|
#
|
|
_test_inode_flag()
|
|
{
|
|
flag=$1
|
|
file=$2
|
|
|
|
if which $XFS_IO_PROG >/dev/null; then
|
|
if $XFS_IO_PROG -r -c 'lsattr -v' "$file" | grep -q "$flag" ; then
|
|
return 0
|
|
fi
|
|
fi
|
|
return 1
|
|
}
|
|
|
|
# query the given files extsize allocator hint in bytes (if any)
|
|
#
|
|
_test_inode_extsz()
|
|
{
|
|
file=$1
|
|
blocks=""
|
|
|
|
if which $XFS_IO_PROG >/dev/null; then
|
|
blocks=`$XFS_IO_PROG -r -c 'stat' "$file" | \
|
|
awk '/^xattr.extsize =/ { print $3 }'`
|
|
fi
|
|
[ -z "$blocks" ] && blocks="0"
|
|
echo $blocks
|
|
}
|
|
|
|
# scratch_dev_pool should contain the disks pool for the btrfs raid
|
|
_require_scratch_dev_pool()
|
|
{
|
|
local i
|
|
local ndevs
|
|
|
|
if [ -z "$SCRATCH_DEV_POOL" ]; then
|
|
_notrun "this test requires a valid \$SCRATCH_DEV_POOL"
|
|
fi
|
|
|
|
if [ -z "$1" ]; then
|
|
ndevs=2
|
|
else
|
|
ndevs=$1
|
|
fi
|
|
|
|
# btrfs test case needs ndevs or more scratch_dev_pool; other FS not sure
|
|
# so fail it
|
|
case $FSTYP in
|
|
btrfs)
|
|
if [ "`echo $SCRATCH_DEV_POOL|wc -w`" -lt $ndevs ]; then
|
|
_notrun "btrfs and this test needs $ndevs or more disks in SCRATCH_DEV_POOL"
|
|
fi
|
|
;;
|
|
*)
|
|
_notrun "dev_pool is not supported by fstype \"$FSTYP\""
|
|
;;
|
|
esac
|
|
|
|
for i in $SCRATCH_DEV_POOL; do
|
|
if [ "`_is_block_dev $i`" = "" ]; then
|
|
_notrun "this test requires valid block disk $i"
|
|
fi
|
|
if [ "`_is_block_dev $i`" = "`_is_block_dev $TEST_DEV`" ]; then
|
|
_notrun "$i is part of TEST_DEV, this test requires unique disks"
|
|
fi
|
|
if _mount | grep -q $i; then
|
|
if ! $UMOUNT_PROG $i; then
|
|
echo "failed to unmount $i - aborting"
|
|
exit 1
|
|
fi
|
|
fi
|
|
# to help better debug when something fails, we remove
|
|
# traces of previous btrfs FS on the dev.
|
|
dd if=/dev/zero of=$i bs=4096 count=100 > /dev/null 2>&1
|
|
done
|
|
}
|
|
|
|
# We will check if the device is deletable
|
|
_require_deletable_scratch_dev_pool()
|
|
{
|
|
local i
|
|
local x
|
|
for i in $SCRATCH_DEV_POOL; do
|
|
x=`echo $i | cut -d"/" -f 3`
|
|
if [ ! -f /sys/class/block/${x}/device/delete ]; then
|
|
_notrun "$i is a device which is not deletable"
|
|
fi
|
|
done
|
|
}
|
|
|
|
# We check for btrfs and (optionally) features of the btrfs command
|
|
_require_btrfs()
|
|
{
|
|
cmd=$1
|
|
_require_command $BTRFS_UTIL_PROG btrfs
|
|
if [ -z "$1" ]; then
|
|
return 1;
|
|
fi
|
|
$BTRFS_UTIL_PROG $cmd --help >/dev/null 2>&1
|
|
[ $? -eq 0 ] || _notrun "$BTRFS_UTIL_PROG too old (must support $cmd)"
|
|
}
|
|
|
|
# Check that fio is present, and it is able to execute given jobfile
|
|
_require_fio()
|
|
{
|
|
job=$1
|
|
|
|
_require_command $FIO_PROG
|
|
if [ -z "$1" ]; then
|
|
return 1;
|
|
fi
|
|
|
|
$FIO_PROG --warnings-fatal --showcmd $job >> $seqres.full 2>&1
|
|
[ $? -eq 0 ] || _notrun "$FIO_PROG too old, see $seqres.full"
|
|
}
|
|
|
|
# Does freeze work on this fs?
|
|
_require_freeze()
|
|
{
|
|
xfs_freeze -f "$TEST_DIR" >/dev/null 2>&1
|
|
result=$?
|
|
xfs_freeze -u "$TEST_DIR" >/dev/null 2>&1
|
|
[ $result -eq 0 ] || _notrun "$FSTYP does not support freezing"
|
|
}
|
|
|
|
# arg 1 is dev to remove and is output of the below eg.
|
|
# ls -l /sys/class/block/sdd | rev | cut -d "/" -f 3 | rev
|
|
_devmgt_remove()
|
|
{
|
|
local lun=$1
|
|
local disk=$2
|
|
|
|
echo 1 > /sys/class/scsi_device/${lun}/device/delete || _fail "Remove disk failed"
|
|
|
|
stat $disk > /dev/null 2>&1
|
|
while [ $? -eq 0 ]; do
|
|
sleep 1
|
|
stat $disk > /dev/null 2>&1
|
|
done
|
|
}
|
|
|
|
# arg 1 is dev to add and is output of the below eg.
|
|
# ls -l /sys/class/block/sdd | rev | cut -d "/" -f 3 | rev
|
|
_devmgt_add()
|
|
{
|
|
local h
|
|
local tdl
|
|
# arg 1 will be in h:t:d:l format now in the h and "t d l" format
|
|
h=`echo ${1} | cut -d":" -f 1`
|
|
tdl=`echo ${1} | cut -d":" -f 2-|sed 's/:/ /g'`
|
|
|
|
echo ${tdl} > /sys/class/scsi_host/host${h}/scan || _fail "Add disk failed"
|
|
}
|
|
|
|
_require_fstrim()
|
|
{
|
|
if [ -z "$FSTRIM_PROG" ]; then
|
|
_notrun "This test requires fstrim utility."
|
|
fi
|
|
}
|
|
|
|
_test_batched_discard()
|
|
{
|
|
if [ $# -ne 1 ]; then
|
|
echo "Usage: _test_batched_discard mnt_point" 1>&2
|
|
exit 1
|
|
fi
|
|
_require_fstrim
|
|
$FSTRIM_PROG ${1} &>/dev/null
|
|
}
|
|
|
|
_require_dumpe2fs()
|
|
{
|
|
if [ -z "$DUMPE2FS_PROG" ]; then
|
|
_notrun "This test requires dumpe2fs utility."
|
|
fi
|
|
}
|
|
|
|
_require_ugid_map()
|
|
{
|
|
if [ ! -e /proc/self/uid_map ]; then
|
|
_notrun "This test requires procfs uid_map support."
|
|
fi
|
|
if [ ! -e /proc/self/gid_map ]; then
|
|
_notrun "This test requires procfs gid_map support."
|
|
fi
|
|
}
|
|
|
|
_require_cp_reflink()
|
|
{
|
|
cp --help | grep -q reflink || \
|
|
_notrun "This test requires a cp with --reflink support."
|
|
}
|
|
|
|
_require_fssum()
|
|
{
|
|
FSSUM_PROG=$here/src/fssum
|
|
[ -x $FSSUM_PROG ] || _notrun "fssum not built"
|
|
}
|
|
|
|
_require_btrfs_cloner()
|
|
{
|
|
CLONER_PROG=$here/src/cloner
|
|
[ -x $CLONER_PROG ] || \
|
|
_notrun "cloner binary not present at $CLONER_PROG"
|
|
}
|
|
|
|
# Given 2 files, verify that they have the same mapping but different
|
|
# inodes - i.e. an undisturbed reflink
|
|
# Silent if so, make noise if not
|
|
_verify_reflink()
|
|
{
|
|
# not a hard link or symlink?
|
|
cmp -s <(stat -c '%i' $1) <(stat -c '%i' $2) \
|
|
&& echo "$1 and $2 are not reflinks: same inode number"
|
|
|
|
# same mapping?
|
|
diff -u <($XFS_IO_PROG -c "fiemap" $1 | grep -v $1) \
|
|
<($XFS_IO_PROG -c "fiemap" $2 | grep -v $2) \
|
|
|| echo "$1 and $2 are not reflinks: different extents"
|
|
}
|
|
|
|
_require_relatime()
|
|
{
|
|
_scratch_mkfs > /dev/null 2>&1
|
|
_mount -t $FSTYP -o relatime $SCRATCH_DEV $SCRATCH_MNT || \
|
|
_notrun "relatime not supported by the current kernel"
|
|
_scratch_unmount
|
|
}
|
|
|
|
_create_loop_device()
|
|
{
|
|
file=$1
|
|
dev=`losetup -f --show $file` || _fail "Cannot assign $file to a loop device"
|
|
echo $dev
|
|
}
|
|
|
|
_destroy_loop_device()
|
|
{
|
|
dev=$1
|
|
losetup -d $dev || _fail "Cannot destroy loop device $dev"
|
|
}
|
|
|
|
_scale_fsstress_args()
|
|
{
|
|
args=""
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
-n) args="$args $1 $(($2 * $TIME_FACTOR))"; shift ;;
|
|
-p) args="$args $1 $(($2 * $LOAD_FACTOR))"; shift ;;
|
|
*) args="$args $1" ;;
|
|
esac
|
|
shift
|
|
done
|
|
echo $args
|
|
}
|
|
|
|
#
|
|
# Return the logical block size if running on a block device,
|
|
# else substitute the page size.
|
|
#
|
|
_min_dio_alignment()
|
|
{
|
|
dev=$1
|
|
|
|
if [ -b "$dev" ]; then
|
|
blockdev --getss $dev
|
|
else
|
|
$here/src/feature -s
|
|
fi
|
|
}
|
|
|
|
run_check()
|
|
{
|
|
echo "# $@" >> $seqres.full 2>&1
|
|
"$@" >> $seqres.full 2>&1 || _fail "failed: '$@'"
|
|
}
|
|
|
|
_run_btrfs_util_prog()
|
|
{
|
|
run_check $BTRFS_UTIL_PROG $*
|
|
}
|
|
|
|
_require_btrfs_send_stream_version()
|
|
{
|
|
$BTRFS_UTIL_PROG send 2>&1 | \
|
|
grep '^[ \t]*\-\-stream\-version <version>' > /dev/null 2>&1
|
|
if [ $? -ne 0 ]; then
|
|
_notrun "Missing btrfs-progs send --stream-version command line option, skipped this test"
|
|
fi
|
|
}
|
|
|
|
_require_btrfs_mkfs_feature()
|
|
{
|
|
if [ -z $1 ]; then
|
|
echo "Missing feature name argument for _require_btrfs_mkfs_feature"
|
|
exit 1
|
|
fi
|
|
feat=$1
|
|
$MKFS_BTRFS_PROG -O list-all 2>&1 | \
|
|
grep '^[ \t]*'"$feat"'\b' > /dev/null 2>&1
|
|
[ $? -eq 0 ] || \
|
|
_notrun "Feature $feat not supported in the available version of mkfs.btrfs"
|
|
}
|
|
|
|
_require_btrfs_fs_feature()
|
|
{
|
|
if [ -z $1 ]; then
|
|
echo "Missing feature name argument for _require_btrfs_fs_feature"
|
|
exit 1
|
|
fi
|
|
feat=$1
|
|
modprobe btrfs > /dev/null 2>&1
|
|
[ -e /sys/fs/btrfs/features/$feat ] || \
|
|
_notrun "Feature $feat not supported by the available btrfs version"
|
|
}
|
|
|
|
init_rc()
|
|
{
|
|
if [ "$iam" == new ]
|
|
then
|
|
return
|
|
fi
|
|
# make some further configuration checks here
|
|
if [ "$TEST_DEV" = "" ]
|
|
then
|
|
echo "common/rc: Error: \$TEST_DEV is not set"
|
|
exit 1
|
|
fi
|
|
|
|
# if $TEST_DEV is not mounted, mount it now as XFS
|
|
if [ -z "`_fs_type $TEST_DEV`" ]
|
|
then
|
|
# $TEST_DEV is not mounted
|
|
if ! _test_mount
|
|
then
|
|
echo "common/rc: retrying test device mount with external set"
|
|
[ "$USE_EXTERNAL" != "yes" ] && export USE_EXTERNAL=yes
|
|
if ! _test_mount
|
|
then
|
|
echo "common/rc: could not mount $TEST_DEV on $TEST_DIR"
|
|
exit 1
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
if [ "`_fs_type $TEST_DEV`" != "$FSTYP" ]
|
|
then
|
|
echo "common/rc: Error: \$TEST_DEV ($TEST_DEV) is not a MOUNTED $FSTYP filesystem"
|
|
$DF_PROG $TEST_DEV
|
|
exit 1
|
|
fi
|
|
# Figure out if we need to add -F ("foreign", deprecated) option to xfs_io
|
|
xfs_io -c stat $TEST_DIR 2>&1 | grep -q "is not on an XFS filesystem" && \
|
|
export XFS_IO_PROG="$XFS_IO_PROG -F"
|
|
}
|
|
|
|
# get real device path name by following link
|
|
_real_dev()
|
|
{
|
|
local _dev=$1
|
|
if [ -b "$_dev" ] && [ -L "$_dev" ]; then
|
|
_dev=`readlink -f "$_dev"`
|
|
fi
|
|
echo $_dev
|
|
}
|
|
|
|
# basename of a device
|
|
_short_dev()
|
|
{
|
|
echo `basename $(_real_dev $1)`
|
|
}
|
|
|
|
init_rc
|
|
|
|
################################################################################
|
|
# make sure this script returns success
|
|
/bin/true
|