blob: b6c337e7331856825df75dc755f1c806f45be5d7 [file] [log] [blame]
##/bin/bash
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2007 Silicon Graphics, Inc. All Rights Reserved.
#
# common functions for excersizing hole punches with extent size hints etc.
_spawn_test_file() {
echo "# spawning test file with $*"
local blksize=$1
local file_size=`expr $2 \* $blksize`
local extent_size_hint=`expr $3 \* $blksize`
local test_file=$4
local reserve_space=$5
if [ $extent_size_hint -ne 0 ]; then
echo "+ setting extent size hint to $extent_size_hint"
$XFS_IO_PROG -f \
-c "extsize $extent_size_hint" \
$test_file
fi
# print extent size hint for $test_file
$XFS_IO_PROG -f \
-c "extsize" \
$test_file
if [ "$reserve_space" == "noresv" ]; then
echo "+ not using resvsp at file creation"
$XFS_IO_PROG -f \
-c "truncate $file_size" \
$test_file
else
$XFS_IO_PROG -f \
-c "truncate $file_size" \
-c "resvsp 0 $file_size" \
$test_file
fi
}
_do_write() {
echo "# writing with $*"
local blksize=$1
local write_offset=`expr $2 \* $blksize`
local write_size=`expr $3 \* $blksize`
local test_file=$4
$XFS_IO_PROG -f \
-c "pwrite $write_offset $write_size" \
$test_file >/dev/null
}
_do_bmap() {
echo "# showing file state $*"
local test_file=$1
$XFS_IO_PROG -f \
-c "bmap -vvp" \
$test_file
}
_coalesce_extents()
{
block_size=$1
[[ -z $block_size ]] && block_size=512
awk -v block_size="$block_size" -F: '
{
range = $2;
type = $3;
split(range, bounds, "[\\[ \\.\\]]");
low = bounds[3];
high = bounds[5];
if (type != prev_type) {
if (prev_type != "")
printf("%u]:%s\n", (low * 512 / block_size) - 1,
prev_type);
printf("%u: [%u..", out_count++,
(low * 512) / block_size);
prev_type = type;
}
}
END {
if (prev_type != "")
printf("%u]:%s\n", ((high + 1) * 512 / block_size) - 1,
prev_type);
}'
}
_filter_fiemap()
{
block_size=$1
$AWK_PROG '
$3 ~ /hole/ {
print $1, $2, $3;
next;
}
$5 ~ /0x[[:xdigit:]]*8[[:xdigit:]][[:xdigit:]]/ {
print $1, $2, "unwritten";
next;
}
$5 ~ /0x[[:xdigit:]]+/ {
print $1, $2, "data";
}' |
_coalesce_extents $block_size
}
_filter_fiemap_flags()
{
$AWK_PROG '
$3 ~ /hole/ {
print $1, $2, $3;
next;
}
$5 ~ /0x[[:xdigit:]]*8[[:xdigit:]][[:xdigit:]]/ {
print $1, $2, "unwritten";
next;
}
$5 ~ /0x[[:xdigit:]]+/ {
print $1, $2, $5;
}' |
_coalesce_extents
}
# Filters fiemap output to only print the
# file offset column and whether or not
# it is an extent or a hole
_filter_hole_fiemap()
{
$AWK_PROG '
$3 ~ /hole/ {
print $1, $2, $3;
next;
}
$5 ~ /0x[[:xdigit:]]+/ {
print $1, $2, "extent";
}' |
_coalesce_extents
}
# 10000 Unwritten preallocated extent
# 01000 Doesn't begin on stripe unit
# 00100 Doesn't end on stripe unit
# 00010 Doesn't begin on stripe width
# 00001 Doesn't end on stripe width
_filter_bmap()
{
awk '
$3 ~ /hole/ {
print $1, $2, $3;
next;
}
$7 ~ /1[01][01][01][01]/ {
print $1, $2, "unwritten";
next;
}
$7 ~ /0[01][01][01][01]/ {
print $1, $2, "data"
}' |
_coalesce_extents
}
die_now()
{
status=1
exit
}
# test the different corner cases for zeroing a range:
#
# 1. into a hole
# 2. into allocated space
# 3. into unwritten space
# 4. hole -> data
# 5. hole -> unwritten
# 6. data -> hole
# 7. data -> unwritten
# 8. unwritten -> hole
# 9. unwritten -> data
# 10. hole -> data -> hole
# 11. data -> hole -> data
# 12. unwritten -> data -> unwritten
# 13. data -> unwritten -> data
# 14. data -> hole @ EOF
# 15. data -> hole @ 0
# 16. data -> cache cold ->hole
# 17. data -> hole in single block file
#
# Test file is removed, created and sync'd between tests.
#
# Use -k flag to keep the file between tests. This will
# test the handling of pre-existing holes.
#
# Use the -d flag to not sync the file between tests.
# This will test the handling of delayed extents
#
# Use the -u flag to not run unwritten tests.
# This will eliminate some unnecessary information.
#
_test_generic_punch()
{
remove_testfile=1
sync_cmd="-c fsync"
unwritten_tests=1
OPTIND=1
while getopts 'dku' OPTION
do
case $OPTION in
k) remove_testfile=
;;
d) sync_cmd=
;;
u) unwritten_tests=
;;
?) echo Invalid flag
exit 1
;;
esac
done
shift $(($OPTIND - 1))
alloc_cmd=$1
punch_cmd=$2
zero_cmd=$3 #if not testing zero just set to punch
map_cmd=$4
filter_cmd=$5
testfile=$6
# The punch hole tests needs multiple of the largest extent size being
# tested, with multiple=16 it can test extent size upto 64k.
multiple=16
_4k="$((multiple * 4))k"
_8k="$((multiple * 8))k"
_12k="$((multiple * 12))k"
_20k="$((multiple * 20))k"
# initial test state must be defined, otherwise the first test can fail
# due ot stale file state left from previous tests.
rm -f $testfile
echo " 1. into a hole"
$XFS_IO_PROG -f -c "truncate $_20k" \
-c "$zero_cmd $_4k $_8k" \
-c "$map_cmd -v" $testfile | $filter_cmd
[ $? -ne 0 ] && die_now
_md5_checksum $testfile
echo " 2. into allocated space"
if [ "$remove_testfile" ]; then
rm -f $testfile
fi
$XFS_IO_PROG -f -c "truncate $_20k" \
-c "pwrite 0 $_20k" $sync_cmd \
-c "$zero_cmd $_4k $_8k" \
-c "$map_cmd -v" $testfile | $filter_cmd
[ $? -ne 0 ] && die_now
_md5_checksum $testfile
if [ "$unwritten_tests" ]; then
echo " 3. into unwritten space"
if [ "$remove_testfile" ]; then
rm -f $testfile
fi
$XFS_IO_PROG -f -c "truncate $_20k" \
-c "$alloc_cmd 0 $_20k" \
-c "$zero_cmd $_4k $_8k" \
-c "$map_cmd -v" $testfile | $filter_cmd
[ $? -ne 0 ] && die_now
_md5_checksum $testfile
fi
echo " 4. hole -> data"
if [ "$remove_testfile" ]; then
rm -f $testfile
fi
$XFS_IO_PROG -f -c "truncate $_20k" \
-c "pwrite $_8k $_8k" $sync_cmd \
-c "$zero_cmd $_4k $_8k" \
-c "$map_cmd -v" $testfile | $filter_cmd
[ $? -ne 0 ] && die_now
_md5_checksum $testfile
if [ "$unwritten_tests" ]; then
echo " 5. hole -> unwritten"
if [ "$remove_testfile" ]; then
rm -f $testfile
fi
$XFS_IO_PROG -f -c "truncate $_20k" \
-c "$alloc_cmd $_8k $_8k" \
-c "$zero_cmd $_4k $_8k" \
-c "$map_cmd -v" $testfile | $filter_cmd
[ $? -ne 0 ] && die_now
_md5_checksum $testfile
fi
echo " 6. data -> hole"
if [ "$remove_testfile" ]; then
rm -f $testfile
fi
$XFS_IO_PROG -f -c "truncate $_20k" \
-c "pwrite 0 $_8k" $sync_cmd \
-c "$zero_cmd $_4k $_8k" \
-c "$map_cmd -v" $testfile | $filter_cmd
[ $? -ne 0 ] && die_now
_md5_checksum $testfile
if [ "$unwritten_tests" ]; then
echo " 7. data -> unwritten"
if [ "$remove_testfile" ]; then
rm -f $testfile
fi
$XFS_IO_PROG -f -c "truncate $_20k" \
-c "pwrite 0 $_8k" $sync_cmd \
-c "$alloc_cmd $_8k $_8k" \
-c "$zero_cmd $_4k $_8k" \
-c "$map_cmd -v" $testfile | $filter_cmd
[ $? -ne 0 ] && die_now
_md5_checksum $testfile
echo " 8. unwritten -> hole"
if [ "$remove_testfile" ]; then
rm -f $testfile
fi
$XFS_IO_PROG -f -c "truncate $_20k" \
-c "$alloc_cmd 0 $_8k" \
-c "$zero_cmd $_4k $_8k" \
-c "$map_cmd -v" $testfile | $filter_cmd
[ $? -ne 0 ] && die_now
_md5_checksum $testfile
echo " 9. unwritten -> data"
if [ "$remove_testfile" ]; then
rm -f $testfile
fi
$XFS_IO_PROG -f -c "truncate $_20k" \
-c "$alloc_cmd 0 $_8k" \
-c "pwrite $_8k $_8k" $sync_cmd \
-c "$zero_cmd $_4k $_8k" \
-c "$map_cmd -v" $testfile | $filter_cmd
[ $? -ne 0 ] && die_now
_md5_checksum $testfile
fi
echo " 10. hole -> data -> hole"
if [ "$remove_testfile" ]; then
rm -f $testfile
fi
$XFS_IO_PROG -f -c "truncate $_20k" \
-c "pwrite $_8k $_4k" $sync_cmd \
-c "$zero_cmd $_4k $_12k" \
-c "$map_cmd -v" $testfile | $filter_cmd
[ $? -ne 0 ] && die_now
_md5_checksum $testfile
echo " 11. data -> hole -> data"
if [ "$remove_testfile" ]; then
rm -f $testfile
fi
$XFS_IO_PROG -f -c "truncate $_20k" \
-c "$alloc_cmd 0 $_20k" \
-c "pwrite 0 $_8k" \
-c "pwrite $_12k $_8k" $sync_cmd \
-c "$punch_cmd $_8k $_4k" \
-c "$zero_cmd $_4k $_12k" \
-c "$map_cmd -v" $testfile | $filter_cmd
[ $? -ne 0 ] && die_now
_md5_checksum $testfile
if [ "$unwritten_tests" ]; then
echo " 12. unwritten -> data -> unwritten"
if [ "$remove_testfile" ]; then
rm -f $testfile
fi
$XFS_IO_PROG -f -c "truncate $_20k" \
-c "$alloc_cmd 0 $_20k" \
-c "pwrite $_8k $_4k" $sync_cmd \
-c "$zero_cmd $_4k $_12k" \
-c "$map_cmd -v" $testfile | $filter_cmd
[ $? -ne 0 ] && die_now
_md5_checksum $testfile
echo " 13. data -> unwritten -> data"
if [ "$remove_testfile" ]; then
rm -f $testfile
fi
$XFS_IO_PROG -f -c "truncate $_20k" \
-c "$alloc_cmd 0 $_20k" \
-c "pwrite 0k $_4k" $sync_cmd \
-c "pwrite $_12k $_8k" -c "fsync" \
-c "$zero_cmd $_4k $_12k" \
-c "$map_cmd -v" $testfile | $filter_cmd
[ $? -ne 0 ] && die_now
_md5_checksum $testfile
fi
# Don't need to check EOF case for collapse range.
# VFS layer return invalid error in this case,
# So it is not a proper case for collapse range test of each local fs.
if [ "$zero_cmd" != "fcollapse" ]; then
echo " 14. data -> hole @ EOF"
rm -f $testfile
$XFS_IO_PROG -f -c "truncate $_20k" \
-c "pwrite 0 $_20k" $sync_cmd \
-c "$zero_cmd $_12k $_8k" \
-c "$map_cmd -v" $testfile | $filter_cmd
[ $? -ne 0 ] && die_now
_md5_checksum $testfile
fi
if [ "$zero_cmd" == "fcollapse" ]; then
echo " 14. data -> hole @ 0"
else
echo " 15. data -> hole @ 0"
fi
if [ "$remove_testfile" ]; then
rm -f $testfile
fi
$XFS_IO_PROG -f -c "truncate $_20k" \
-c "pwrite 0 $_20k" $sync_cmd \
-c "$zero_cmd 0 $_8k" \
-c "$map_cmd -v" $testfile | $filter_cmd
[ $? -ne 0 ] && die_now
_md5_checksum $testfile
# If zero_cmd is fcollpase, don't check unaligned offsets
if [ "$zero_cmd" == "fcollapse" ]; then
return
fi
# If zero_cmd is finsert, don't check unaligned offsets
if [ "$zero_cmd" == "finsert" ]; then
return
fi
echo " 16. data -> cache cold ->hole"
if [ "$remove_testfile" ]; then
rm -f $testfile
rm -f $testfile.2
else
cp $testfile $testfile.2
fi
$XFS_IO_PROG -f -c "truncate $_20k" \
-c "pwrite $_8k $_12k" -c "fsync" $testfile.2 \
> /dev/null
$XFS_IO_PROG -f -c "truncate $_20k" \
-c "pwrite 0 $_20k" $sync_cmd \
-c "$zero_cmd 0k $_8k" \
-c "fadvise -d" \
-c "$map_cmd -v" $testfile | $filter_cmd
diff $testfile $testfile.2
[ $? -ne 0 ] && die_now
rm -f $testfile.2
_md5_checksum $testfile
# different file sizes mean we can't use md5sum to check the hole is
# valid. Hence use hexdump to dump the contents and chop off the last
# line of output that indicates the file size. We also have to fudge
# the extent size as that will change with file size, too - that's what
# the sed line noise does - it will always result in an output of [0..7]
# so it matches 4k block size...
echo " 17. data -> hole in single block file"
if [ "$remove_testfile" ]; then
rm -f $testfile
fi
block_size=`_get_block_size $TEST_DIR`
$XFS_IO_PROG -f -c "truncate $block_size" \
-c "pwrite 0 $block_size" $sync_cmd \
-c "$zero_cmd 128 128" \
-c "$map_cmd -v" $testfile | $filter_cmd | \
sed -e "s/\.\.[0-9]*\]/..7\]/"
[ $? -ne 0 ] && die_now
od -x $testfile | head -n -1
}
_test_block_boundaries()
{
remove_testfile=1
sync_cmd="-c fsync"
unwritten_tests=1
OPTIND=1
while getopts 'dk' OPTION
do
case $OPTION in
k) remove_testfile=
;;
d) sync_cmd=
;;
?) echo Invalid flag
exit 1
;;
esac
done
shift $(($OPTIND - 1))
bs=$1
zero_cmd=$2
filter_cmd=$3
testfile=$4
# Block size plus 1
bs_p1=$(($bs + 1))
# Block size plus 2
bs_p2=$(($bs + 2))
# Block size minus 1
bs_m1=$(($bs - 1))
# Block size multiplied by 2
bs_t2=$(($bs * 2))
# Block size divided by 2
bs_d2=$(($bs / 2))
echo "zero 0, 1"
$XFS_IO_PROG -f -t -c "pwrite -S 0x41 0 $bs" \
-c "pwrite -S 0x42 $bs $bs" \
-c "$zero_cmd 0 1" \
-c "pread -v 0 $bs_t2" \
$testfile | $filter_cmd
echo "zero 0, $bs_m1"
$XFS_IO_PROG -f -t -c "pwrite -S 0x41 0 $bs" \
-c "pwrite -S 0x42 $bs $bs" \
-c "$zero_cmd 0 $bs_m1" \
-c "pread -v 0 $bs_t2" \
$testfile | $filter_cmd
echo "zero 0, $bs"
$XFS_IO_PROG -f -t -c "pwrite -S 0x41 0 $bs" \
-c "pwrite -S 0x42 $bs $bs" \
-c "$zero_cmd 0 $bs" \
-c "pread -v 0 $bs_t2" \
$testfile | $filter_cmd
echo "zero 0, $bs_p1"
$XFS_IO_PROG -f -t -c "pwrite -S 0x41 0 $bs" \
-c "pwrite -S 0x42 $bs $bs" \
-c "$zero_cmd 0 $bs_p1" \
-c "pread -v 0 $bs_t2" \
$testfile | $filter_cmd
echo "zero $bs_m1, $bs"
$XFS_IO_PROG -f -t -c "pwrite -S 0x41 0 $bs" \
-c "pwrite -S 0x42 $bs $bs" \
-c "$zero_cmd $bs_m1 $bs" \
-c "pread -v 0 $bs_t2" \
$testfile | $filter_cmd
echo "zero $bs_m1, $bs_p1"
$XFS_IO_PROG -f -t -c "pwrite -S 0x41 0 $bs" \
-c "pwrite -S 0x42 $bs $bs" \
-c "$zero_cmd $bs_m1 $bs_p1" \
-c "pread -v 0 $bs_t2" \
$testfile | $filter_cmd
echo "zero $bs_m1, $bs_p2"
$XFS_IO_PROG -f -t -c "pwrite -S 0x41 0 $bs" \
-c "pwrite -S 0x42 $bs $bs" \
-c "$zero_cmd $bs_m1 $bs_p2" \
-c "pread -v 0 $bs_t2" \
$testfile | $filter_cmd
echo "zero $bs, $bs"
$XFS_IO_PROG -f -t -c "pwrite -S 0x41 0 $bs" \
-c "pwrite -S 0x42 $bs $bs" \
-c "$zero_cmd $bs $bs" \
-c "pread -v 0 $bs_t2" \
$testfile | $filter_cmd
echo "zero $bs_d2 , $bs"
$XFS_IO_PROG -f -t -c "pwrite -S 0x41 0 $bs" \
-c "pwrite -S 0x42 $bs $bs" \
-c "$zero_cmd $bs_d2 $bs" \
-c "pread -v 0 $bs_t2" \
$testfile | $filter_cmd
}