##/bin/bash # # 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="$XFS_FSR_PROG" ;; ext4|ext4dev) testfile="$TEST_DIR/$$-test.defrag" donorfile="$TEST_DIR/$$-donor.defrag" bsize=`get_block_size $TEST_DIR` $XFS_IO_PROG -f -c "pwrite -b $bsize 0 $bsize" $testfile > /dev/null cp $testfile $donorfile echo $testfile | $here/src/e4compact -v -f $donorfile | \ grep -q "err:95" if [ $? -eq 0 ]; then rm -f $testfile $donorfile 2>&1 > /dev/null _notrun "$FSTYP test filesystem doesn't support online defrag" fi rm -f $testfile $donorfile 2>&1 > /dev/null DEFRAG_PROG="$E4DEFRAG_PROG" ;; btrfs) DEFRAG_PROG="$BTRFS_UTIL_PROG filesystem defragment" ;; *) _notrun "defragmentation not supported for fstype \"$FSTYP\"" ;; esac _require_command "$DEFRAG_PROG" defragment _require_xfs_io_command "fiemap" } _extent_count() { $XFS_IO_PROG -c "fiemap" $1 >> $seqres.full 2>&1 $XFS_IO_PROG -c "fiemap" $1 | tail -n +2 | grep -v hole | wc -l| $AWK_PROG '{print $1}' } _check_extent_count() { min=$1 max=$2 ext_cnt=$3 # Return failure if $3 isn't between $1 and $2; let caller decide # action if it's not, we just return status here. if [ "$min" -gt "$ext_cnt" ]; then echo "Found $ext_cnt extents min:$max" return 1; fi if [ "$max" -ne -1 ] && [ "$ext_cnt" -gt "$max" ]; then echo "Found $ext_cnt max: $max" return 1; fi if [ $max -ne $min ]; then echo "in_range($min, $max)" else echo "$ext_cnt" fi # success return 0 } # Defrag file, check it, and remove it. _defrag() { min_before=0 max_before=-1 min_after=0 max_after=-1 csum=1 mtime=1 while [ $# -gt 1 ] do case $1 in --min_before) [ -z "$2" ] && _fail "missing argument for --min_before" min_before=$2 shift ;; --max_before) [ -z "$2" ] && _fail "missing argument for --max_before" max_before=$2 shift ;; --min_after) [ -z "$2" ] && _fail "missing argument for --min_after" min_after=$2 shift ;; --max_after) [ -z "$2" ] && _fail "missing argument for --max_after" max_after=$2 shift ;; --before) [ -z "$2" ] && _fail "missing argument for --before" min_before=$2 max_before=$2 shift ;; --after) [ -z "$2" ] && _fail "missing argument for --after" min_after=$2 max_after=$2 shift ;; --no_csum) csum= ;; --no_mtime) mtime= ;; --no_unlink) no_unlink=1 ;; *) _fail "invalid argument to common/dump function: $1" ;; esac shift done echo -n "Before: " ext_before=$(_extent_count $1) _check_extent_count $min_before $max_before $ext_before [ $? -eq 0 ] || _notrun "Could not adequately fragment file" [ ! -z $csum ] && CSUM_BEFORE=`md5sum $1` STAT_BEFORE=`stat -c "a: %x m: %y c: %z" $1` $DEFRAG_PROG -v $1 >> $seqres.full 2>&1 _scratch_cycle_mount STAT_AFTER=`stat -c "a: %x m: %y c: %z" $1` [ ! -z $csum ] && CSUM_AFTER=`md5sum $1` echo -n "After: " ext_after=$(_extent_count $1) _check_extent_count $min_after $max_after $ext_after [ $? -eq 0 ] || _fail "Failed to adequately defragment file" [ "$ext_before" -lt "$ext_after" ] && \ _fail "Number of extents increased after defragmentation," \ " before:$ext_before, after:$ext_after" if [ ! -z $csum ] && [ "$CSUM_BEFORE" != "$CSUM_AFTER" ]; then _fail "file checksum changed post-defrag ($CSUM_BEFORE/$CSUM_AFTER)" fi if [ ! -z $mtime ] && [ "$STAT_BEFORE" != "$STAT_AFTER" ]; then _fail "file timestamps changed post-defrag:\n$STAT_BEFORE\n$STAT_AFTER" fi [ -z $no_unlink ] && rm -f $1 }