This is done by comparing free sectors reported by some FS utility (dumpe2fs/xfs_db) and actual discard commands sent to device obtained via blk tracer in debugfs. Currently supported FS are ext[34], xfs; device with discard support is not required, the test creates loop device for this purpose. Signed-off-by: Tomas Racek <tracek@xxxxxxxxxx> --- 289 | 169 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 289.out | 5 ++ group | 1 + 3 files changed, 175 insertions(+) create mode 100755 289 create mode 100644 289.out diff --git a/289 b/289 new file mode 100755 index 0000000..b6bffc1 --- /dev/null +++ b/289 @@ -0,0 +1,169 @@ +#! /bin/bash +# FS QA Test No. 289 +# +# Test that filesystem sends discard requests only on free blocks +# +#----------------------------------------------------------------------- +# Copyright (c) 2012 Red Hat, Inc., Tomas Racek <tracek@xxxxxxxxxx> +# +# 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 +#----------------------------------------------------------------------- +# +# creator +owner=tracek@xxxxxxxxxx + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=`mktemp -d` +status=1 # failure is the default! +trap "_cleanup; exit \$status" 0 1 2 3 15 + +_cleanup() +{ + $UMOUNT_PROG $loop_mnt + rm -rf $tmp + _destroy_loop_device $loop_dev + rm $img_file +} + +mkfs_loop() +{ + if [ $FSTYP = "xfs" ]; then + MKFS_OPTIONS="-f $MKFS_OPTIONS" + fi + + $MKFS_PROG -t $FSTYP $MKFS_OPTIONS $loop_dev &> /dev/null +} + +get_block_size() +{ + case $FSTYP in + ext[34]) + bsize=$($DUMPE2FS_PROG $loop_dev 2>&1 | sed -n '/^Block size/ s/.*: *\(.*\)/\1/p') + ;; + xfs) + $UMOUNT_PROG $loop_mnt + bsize=$($XFS_DB_PROG -c "sb" -c"p" $loop_dev | sed -n 's/^blocksize = \([0-9]\+\).*/\1/p') + $MOUNT_PROG $loop_dev $loop_mnt + ;; + esac +} + +get_free_sectors() +{ + case $FSTYP in + ext[34]) + size=1 + clstsize=$($DUMPE2FS_PROG $loop_dev 2>/dev/null | sed '/Cluster size/!d; s/.*: *//') + if [ -n "$clstsize" ]; then + size=$((clstsize/bsize)) + fi + $DUMPE2FS_PROG $loop_dev 2>/dev/null | sed '/ Free blocks/!d; s/.*: //; s/, /\n/g; /^$/d' | \ + $AWK_PROG -v spb=$spb -v size=$size 'BEGIN{FS="-"}; {printf "%d-%d\n", spb * $1, (spb * $2 == 0)? spb * ($1 + size) - 1 : spb * ($2 + size) - 1}' > $free_sectors + ;; + xfs) + $UMOUNT_PROG $loop_mnt + agblocks=$($XFS_DB_PROG -c"sb" -c "p" $loop_dev | sed -n 's/agblocks = \(.*\)$/\1/p') + $XFS_DB_PROG -c"freesp -d" $loop_dev | $AWK_PROG '{if($1 == "from") exit; else print}' | \ + $AWK_PROG -v agb=$agblocks -v spb=$spb '{print spb * ($1 * agb + $2) "-" spb * ($1 * agb + $2 + $3) - 1}' | sort -n > $free_sectors + $MOUNT_PROG $loop_dev $loop_mnt + ;; + esac +} + +# get standard environment, filters and checks +. ./common.rc +. ./common.config + +# real QA test starts here + +_supported_fs ext3 ext4 xfs +_supported_os Linux +_require_fstrim +_require_dumpe2fs +_require_fs_space $TEST_DIR 3145728 + +debugfs=$($MOUNT_PROG | grep debugfs | cut -d " " -f3) +[ -n $debugfs ] || _notrun "This test requires mounted debugfs" + +cat $debugfs/tracing/available_tracers | grep -q blk || _notrun "blk tracer is not available" + +img_file=$TEST_DIR/$$.fs +$XFS_IO_PROG -f -c "truncate 3G" $img_file + +loop_dev=$(_create_loop_device $img_file) +loop_base=$(basename $loop_dev) +loop_mnt=$tmp/loop_mnt + +mkdir $loop_mnt + +mkfs_loop +$MOUNT_PROG $loop_dev $loop_mnt + +echo -n "Generating garbage on loop..." +for i in `seq 1 30`; do + + mkdir $loop_mnt/$i + cp -r $here/* $loop_mnt/$i +done +find $loop_mnt -type f -print | $AWK_PROG 'BEGIN {srand()}; {if(rand() > 0.7) print $1;}' | xargs rm +echo "done." + +ssize=`cat /sys/block/$loop_base/queue/hw_sector_size` +get_block_size +spb=$((bsize/ssize)) + +free_sectors=$tmp/sectors +trace=$tmp/trace + +echo -n "Obtaining free sectors from FS..." +get_free_sectors +echo "done." + +echo -n "Running fstrim & trace..." +echo 1 > /sys/block/$loop_base/trace/enable +echo blk > $debugfs/tracing/current_tracer +echo > $debugfs/tracing/trace +echo 1 > $debugfs/tracing/tracing_on + +$FSTRIM_PROG $loop_mnt > /dev/null + +cat $debugfs/tracing/trace | grep "\[fstrim\]" | cut -d ":" -f2- | +$AWK_PROG '$3 == "D"' | # Filter discard operation +$AWK_PROG '{print $4 "-" $4 + $6 - 1}' | # Transform (start, length) => (start, end) +sort -n > $trace + +echo 0 > $debugfs/tracing/tracing_on +echo 0 > /sys/block/$loop_base/trace/enable +echo "done." + +echo -n "Comparing trace to free sectors..." +while read line +do + start=${line%-*} + end=${line#*-} + # Check if sectors obtained from trace can be matched with free sectors + if ! $AWK_PROG -v s=$start -v e=$end 'BEGIN {FS="-"}; {if ($1 <= s && e <= $2) found = 1}; END{if (found) exit 0; else exit 1}' $free_sectors + then + echo "Sectors $line are not marked as free by FS!" + exit + fi +done <$trace +echo "done." + +# success, all done +status=0 +exit diff --git a/289.out b/289.out new file mode 100644 index 0000000..90465a6 --- /dev/null +++ b/289.out @@ -0,0 +1,5 @@ +QA output created by 289 +Generating garbage on loop...done. +Obtaining free sectors from FS...done. +Running fstrim & trace...done. +Comparing trace to free sectors...done. diff --git a/group b/group index f52c5d5..ead4911 100644 --- a/group +++ b/group @@ -406,3 +406,4 @@ deprecated 285 auto rw 286 other 287 auto dump quota quick +289 auto trim -- 1.7.11.7 _______________________________________________ xfs mailing list xfs@xxxxxxxxxxx http://oss.sgi.com/mailman/listinfo/xfs