generic/204: don't flood stdout with ENOSPC messages on an ENOSPC test
[xfstests-dev.git] / common / defrag
1 ##/bin/bash
2 # SPDX-License-Identifier: GPL-2.0
3 # Copyright (c) 2009 Eric Sandeen. All Rights Reserved.
4 #
5 # Functions useful for defragmentation tests
6
7 _require_defrag()
8 {
9     case "$FSTYP" in
10     xfs)
11         # xfs_fsr does preallocates, require "falloc"
12         _require_xfs_io_command "falloc"
13         DEFRAG_PROG="$XFS_FSR_PROG"
14         ;;
15     ext4|ext4dev)
16         testfile="$TEST_DIR/$$-test.defrag"
17         donorfile="$TEST_DIR/$$-donor.defrag"
18         bsize=`_get_block_size $TEST_DIR`
19         $XFS_IO_PROG -f -c "pwrite -b $bsize 0 $bsize" $testfile > /dev/null
20         cp $testfile $donorfile
21         echo $testfile | $here/src/e4compact -v -f $donorfile | \
22                 grep -q "err:95"
23         if [ $? -eq 0 ]; then
24                 rm -f $testfile $donorfile 2>&1 > /dev/null
25                 _notrun "$FSTYP test filesystem doesn't support online defrag"
26         fi
27         rm -f $testfile $donorfile 2>&1 > /dev/null
28         DEFRAG_PROG="$E4DEFRAG_PROG"
29         ;;
30     f2fs)
31         DEFRAG_PROG="$F2FS_IO_PROG defrag_file"
32         ;;
33     btrfs)
34         DEFRAG_PROG="$BTRFS_UTIL_PROG filesystem defragment"
35         ;;
36     *)
37         _notrun "defragmentation not supported for fstype \"$FSTYP\""
38         ;;
39     esac
40
41     _require_command "$DEFRAG_PROG" defragment
42     _require_xfs_io_command "fiemap"
43 }
44
45 _extent_count()
46 {
47         $XFS_IO_PROG -c "fiemap" $1  >> $seqres.full 2>&1
48         $XFS_IO_PROG -c "fiemap" $1 | tail -n +2 | grep -v hole | wc -l| $AWK_PROG '{print $1}'
49 }
50
51 _check_extent_count()
52 {
53         min=$1
54         max=$2
55         ext_cnt=$3
56
57         # Return failure if $3 isn't between $1 and $2; let caller decide
58         # action if it's not, we just return status here.
59         if [ "$min" -gt "$ext_cnt" ]; then
60                 echo "Found $ext_cnt extents  min:$max"
61                 return 1;
62         fi
63         if [ "$max" -ne -1 ] && [ "$ext_cnt" -gt "$max" ]; then
64                 echo "Found $ext_cnt max: $max"
65                 return 1;
66         fi
67
68         if [ $max -ne $min ]; then
69             echo "in_range($min, $max)"
70         else
71             echo "$ext_cnt"
72         fi
73         # success
74         return 0
75 }
76
77 # Defrag file, check it, and remove it.
78 _defrag()
79 {
80         min_before=0
81         max_before=-1
82         min_after=0
83         max_after=-1
84         csum=1
85         mtime=1
86
87         while [ $# -gt 1 ]
88         do
89             case $1
90                 in
91                 --min_before)
92                     [ -z "$2" ] && _fail "missing argument for --min_before"
93                     min_before=$2
94                     shift
95                     ;;
96                 --max_before)
97                     [ -z "$2" ] && _fail "missing argument for --max_before"
98                     max_before=$2
99                     shift
100                     ;;
101                 --min_after)
102                     [ -z "$2" ] && _fail "missing argument for --min_after"
103                     min_after=$2
104                     shift
105                     ;;
106                 --max_after)
107                     [ -z "$2" ] && _fail "missing argument for --max_after"
108                     max_after=$2
109                     shift
110                     ;;
111                 --before)
112                     [ -z "$2" ] && _fail "missing argument for --before"
113                     min_before=$2
114                     max_before=$2
115                     shift
116                     ;;
117                 --after)
118                     [ -z "$2" ] && _fail "missing argument for --after"
119                     min_after=$2
120                     max_after=$2
121                     shift
122                     ;;
123                 --no_csum)
124                     csum=
125                     ;;
126                 --no_mtime)
127                     mtime=
128                     ;;
129                 --no_unlink)
130                     no_unlink=1
131                     ;;
132                 *)
133                     _fail "invalid argument to common/dump function: $1"
134                     ;;
135             esac
136             shift
137         done
138
139         echo -n "Before: "
140         ext_before=$(_extent_count $1)
141         _check_extent_count $min_before $max_before $ext_before
142         [ $? -eq 0 ] || _notrun "Could not adequately fragment file"
143
144         [ ! -z $csum ] && CSUM_BEFORE=`md5sum $1`
145         STAT_BEFORE=`stat -c "a: %x m: %y c: %z" $1`
146
147         if [ $FSTYP == "f2fs" ]; then
148                 local filesize=`ls -l $1 | $AWK_PROG '{print $5}'`
149                 $DEFRAG_PROG 0 $filesize $1 >> $seqres.full 2>&1
150         else
151                 $DEFRAG_PROG -v $1 >> $seqres.full 2>&1
152         fi
153
154         _scratch_cycle_mount
155         STAT_AFTER=`stat -c "a: %x m: %y c: %z" $1`
156         [ ! -z $csum ] && CSUM_AFTER=`md5sum $1`
157
158         echo -n "After: "
159         ext_after=$(_extent_count $1)
160         _check_extent_count $min_after $max_after $ext_after
161         [ $? -eq 0 ] || _fail "Failed to adequately defragment file"
162
163         [ "$ext_before" -lt "$ext_after" ] && \
164                 _fail "Number of extents increased after defragmentation," \
165                       " before:$ext_before, after:$ext_after"
166         if [ ! -z $csum ] && [ "$CSUM_BEFORE" != "$CSUM_AFTER" ]; then
167                 _fail "file checksum changed post-defrag ($CSUM_BEFORE/$CSUM_AFTER)"
168         fi
169         if [ ! -z $mtime ] && [ "$STAT_BEFORE" != "$STAT_AFTER" ]; then
170                 _fail "file timestamps changed post-defrag:\n$STAT_BEFORE\n$STAT_AFTER"
171         fi
172         [ -z $no_unlink ] && rm -f $1
173 }
174