| ##/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) | |
| 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" | |
| ;; | |
| f2fs) | |
| DEFRAG_PROG="$F2FS_IO_PROG defrag_file" | |
| ;; | |
| 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` | |
| if [ $FSTYP == "f2fs" ]; then | |
| local filesize=`ls -l $1 | $AWK_PROG '{print $5}'` | |
| $DEFRAG_PROG 0 $filesize $1 >> $seqres.full 2>&1 | |
| else | |
| $DEFRAG_PROG -v $1 >> $seqres.full 2>&1 | |
| fi | |
| _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 | |
| } | |