4 # Test that filesystem sends discard requests only on free blocks
6 #-----------------------------------------------------------------------
7 # Copyright (c) 2013 Red Hat, Inc., Tomas Racek <tracek@redhat.com>
9 # This program is free software; you can redistribute it and/or
10 # modify it under the terms of the GNU General Public License as
11 # published by the Free Software Foundation.
13 # This program is distributed in the hope that it would be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with this program; if not, write the Free Software Foundation,
20 # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 #-----------------------------------------------------------------------
25 seqres=$RESULT_DIR/$seq
26 echo "QA output created by $seq"
28 status=1 # failure is the default!
29 trap "_cleanup; exit \$status" 0 1 2 3 15
33 _supported_fs ext4 xfs
38 _require_xfs_io_command "fiemap"
39 _require_fs_space $TEST_DIR 307200
40 [ "$FSTYP" = "ext4" ] && _require_dumpe2fs
44 $UMOUNT_PROG $loop_dev &> /dev/null
45 _destroy_loop_device $loop_dev
46 if [ $status -eq 0 ]; then
54 $XFS_IO_PROG -F -c fiemap $1 | grep hole | $SED_PROG 's/.*\[\(.*\)\.\.\(.*\)\].*/\1 \2/'
61 $DUMPE2FS_PROG $img_file 2>&1 | grep " Free blocks" | cut -d ":" -f2- | \
62 tr ',' '\n' | $SED_PROG 's/^ //' | \
63 $AWK_PROG -v spb=$sectors_per_block 'BEGIN{FS="-"};
65 if($2 != "") # range of blocks
66 print spb * $1, spb * ($2 + 1) - 1;
67 else # just single block
68 print spb * $1, spb * ($1 + 1) - 1;
72 agsize=`xfs_info $loop_mnt | $SED_PROG -n 's/.*agsize=\(.*\) blks.*/\1/p'`
73 # Convert free space (agno, block, length) to (start sector, end sector)
74 $UMOUNT_PROG $loop_mnt
75 $XFS_DB_PROG -r -c "freesp -d" $img_file | $SED_PROG '/^.*from/,$d'| \
76 $AWK_PROG -v spb=$sectors_per_block -v agsize=$agsize \
77 '{ print spb * ($1 * agsize + $2), spb * ($1 * agsize + $2 + $3) - 1 }'
84 # Merges consecutive ranges from two input files
88 tmp_file=$tmp/sectors.tmp
90 cat $file1 $file2 | sort -n > $tmp_file
96 # Continue from second line
102 if [ `expr $end + 1` -ge $curr_start ]; then
103 if [ $curr_end -gt $end ]; then
122 img_file=$TEST_DIR/$$.fs
123 dd if=/dev/zero of=$img_file bs=1M count=300 &> /dev/null
125 loop_dev=$(_create_loop_device $img_file)
126 loop_mnt=$tmp/loop_mnt
128 fiemap_ref="$tmp/reference"
129 fiemap_after="$tmp/after"
130 free_sectors="$tmp/free_sectors"
131 merged_sectors="$tmp/merged_free_sectors"
135 [ "$FSTYP" = "xfs" ] && MKFS_OPTIONS="-f $MKFS_OPTIONS"
138 _mount $loop_dev $loop_mnt
140 echo -n "Generating garbage on loop..."
141 # Goal is to fill it up, ignore any errors.
142 for i in `seq 1 10`; do
143 mkdir $loop_mnt/$i &> /dev/null
144 cp -r $here/* $loop_mnt/$i &> /dev/null || break
147 # Get reference fiemap, this can contain i.e. uninitialized inode table
149 get_holes $img_file > $fiemap_ref
152 find $loop_mnt -type f -print | $AWK_PROG \
153 'BEGIN {srand()}; {if(rand() > 0.7) print $1;}' | xargs rm
156 echo -n "Running fstrim..."
157 $FSTRIM_PROG $loop_mnt &> /dev/null
160 echo -n "Detecting interesting holes in image..."
161 # Get after-trim fiemap
163 get_holes $img_file > $fiemap_after
166 echo -n "Comparing holes to the reported space from FS..."
168 block_size=$(get_block_size $loop_mnt/)
169 sectors_per_block=`expr $block_size / 512`
171 # Obtain free space from filesystem
172 get_free_sectors > $free_sectors
173 # Merge original holes with free sectors
174 merge_ranges $fiemap_ref $free_sectors > $merged_sectors
176 # Check that all holes after fstrim call were already present before or
177 # that they match free space reported from FS
181 if ! $AWK_PROG -v s=$from -v e=$to \
182 '{ if ($1 <= s && e <= $2) found = 1};
183 END { if(found) exit 0; else exit 1}' $merged_sectors
185 echo "Sectors $from-$to are not marked as free!"