--- /dev/null
+#! /bin/sh
+# FS QA Test No. 218
+#
+# Basic defragmentation sanity tests
+#
+#-----------------------------------------------------------------------
+# Copyright (c) 2009 Eric Sandeen. 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.
+#
+# 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=sandeen@sandeen.net
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=tmp/$$
+status=1 # failure is the default!
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+_cleanup()
+{
+ cd /
+ rm -f $tmp.*
+ _cleanup_testdir
+}
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+. ./common.defrag
+
+# real QA test starts here
+_supported_fs xfs ext4
+_supported_os Linux
+
+_setup_testdir
+# We require scratch so that we'll have free contiguous space
+_require_scratch
+_scratch_mkfs >/dev/null 2>&1
+_scratch_mount
+
+_require_defrag
+
+fragfile=$SCRATCH_MNT/fragfile.$$
+
+rm -f $fragfile
+
+# Craft some fragmented files, defrag them, check the result.
+
+echo "zero-length file:" | tee -a $seq.full
+touch $fragfile
+_defrag $fragfile
+
+echo "Sparse file (no blocks):" | tee -a $seq.full
+xfs_io -F -f -c "truncate 1m" $fragfile
+_defrag $fragfile
+
+echo "Contiguous file:" | tee -a $seq.full
+dd if=/dev/zero of=$fragfile bs=4k count=4 &>/dev/null
+_defrag $fragfile
+
+echo "Write backwards sync, but contiguous - should defrag to 1 extent" | tee -a $seq.full
+for I in `seq 9 -1 0`; do
+ dd if=/dev/zero of=$fragfile bs=4k count=1 conv=notrunc seek=$I oflag=sync &>/dev/null
+done
+_defrag $fragfile
+
+echo "Write backwards sync leaving holes - defrag should do nothing" | tee -a $seq.full
+for I in `seq 31 -2 0`; do
+ dd if=/dev/zero of=$fragfile bs=4k count=1 conv=notrunc seek=$I oflag=sync &>/dev/null
+done
+_defrag $fragfile
+
+echo "Write forwards sync leaving holes - defrag should do nothing" | tee -a $seq.full
+for I in `seq 0 2 31`; do
+ dd if=/dev/zero of=$fragfile bs=4k count=1 conv=notrunc seek=$I oflag=sync &>/dev/null
+done
+_defrag $fragfile
+
+rm -f $seq.full
+status=0
+exit
--- /dev/null
+##/bin/sh
+#
+# Copyright (c) 2009 Eric Sandeen
+# 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.
+#
+# 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
+#
+#
+# Functions useful for defragmentation tests
+#
+
+_require_defrag()
+{
+ case "$FSTYP" in
+ xfs)
+ DEFRAG_PROG=/usr/sbin/xfs_fsr
+ ;;
+ ext4)
+ DEFRAG_PROG=/usr/bin/e4defrag
+ ;;
+ *)
+ _notrun "defragmentation not supported for fstype \"$FSTYP\""
+ ;;
+ esac
+
+ _require_command $DEFRAG_PROG
+ _require_command /usr/sbin/filefrag
+}
+
+_extent_count()
+{
+ filefrag $1 | awk '{print $2}'
+ filefrag -v $1 >> $seq.full 2>&1
+}
+
+# Defrag file, check it, and remove it.
+_defrag()
+{
+ echo -n "Before: "
+ _extent_count $1
+ CSUM_BEFORE=`md5sum $1`
+ STAT_BEFORE=`stat -c "a: %x m: %y c: %z" $1`
+ $DEFRAG_PROG -v $1 >> $seq.full 2>&1
+ _scratch_remount
+ STAT_AFTER=`stat -c "a: %x m: %y c: %z" $1`
+ CSUM_AFTER=`md5sum $1`
+ echo -n "After: "
+ _extent_count $1
+ if [ "$CSUM_BEFORE" != "$CSUM_AFTER" ]; then
+ _fail "file checksum changed post-defrag ($CSUM_BEFORE/$CSUM_AFTER)"
+ fi
+ if [ "$STAT_BEFORE" != "$STAT_AFTER" ]; then
+ _fail "file timestamps changed post-defrag:\n$STAT_BEFORE\n$STAT_AFTER"
+ fi
+ rm -f $1
+}
+