mirror of
https://github.com/linux-apfs/apfstests.git
synced 2026-05-01 15:01:44 -07:00
2ff460998d
Move configuration checks into separate function to allow us to recheck the options without the need to reinclude the whole source file which is ugly. We still run the check on include. Signed-off-by: Lukas Czerner <lczerner@redhat.com> Reviewed-by: Chandra Seetharaman <sekharan@us.ibm.com> Signed-off-by: Rich Johnston <rjohnston@sgi.com>
2187 lines
50 KiB
Plaintext
2187 lines
50 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
|
|
|
|
_ls_l()
|
|
{
|
|
ls -l $* | sed "s/\(^[-rwxdlbcpsStT]*\)\. /\1 /"
|
|
}
|
|
|
|
_mount_opts()
|
|
{
|
|
# SELinux adds extra xattrs which can mess up our expected output.
|
|
# So, mount with a context, and they won't be created
|
|
# nfs_t is a "liberal" context so we can use it.
|
|
if [ -x /usr/sbin/selinuxenabled ] && /usr/sbin/selinuxenabled; then
|
|
SELINUX_MOUNT_OPTIONS="-o context=system_u:object_r:nfs_t:s0"
|
|
export SELINUX_MOUNT_OPTIONS
|
|
fi
|
|
|
|
case $FSTYP in
|
|
xfs)
|
|
export MOUNT_OPTIONS=$XFS_MOUNT_OPTIONS
|
|
;;
|
|
udf)
|
|
export MOUNT_OPTIONS=$UDF_MOUNT_OPTIONS
|
|
;;
|
|
nfs)
|
|
export MOUNT_OPTIONS=$NFS_MOUNT_OPTIONS
|
|
;;
|
|
ext2|ext3|ext4|ext4dev)
|
|
# acls & xattrs aren't turned on by default on ext$FOO
|
|
export MOUNT_OPTIONS="-o acl,user_xattr $EXT_MOUNT_OPTIONS"
|
|
;;
|
|
reiserfs)
|
|
# acls & xattrs aren't turned on by default on reiserfs
|
|
export MOUNT_OPTIONS="-o acl,user_xattr $REISERFS_MOUNT_OPTIONS"
|
|
;;
|
|
gfs2)
|
|
# acls aren't turned on by default on gfs2
|
|
export MOUNT_OPTIONS="-o acl $GFS2_MOUNT_OPTIONS"
|
|
;;
|
|
*)
|
|
;;
|
|
esac
|
|
}
|
|
|
|
_mkfs_opts()
|
|
{
|
|
case $FSTYP in
|
|
xfs)
|
|
export MKFS_OPTIONS=$XFS_MKFS_OPTIONS
|
|
;;
|
|
udf)
|
|
[ ! -z "$udf_fsize" ] && \
|
|
UDF_MKFS_OPTIONS="$UDF_MKFS_OPTIONS -s $udf_fsize"
|
|
export MKFS_OPTIONS=$UDF_MKFS_OPTIONS
|
|
;;
|
|
nfs)
|
|
export MKFS_OPTIONS=$NFS_MKFS_OPTIONS
|
|
;;
|
|
reiserfs)
|
|
export MKFS_OPTIONS="$REISERFS_MKFS_OPTIONS -q"
|
|
;;
|
|
gfs2)
|
|
export MKFS_OPTIONS="$GFS2_MKFS_OPTIONS -O -p lock_nolock"
|
|
;;
|
|
jfs)
|
|
export MKFS_OPTIONS="$JFS_MKFS_OPTIONS -q"
|
|
;;
|
|
*)
|
|
;;
|
|
esac
|
|
}
|
|
|
|
_fsck_opts()
|
|
{
|
|
case $FSTYP in
|
|
ext2|ext3|ext4|ext4dev)
|
|
export FSCK_OPTIONS="-nf"
|
|
;;
|
|
reiserfs)
|
|
export FSCK_OPTIONS="--yes"
|
|
;;
|
|
*)
|
|
export FSCK_OPTIONS="-n"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
[ -z "$FSTYP" ] && FSTYP=xfs
|
|
[ -z "$MOUNT_OPTIONS" ] && _mount_opts
|
|
[ -z "$MKFS_OPTIONS" ] && _mkfs_opts
|
|
[ -z "$FSCK_OPTIONS" ] && _fsck_opts
|
|
|
|
|
|
# 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
|
|
}
|
|
|
|
|
|
_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()
|
|
{
|
|
# extra mkfs options can be added by tests
|
|
local extra_mkfs_options=$*
|
|
|
|
local tmp_dir=/tmp/
|
|
|
|
_scratch_options mkfs
|
|
|
|
# save mkfs output in case conflict means we need to run again.
|
|
# only the output for the mkfs that applies should be shown
|
|
$MKFS_XFS_PROG $SCRATCH_OPTIONS $MKFS_OPTIONS $extra_mkfs_options $SCRATCH_DEV \
|
|
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 "** mkfs failed with extra mkfs options added to \"$MKFS_OPTIONS\" by test $seq **" \
|
|
>>$seqres.full
|
|
echo "** attempting to mkfs using only test $seq options: $extra_mkfs_options **" \
|
|
>>$seqres.full
|
|
# running mkfs again. overwrite previous mkfs output files
|
|
$MKFS_XFS_PROG $SCRATCH_OPTIONS $extra_mkfs_options $SCRATCH_DEV \
|
|
2>$tmp_dir.mkfserr 1>$tmp_dir.mkfsstd
|
|
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
|
|
}
|
|
|
|
_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 $*
|
|
;;
|
|
*)
|
|
yes | $MKFS_PROG -t $FSTYP -- $MKFS_OPTIONS $* $SCRATCH_DEV
|
|
;;
|
|
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
|
|
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)
|
|
_scratch_mkfs_xfs -d size=$fssize -b size=$blocksize
|
|
;;
|
|
ext2|ext3|ext4|ext4dev)
|
|
yes | ${MKFS_PROG}.$FSTYP $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*)
|
|
echo $SCRATCH_DEV | grep -q ":" > /dev/null 2>&1
|
|
if [ -z "$SCRATCH_DEV" -o "$?" != "0" ]
|
|
then
|
|
_notrun "this test requires a valid \$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 -f -i projid32bit=0 2>&1 >/dev/null \
|
|
|| _notrun "mkfs.xfs doesn't have projid32bit feature"
|
|
}
|
|
|
|
# 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
|
|
}
|
|
|
|
# check that xfs_io, kernel, and filesystem all support zero
|
|
_require_xfs_io_zero()
|
|
{
|
|
testio=`$XFS_IO_PROG -c "zero help" 2>&1`
|
|
echo $testio | grep -q 'command "zero" not found' && \
|
|
_notrun "zero command not supported"
|
|
}
|
|
|
|
# check that xfs_io, glibc, kernel, and filesystem all (!) support
|
|
# fallocate
|
|
#
|
|
_require_xfs_io_falloc()
|
|
{
|
|
testfile=$TEST_DIR/$$.falloc
|
|
testio=`$XFS_IO_PROG -F -f -c "falloc 0 1m" $testfile 2>&1`
|
|
rm -f $testfile 2>&1 > /dev/null
|
|
echo $testio | grep -q "not found" && \
|
|
_notrun "xfs_io fallocate support is missing"
|
|
echo $testio | grep -q "Operation not supported" && \
|
|
_notrun "xfs_io fallocate command failed (old kernel/wrong fs?)"
|
|
}
|
|
|
|
# check that xfs_io, kernel and filesystem all support fallocate with hole
|
|
# punching
|
|
_require_xfs_io_falloc_punch()
|
|
{
|
|
testfile=$TEST_DIR/$$.falloc
|
|
testio=`$XFS_IO_PROG -F -f -c "pwrite 0 20k" -c "fsync" \
|
|
-c "fpunch 4k 8k" $testfile 2>&1`
|
|
rm -f $testfile 2>&1 > /dev/null
|
|
echo $testio | grep -q "not found" && \
|
|
_notrun "xfs_io fallocate punch support is missing"
|
|
echo $testio | grep -q "Operation not supported" && \
|
|
_notrun "xfs_io fallocate punch command failed (no fs support?)"
|
|
}
|
|
|
|
# check that xfs_io, kernel and filesystem support fiemap
|
|
_require_xfs_io_fiemap()
|
|
{
|
|
testfile=$TEST_DIR/$$.fiemap
|
|
testio=`$XFS_IO_PROG -F -f -c "pwrite 0 20k" -c "fsync" \
|
|
-c "fiemap -v" $testfile 2>&1`
|
|
rm -f $testfile 2>&1 > /dev/null
|
|
echo $testio | grep -q "not found" && \
|
|
_notrun "xfs_io fiemap support is missing"
|
|
echo $testio | grep -q "Operation not supported" && \
|
|
_notrun "xfs_io fiemap command failed (no fs support?)"
|
|
}
|
|
|
|
# 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]+" | \
|
|
sed "s/^.*$/Warning UDF Verifier reported errors see $seqres.checkfs./g"
|
|
|
|
}
|
|
|
|
_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
|
|
;;
|
|
*)
|
|
_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
|
|
;;
|
|
*)
|
|
_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"
|
|
}
|
|
|
|
_setup_udf_scratchdir()
|
|
{
|
|
[ "$FSTYP" != "udf" ] \
|
|
&& _fail "setup_udf_testdir: \$FSTYP is not udf"
|
|
[ -z "$SCRATCH_DEV" -o ! -b "$SCRATCH_DEV" ] \
|
|
&& _notrun "this test requires a valid \$SCRATCH_DEV"
|
|
[ -z "$SCRATCH_MNT" ] \
|
|
&& _notrun "this test requires a valid \$SCRATCH_MNT"
|
|
|
|
# mounted?
|
|
if _mount | grep -q $SCRATCH_DEV
|
|
then
|
|
# if it's mounted, make sure its on $TEST_RW_DIR
|
|
if ! _mount | grep $SCRATCH_DEV | grep -q $SCRATCH_MNT
|
|
then
|
|
_fail "\$SCRATCH_DEV is mounted but not on \$SCRATCH_MNT - aborting"
|
|
fi
|
|
$UMOUNT_PROG $SCRATCH_DEV
|
|
fi
|
|
|
|
_scratch_mkfs
|
|
_scratch_mount
|
|
|
|
testdir=$SCRATCH_MNT
|
|
}
|
|
|
|
_setup_nfs_scratchdir()
|
|
{
|
|
[ "$FSTYP" != "nfs" ] \
|
|
&& _fail "setup_nfs_testdir: \$FSTYP is not nfs"
|
|
[ -z "$SCRATCH_DEV" ] \
|
|
&& _notrun "this test requires a valid host fs for \$SCRATCH_DEV"
|
|
[ -z "$SCRATCH_MNT" ] \
|
|
&& _notrun "this test requires a valid \$SCRATCH_MNT"
|
|
|
|
# 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
|
|
_fail "\$SCRATCH_DEV is mounted but not on \$SCRATCH_MNT - aborting"
|
|
fi
|
|
$UMOUNT_PROG $SCRATCH_DEV
|
|
fi
|
|
|
|
_scratch_mkfs
|
|
_scratch_mount
|
|
|
|
testdir=$SCRATCH_MNT
|
|
}
|
|
|
|
#
|
|
# Warning for UDF and NFS:
|
|
# this function calls _setup_udf_scratchdir and _setup_udf_scratchdir
|
|
# which actually uses the scratch dir for the test dir.
|
|
#
|
|
# This was done because testdir was intended to be a persistent
|
|
# XFS only partition. This should eventually change, and treat
|
|
# at least local filesystems all the same.
|
|
#
|
|
_setup_testdir()
|
|
{
|
|
case $FSTYP in
|
|
udf)
|
|
_setup_udf_scratchdir
|
|
;;
|
|
nfs*)
|
|
_setup_nfs_scratchdir
|
|
;;
|
|
*)
|
|
testdir=$TEST_DIR
|
|
;;
|
|
esac
|
|
}
|
|
|
|
_cleanup_testdir()
|
|
{
|
|
case $FSTYP in
|
|
udf)
|
|
# umount testdir as it is $SCRATCH_MNT which could be used by xfs next
|
|
[ -n "$testdir" ] && $UMOUNT_PROG $testdir
|
|
;;
|
|
nfs*)
|
|
# umount testdir as it is $SCRATCH_MNT which could be used by xfs next
|
|
[ -n "$testdir" ] && $UMOUNT_PROG $testdir
|
|
;;
|
|
*)
|
|
# do nothing, testdir is $TEST_DIR
|
|
:
|
|
;;
|
|
esac
|
|
}
|
|
|
|
_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
|
|
if [ -z "$SCRATCH_DEV_POOL" ]; then
|
|
_notrun "this test requires a valid \$SCRATCH_DEV_POOL"
|
|
fi
|
|
|
|
# btrfs test case needs 2 or more scratch_dev_pool; other FS not sure
|
|
# so fail it
|
|
case $FSTYP in
|
|
btrfs)
|
|
if [ "`echo $SCRATCH_DEV_POOL|wc -w`" -lt 2 ]; then
|
|
_notrun "btrfs and this test needs 2 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 virtual (eg: loop device) since it does not
|
|
# have the delete entry-point. Otherwise SCSI and USB devices are fine.
|
|
_require_deletable_scratch_dev_pool()
|
|
{
|
|
local i
|
|
local x
|
|
for i in $SCRATCH_DEV_POOL; do
|
|
x=`echo $i | cut -d"/" -f 3`
|
|
ls -l /sys/class/block/${x} | grep -q "virtual"
|
|
if [ $? == "0" ]; then
|
|
_notrun "$i is a virtual 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()
|
|
{
|
|
echo 1 > /sys/class/scsi_device/${1}/device/delete || _fail "Remove disk failed"
|
|
}
|
|
|
|
# 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
|
|
}
|
|
|
|
_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
|
|
}
|
|
|
|
run_check()
|
|
{
|
|
echo "# $@" >> $seqres.full 2>&1
|
|
"$@" >> $seqres.full 2>&1 || _fail "failed: '$@'"
|
|
}
|
|
|
|
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"
|
|
}
|
|
|
|
init_rc
|
|
|
|
################################################################################
|
|
# make sure this script returns success
|
|
/bin/true
|