fstests: move test group info to test files
[xfstests-dev.git] / tests / btrfs / 004
1 #! /bin/bash
2 # SPDX-License-Identifier: GPL-2.0
3 # Copyright (C) 2011 STRATO.  All rights reserved.
4 #
5 # FSQA Test No. btrfs/004
6 #
7 # Run fsstress to create a reasonably strange file system, make a
8 # snapshot and run more fsstress. Then select some files from that fs,
9 # run filefrag to get the extent mapping and follow the backrefs.
10 # We check to end up back at the original file with the correct offset.
11 #
12 . ./common/preamble
13 _begin_fstest auto rw metadata
14
15 noise_pid=0
16
17 # Override the default cleanup function.
18 _cleanup()
19 {
20         rm $tmp.running
21         wait
22         rm -f $tmp.*
23 }
24
25 # Import common functions.
26 . ./common/filter
27
28 # real QA test starts here
29 _supported_fs btrfs
30 _require_scratch
31 _require_no_large_scratch_dev
32 _require_btrfs_command inspect-internal logical-resolve
33 _require_btrfs_command inspect-internal inode-resolve
34 _require_command "$FILEFRAG_PROG" filefrag
35
36 FILEFRAG_FILTER='
37         if (/blocks? of (\d+) bytes/) {
38                 $blocksize = $1;
39                 next
40         }
41         ($ext, $logical, $physical, $length) =
42                 (/^\s*(\d+):\s+(\d+)..\s+\d+:\s+(\d+)..\s+\d+:\s+(\d+):/)
43         or next;
44         ($flags) = /.*:\s*(\S*)$/;
45         print $physical * $blocksize, "#",
46               $length * $blocksize, "#",
47               $logical * $blocksize, "#",
48               $flags, " "'
49
50 # this makes filefrag output script readable by using a perl helper.
51 # output is one extent per line, with three numbers separated by '#'
52 # the numbers are: physical, length, logical (all in bytes)
53 # sample output: "1234#10#5678" -> physical 1234, length 10, logical 5678
54 _filter_extents()
55 {
56         tee -a $seqres.full | $PERL_PROG -ne "$FILEFRAG_FILTER"
57 }
58
59 _check_file_extents()
60 {
61         cmd="$FILEFRAG_PROG -v $1"
62         echo "# $cmd" >> $seqres.full
63         out=`$cmd | _filter_extents`
64         if [ -z "$out" ]; then
65                 return 1
66         fi
67         echo "after filter: $out" >> $seqres.full
68         echo $out
69         return 0
70 }
71
72 # use a logical address and walk the backrefs back to the inode.
73 # compare to the expected result.
74 # returns 0 on success, 1 on error (with output made)
75 _btrfs_inspect_addr()
76 {
77         mp=$1
78         addr=$2
79         expect_addr=$3
80         expect_inum=$4
81         file=$5
82         cmd="$BTRFS_UTIL_PROG inspect-internal logical-resolve -s 65536 -P $addr $mp"
83         echo "# $cmd" >> $seqres.full
84         out=`$cmd`
85         echo "$out" >> $seqres.full
86         grep_expr="inode $expect_inum offset $expect_addr root"
87         echo "$out" | grep "^$grep_expr 5$" >/dev/null
88         ret=$?
89         if [ $ret -eq 0 ]; then
90                 # look for a root number that is not 5
91                 echo "$out" | grep "^$grep_expr \([0-46-9][0-9]*\|5[0-9]\+\)$" \
92                         >/dev/null
93                 ret=$?
94         fi
95         if [ $ret -eq 0 ]; then
96                 return 0
97         fi
98         echo "unexpected output from"
99         echo "  $cmd"
100         echo "expected inum: $expect_inum, expected address: $expect_addr,"\
101                 "file: $file, got:"
102         echo "$out"
103         return 1
104 }
105
106 # use an inode number and walk the backrefs back to the file name.
107 # compare to the expected result.
108 # returns 0 on success, 1 on error (with output made)
109 _btrfs_inspect_inum()
110 {
111         file=$1
112         inum=$2
113         snap_name=$3
114         mp="$SCRATCH_MNT/$snap_name"
115         cmd="$BTRFS_UTIL_PROG inspect-internal inode-resolve $inum $mp"
116         echo "# $cmd" >> $seqres.full
117         out=`$cmd`
118         echo "$out" >> $seqres.full
119         grep_expr="^$file$"
120         cnt=`echo "$out" | grep "$grep_expr" | wc -l`
121         if [ $cnt -ge "1" ]; then
122                 return 0
123         fi
124         echo "unexpected output from"
125         echo "  $cmd"
126         echo "expected path: $file, got:"
127         echo "$out"
128         return 1
129 }
130
131 _btrfs_inspect_check()
132 {
133         file=$1
134         physical=$2
135         length=$3
136         logical=$4
137         snap_name=$5
138         cmd="stat -c %i $file"
139         echo "# $cmd" >> $seqres.full
140         inum=`$cmd`
141         echo "$inum" >> $seqres.full
142         _btrfs_inspect_addr $SCRATCH_MNT $physical $logical $inum $file
143         ret=$?
144         if [ $ret -eq 0 ]; then
145                 _btrfs_inspect_inum $file $inum $snap_name
146                 ret=$?
147         fi
148         return $ret
149 }
150
151 workout()
152 {
153         fsz=$1
154         nfiles=$2
155         procs=$3
156         snap_name=$4
157         do_bg_noise=$5
158
159         _scratch_unmount >/dev/null 2>&1
160         echo "*** mkfs -dsize=$fsz"    >>$seqres.full
161         echo ""                                     >>$seqres.full
162         _scratch_mkfs_sized $fsz >>$seqres.full 2>&1 \
163                 || _fail "size=$fsz mkfs failed"
164         _scratch_mount
165         # -w ensures that the only ops are ones which cause write I/O
166         run_check $FSSTRESS_PROG -d $SCRATCH_MNT -w -p $procs -n 2000 \
167                 $FSSTRESS_AVOID
168
169         _run_btrfs_util_prog subvolume snapshot $SCRATCH_MNT \
170                 $SCRATCH_MNT/$snap_name
171
172         run_check _scratch_unmount >/dev/null 2>&1
173         _scratch_mount "-o compress=lzo"
174
175         # make some noise but ensure we're not touching existing data
176         # extents.
177         run_check $FSSTRESS_PROG -d $SCRATCH_MNT -p $procs -n 4000 \
178                 -z -f chown=3 -f link=1 -f mkdir=2 -f mknod=2 \
179                 -f rename=2 -f setxattr=1 -f symlink=2
180
181         clean_dir="$SCRATCH_MNT/next"
182         mkdir $clean_dir
183         # now make more files to get a higher tree
184         run_check $FSSTRESS_PROG -d $clean_dir -w -p $procs -n 2000 \
185                 $FSSTRESS_AVOID
186         run_check _scratch_unmount >/dev/null 2>&1
187         _scratch_mount "-o atime"
188
189         if [ $do_bg_noise -ne 0 ]; then
190                 # make background noise while backrefs are being walked
191                 while [ -f "$tmp.running" ]; do
192                         echo background fsstress >>$seqres.full
193                         run_check $FSSTRESS_PROG -d $SCRATCH_MNT/bgnoise -n 999
194                         echo background rm >>$seqres.full
195                         rm -rf $SCRATCH_MNT/bgnoise/
196                 done &
197                 noise_pid=`jobs -p %1`
198                 echo "background noise by $noise_pid" >>$seqres.full
199         fi
200
201         cnt=0
202         errcnt=0
203         dir="$SCRATCH_MNT/$snap_name/"
204         for file in `find $dir -name f\* -size +0 | sort -R`; do
205                 extents=`_check_file_extents $file`
206                 ret=$?
207                 if [ $ret -ne 0 ]; then
208                         continue;
209                 fi
210                 for i in $extents; do
211                         physical=`echo $i | cut -d '#' -f 1`
212                         length=`echo $i | cut -d '#' -f 2`
213                         logical=`echo $i | cut -d '#' -f 3`
214                         flags=`echo $i | cut -d '#' -f 4`
215                         # Skip inline extents, otherwise btrfs inspect-internal
216                         # logical-resolve will fail (with errno ENOENT), as it
217                         # can't find an extent with a start address of 0 in the
218                         # extent tree.
219                         if [ $physical -eq 0 ]; then
220                                 echo "$flags" | grep -E '(^|,)inline(,|$)' \
221                                         > /dev/null
222                                 ret=$?
223                                 if [ $ret -ne 0 ]; then
224                                         echo "Unexpected physical address 0 for non-inline extent, file $file, flags $flags"
225                                 fi
226                         else
227                                 _btrfs_inspect_check $file $physical $length \
228                                         $logical $snap_name
229                                 ret=$?
230                         fi
231                         if [ $ret -ne 0 ]; then
232                                 errcnt=`expr $errcnt + 1`
233                         fi
234                 done
235                 cnt=`expr $cnt + 1`
236                 if [ $cnt -ge $nfiles ]; then
237                         break
238                 fi
239         done
240
241         if [ $errcnt -gt 0 ]; then
242                 _fail "test failed: $errcnt error(s)"
243         fi
244 }
245
246 echo "*** test backref walking"
247
248 snap_name="snap1"
249 filesize=`expr 2000 \* 1024 \* 1024`
250 nfiles=4
251 numprocs=1
252 do_bg_noise=1
253
254 touch $tmp.running
255
256 workout $filesize $nfiles $numprocs $snap_name $do_bg_noise
257
258 echo "*** done"
259 status=0
260 exit