| ##/bin/bash |
| # SPDX-License-Identifier: GPL-2.0 |
| # Copyright (c) 2009 Eric Sandeen. All Rights Reserved. |
| # |
| # Functions useful for defragmentation tests |
| |
| _require_defrag() |
| { |
| case "$FSTYP" in |
| xfs) |
| # xfs_fsr does preallocates, require "falloc" |
| _require_xfs_io_command "falloc" |
| 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 |
| } |
| |