2 # SPDX-License-Identifier: GPL-2.0
3 # Copyright (C) 2011 STRATO. All rights reserved.
5 # FSQA Test No. btrfs/004
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.
13 seqres=$RESULT_DIR/$seq
14 echo "QA output created by $seq"
27 trap "_cleanup; exit \$status" 0 1 2 3 15
29 # get standard environment, filters and checks
33 # real QA test starts here
37 _require_no_large_scratch_dev
38 _require_btrfs_command inspect-internal logical-resolve
39 _require_btrfs_command inspect-internal inode-resolve
40 _require_command "$FILEFRAG_PROG" filefrag
45 if (/blocks? of (\d+) bytes/) {
49 ($ext, $logical, $physical, $length) =
50 (/^\s*(\d+):\s+(\d+)..\s+\d+:\s+(\d+)..\s+\d+:\s+(\d+):/)
52 ($flags) = /.*:\s*(\S*)$/;
53 print $physical * $blocksize, "#",
54 $length * $blocksize, "#",
55 $logical * $blocksize, "#",
58 # this makes filefrag output script readable by using a perl helper.
59 # output is one extent per line, with three numbers separated by '#'
60 # the numbers are: physical, length, logical (all in bytes)
61 # sample output: "1234#10#5678" -> physical 1234, length 10, logical 5678
64 tee -a $seqres.full | $PERL_PROG -ne "$FILEFRAG_FILTER"
69 cmd="$FILEFRAG_PROG -v $1"
70 echo "# $cmd" >> $seqres.full
71 out=`$cmd | _filter_extents`
72 if [ -z "$out" ]; then
75 echo "after filter: $out" >> $seqres.full
80 # use a logical address and walk the backrefs back to the inode.
81 # compare to the expected result.
82 # returns 0 on success, 1 on error (with output made)
90 cmd="$BTRFS_UTIL_PROG inspect-internal logical-resolve -s 65536 -P $addr $mp"
91 echo "# $cmd" >> $seqres.full
93 echo "$out" >> $seqres.full
94 grep_expr="inode $expect_inum offset $expect_addr root"
95 echo "$out" | grep "^$grep_expr 5$" >/dev/null
97 if [ $ret -eq 0 ]; then
98 # look for a root number that is not 5
99 echo "$out" | grep "^$grep_expr \([0-46-9][0-9]*\|5[0-9]\+\)$" \
103 if [ $ret -eq 0 ]; then
106 echo "unexpected output from"
108 echo "expected inum: $expect_inum, expected address: $expect_addr,"\
114 # use an inode number and walk the backrefs back to the file name.
115 # compare to the expected result.
116 # returns 0 on success, 1 on error (with output made)
117 _btrfs_inspect_inum()
122 mp="$SCRATCH_MNT/$snap_name"
123 cmd="$BTRFS_UTIL_PROG inspect-internal inode-resolve $inum $mp"
124 echo "# $cmd" >> $seqres.full
126 echo "$out" >> $seqres.full
128 cnt=`echo "$out" | grep "$grep_expr" | wc -l`
129 if [ $cnt -ge "1" ]; then
132 echo "unexpected output from"
134 echo "expected path: $file, got:"
139 _btrfs_inspect_check()
146 cmd="stat -c %i $file"
147 echo "# $cmd" >> $seqres.full
149 echo "$inum" >> $seqres.full
150 _btrfs_inspect_addr $SCRATCH_MNT $physical $logical $inum $file
152 if [ $ret -eq 0 ]; then
153 _btrfs_inspect_inum $file $inum $snap_name
167 _scratch_unmount >/dev/null 2>&1
168 echo "*** mkfs -dsize=$fsz" >>$seqres.full
169 echo "" >>$seqres.full
170 _scratch_mkfs_sized $fsz >>$seqres.full 2>&1 \
171 || _fail "size=$fsz mkfs failed"
173 # -w ensures that the only ops are ones which cause write I/O
174 run_check $FSSTRESS_PROG -d $SCRATCH_MNT -w -p $procs -n 2000 \
177 _run_btrfs_util_prog subvolume snapshot $SCRATCH_MNT \
178 $SCRATCH_MNT/$snap_name
180 run_check _scratch_unmount >/dev/null 2>&1
181 _scratch_mount "-o compress=lzo"
183 # make some noise but ensure we're not touching existing data
185 run_check $FSSTRESS_PROG -d $SCRATCH_MNT -p $procs -n 4000 \
186 -z -f chown=3 -f link=1 -f mkdir=2 -f mknod=2 \
187 -f rename=2 -f setxattr=1 -f symlink=2
189 clean_dir="$SCRATCH_MNT/next"
191 # now make more files to get a higher tree
192 run_check $FSSTRESS_PROG -d $clean_dir -w -p $procs -n 2000 \
194 run_check _scratch_unmount >/dev/null 2>&1
195 _scratch_mount "-o atime"
197 if [ $do_bg_noise -ne 0 ]; then
198 # make background noise while backrefs are being walked
199 while [ -f "$tmp.running" ]; do
200 echo background fsstress >>$seqres.full
201 run_check $FSSTRESS_PROG -d $SCRATCH_MNT/bgnoise -n 999
202 echo background rm >>$seqres.full
203 rm -rf $SCRATCH_MNT/bgnoise/
205 noise_pid=`jobs -p %1`
206 echo "background noise by $noise_pid" >>$seqres.full
211 dir="$SCRATCH_MNT/$snap_name/"
212 for file in `find $dir -name f\* -size +0 | sort -R`; do
213 extents=`_check_file_extents $file`
215 if [ $ret -ne 0 ]; then
218 for i in $extents; do
219 physical=`echo $i | cut -d '#' -f 1`
220 length=`echo $i | cut -d '#' -f 2`
221 logical=`echo $i | cut -d '#' -f 3`
222 flags=`echo $i | cut -d '#' -f 4`
223 # Skip inline extents, otherwise btrfs inspect-internal
224 # logical-resolve will fail (with errno ENOENT), as it
225 # can't find an extent with a start address of 0 in the
227 if [ $physical -eq 0 ]; then
228 echo "$flags" | grep -E '(^|,)inline(,|$)' \
231 if [ $ret -ne 0 ]; then
232 echo "Unexpected physical address 0 for non-inline extent, file $file, flags $flags"
235 _btrfs_inspect_check $file $physical $length \
239 if [ $ret -ne 0 ]; then
240 errcnt=`expr $errcnt + 1`
244 if [ $cnt -ge $nfiles ]; then
249 if [ $errcnt -gt 0 ]; then
250 _fail "test failed: $errcnt error(s)"
254 echo "*** test backref walking"
257 filesize=`expr 2000 \* 1024 \* 1024`
264 workout $filesize $nfiles $numprocs $snap_name $do_bg_noise