mirror of
https://github.com/linux-apfs/apfstests.git
synced 2026-05-01 15:01:44 -07:00
9b7f704ca3
Several tests happen to make use of loop device support without the requisite pre-test checks. This results in spurious failures for systems that might not have loop device support. Add _require_loop checks to shared/298, xfs/206 and xfs/259. Signed-off-by: Brian Foster <bfoster@redhat.com> Reviewed-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Dave Chinner <david@fromorbit.com>
192 lines
4.7 KiB
Bash
Executable File
192 lines
4.7 KiB
Bash
Executable File
#! /bin/bash
|
|
# FS QA Test No. 298
|
|
#
|
|
# Test that filesystem sends discard requests only on free blocks
|
|
#
|
|
#-----------------------------------------------------------------------
|
|
# Copyright (c) 2013 Red Hat, Inc., Tomas Racek <tracek@redhat.com>
|
|
#
|
|
# 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.
|
|
#
|
|
# This program is distributed in the hope that it would 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 the Free Software Foundation,
|
|
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
#-----------------------------------------------------------------------
|
|
#
|
|
|
|
seq=`basename $0`
|
|
seqres=$RESULT_DIR/$seq
|
|
echo "QA output created by $seq"
|
|
|
|
status=1 # failure is the default!
|
|
trap "_cleanup; exit \$status" 0 1 2 3 15
|
|
|
|
. ./common/rc
|
|
|
|
_supported_fs ext4 xfs
|
|
_supported_os Linux
|
|
_require_loop
|
|
_require_fstrim
|
|
_require_xfs_io_command "fiemap"
|
|
_require_fs_space $TEST_DIR 307200
|
|
[ "$FSTYP" = "ext4" ] && _require_dumpe2fs
|
|
|
|
_cleanup()
|
|
{
|
|
$UMOUNT_PROG $loop_dev &> /dev/null
|
|
_destroy_loop_device $loop_dev
|
|
if [ $status -eq 0 ]; then
|
|
rm -rf $tmp
|
|
rm $img_file
|
|
fi
|
|
}
|
|
|
|
get_holes()
|
|
{
|
|
$XFS_IO_PROG -F -c fiemap $1 | grep hole | $SED_PROG 's/.*\[\(.*\)\.\.\(.*\)\].*/\1 \2/'
|
|
}
|
|
|
|
get_free_sectors()
|
|
{
|
|
case $FSTYP in
|
|
ext4)
|
|
$DUMPE2FS_PROG $img_file 2>&1 | grep " Free blocks" | cut -d ":" -f2- | \
|
|
tr ',' '\n' | $SED_PROG 's/^ //' | \
|
|
$AWK_PROG -v spb=$sectors_per_block 'BEGIN{FS="-"};
|
|
NF {
|
|
if($2 != "") # range of blocks
|
|
print spb * $1, spb * ($2 + 1) - 1;
|
|
else # just single block
|
|
print spb * $1, spb * ($1 + 1) - 1;
|
|
}'
|
|
;;
|
|
xfs)
|
|
agsize=`xfs_info $loop_mnt | $SED_PROG -n 's/.*agsize=\(.*\) blks.*/\1/p'`
|
|
# Convert free space (agno, block, length) to (start sector, end sector)
|
|
$UMOUNT_PROG $loop_mnt
|
|
$XFS_DB_PROG -r -c "freesp -d" $img_file | $SED_PROG '/^.*from/,$d'| \
|
|
$AWK_PROG -v spb=$sectors_per_block -v agsize=$agsize \
|
|
'{ print spb * ($1 * agsize + $2), spb * ($1 * agsize + $2 + $3) - 1 }'
|
|
;;
|
|
esac
|
|
}
|
|
|
|
merge_ranges()
|
|
{
|
|
# Merges consecutive ranges from two input files
|
|
file1=$1
|
|
file2=$2
|
|
|
|
tmp_file=$tmp/sectors.tmp
|
|
|
|
cat $file1 $file2 | sort -n > $tmp_file
|
|
|
|
read line < $tmp_file
|
|
start=${line% *}
|
|
end=${line#* }
|
|
|
|
# Continue from second line
|
|
sed -i "1d" $tmp_file
|
|
while read line; do
|
|
curr_start=${line% *}
|
|
curr_end=${line#* }
|
|
|
|
if [ `expr $end + 1` -ge $curr_start ]; then
|
|
if [ $curr_end -gt $end ]; then
|
|
end=$curr_end
|
|
fi
|
|
else
|
|
echo $start $end
|
|
start=$curr_start
|
|
end=$curr_end
|
|
fi
|
|
done < $tmp_file
|
|
|
|
# Print last line
|
|
echo $start $end
|
|
|
|
rm $tmp_file
|
|
}
|
|
|
|
here=`pwd`
|
|
tmp=`mktemp -d`
|
|
|
|
img_file=$TEST_DIR/$$.fs
|
|
dd if=/dev/zero of=$img_file bs=1M count=300 &> /dev/null
|
|
|
|
loop_dev=$(_create_loop_device $img_file)
|
|
loop_mnt=$tmp/loop_mnt
|
|
|
|
fiemap_ref="$tmp/reference"
|
|
fiemap_after="$tmp/after"
|
|
free_sectors="$tmp/free_sectors"
|
|
merged_sectors="$tmp/merged_free_sectors"
|
|
|
|
mkdir $loop_mnt
|
|
|
|
[ "$FSTYP" = "xfs" ] && MKFS_OPTIONS="-f $MKFS_OPTIONS"
|
|
|
|
$MKFS_PROG -t $FSTYP $MKFS_OPTIONS $loop_dev &> /dev/null
|
|
$MOUNT_PROG $loop_dev $loop_mnt
|
|
|
|
echo -n "Generating garbage on loop..."
|
|
# Goal is to fill it up, ignore any errors.
|
|
for i in `seq 1 10`; do
|
|
mkdir $loop_mnt/$i &> /dev/null
|
|
cp -r $here/* $loop_mnt/$i &> /dev/null || break
|
|
done
|
|
|
|
# Get reference fiemap, this can contain i.e. uninitialized inode table
|
|
sync
|
|
get_holes $img_file > $fiemap_ref
|
|
|
|
# Delete some files
|
|
find $loop_mnt -type f -print | $AWK_PROG \
|
|
'BEGIN {srand()}; {if(rand() > 0.7) print $1;}' | xargs rm
|
|
echo "done."
|
|
|
|
echo -n "Running fstrim..."
|
|
$FSTRIM_PROG $loop_mnt &> /dev/null
|
|
echo "done."
|
|
|
|
echo -n "Detecting interesting holes in image..."
|
|
# Get after-trim fiemap
|
|
sync
|
|
get_holes $img_file > $fiemap_after
|
|
echo "done."
|
|
|
|
echo -n "Comparing holes to the reported space from FS..."
|
|
# Get block size
|
|
block_size=$(stat -f -c "%S" $loop_mnt/)
|
|
sectors_per_block=`expr $block_size / 512`
|
|
|
|
# Obtain free space from filesystem
|
|
get_free_sectors > $free_sectors
|
|
# Merge original holes with free sectors
|
|
merge_ranges $fiemap_ref $free_sectors > $merged_sectors
|
|
|
|
# Check that all holes after fstrim call were already present before or
|
|
# that they match free space reported from FS
|
|
while read line; do
|
|
from=${line% *}
|
|
to=${line#* }
|
|
if ! $AWK_PROG -v s=$from -v e=$to \
|
|
'{ if ($1 <= s && e <= $2) found = 1};
|
|
END { if(found) exit 0; else exit 1}' $merged_sectors
|
|
then
|
|
echo "Sectors $from-$to are not marked as free!"
|
|
exit
|
|
fi
|
|
done < $fiemap_after
|
|
echo "done."
|
|
|
|
status=0
|
|
exit
|