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
36 _require_no_large_scratch_dev
37 _require_btrfs_command inspect-internal logical-resolve
38 _require_btrfs_command inspect-internal inode-resolve
39 _require_command "$FILEFRAG_PROG" filefrag
44 if (/blocks? of (\d+) bytes/) {
48 ($ext, $logical, $physical, $length) =
49 (/^\s*(\d+):\s+(\d+)..\s+\d+:\s+(\d+)..\s+\d+:\s+(\d+):/)
51 ($flags) = /.*:\s*(\S*)$/;
52 print $physical * $blocksize, "#",
53 $length * $blocksize, "#",
54 $logical * $blocksize, "#",
57 # this makes filefrag output script readable by using a perl helper.
58 # output is one extent per line, with three numbers separated by '#'
59 # the numbers are: physical, length, logical (all in bytes)
60 # sample output: "1234#10#5678" -> physical 1234, length 10, logical 5678
63 tee -a $seqres.full | $PERL_PROG -ne "$FILEFRAG_FILTER"
68 cmd="$FILEFRAG_PROG -v $1"
69 echo "# $cmd" >> $seqres.full
70 out=`$cmd | _filter_extents`
71 if [ -z "$out" ]; then
74 echo "after filter: $out" >> $seqres.full
79 # use a logical address and walk the backrefs back to the inode.
80 # compare to the expected result.
81 # returns 0 on success, 1 on error (with output made)
89 cmd="$BTRFS_UTIL_PROG inspect-internal logical-resolve -s 65536 -P $addr $mp"
90 echo "# $cmd" >> $seqres.full
92 echo "$out" >> $seqres.full
93 grep_expr="inode $expect_inum offset $expect_addr root"
94 echo "$out" | grep "^$grep_expr 5$" >/dev/null
96 if [ $ret -eq 0 ]; then
97 # look for a root number that is not 5
98 echo "$out" | grep "^$grep_expr \([0-46-9][0-9]*\|5[0-9]\+\)$" \
102 if [ $ret -eq 0 ]; then
105 echo "unexpected output from"
107 echo "expected inum: $expect_inum, expected address: $expect_addr,"\
113 # use an inode number and walk the backrefs back to the file name.
114 # compare to the expected result.
115 # returns 0 on success, 1 on error (with output made)
116 _btrfs_inspect_inum()
121 mp="$SCRATCH_MNT/$snap_name"
122 cmd="$BTRFS_UTIL_PROG inspect-internal inode-resolve $inum $mp"
123 echo "# $cmd" >> $seqres.full
125 echo "$out" >> $seqres.full
127 cnt=`echo "$out" | grep "$grep_expr" | wc -l`
128 if [ $cnt -ge "1" ]; then
131 echo "unexpected output from"
133 echo "expected path: $file, got:"
138 _btrfs_inspect_check()
145 cmd="stat -c %i $file"
146 echo "# $cmd" >> $seqres.full
148 echo "$inum" >> $seqres.full
149 _btrfs_inspect_addr $SCRATCH_MNT $physical $logical $inum $file
151 if [ $ret -eq 0 ]; then
152 _btrfs_inspect_inum $file $inum $snap_name
166 _scratch_unmount >/dev/null 2>&1
167 echo "*** mkfs -dsize=$fsz" >>$seqres.full
168 echo "" >>$seqres.full
169 _scratch_mkfs_sized $fsz >>$seqres.full 2>&1 \
170 || _fail "size=$fsz mkfs failed"
172 # -w ensures that the only ops are ones which cause write I/O
173 run_check $FSSTRESS_PROG -d $SCRATCH_MNT -w -p $procs -n 2000 \
176 _run_btrfs_util_prog subvolume snapshot $SCRATCH_MNT \
177 $SCRATCH_MNT/$snap_name
179 run_check _scratch_unmount >/dev/null 2>&1
180 _scratch_mount "-o compress=lzo"
182 # make some noise but ensure we're not touching existing data
184 run_check $FSSTRESS_PROG -d $SCRATCH_MNT -p $procs -n 4000 \
185 -z -f chown=3 -f link=1 -f mkdir=2 -f mknod=2 \
186 -f rename=2 -f setxattr=1 -f symlink=2
188 clean_dir="$SCRATCH_MNT/next"
190 # now make more files to get a higher tree
191 run_check $FSSTRESS_PROG -d $clean_dir -w -p $procs -n 2000 \
193 run_check _scratch_unmount >/dev/null 2>&1
194 _scratch_mount "-o atime"
196 if [ $do_bg_noise -ne 0 ]; then
197 # make background noise while backrefs are being walked
198 while [ -f "$tmp.running" ]; do
199 echo background fsstress >>$seqres.full
200 run_check $FSSTRESS_PROG -d $SCRATCH_MNT/bgnoise -n 999
201 echo background rm >>$seqres.full
202 rm -rf $SCRATCH_MNT/bgnoise/
204 noise_pid=`jobs -p %1`
205 echo "background noise by $noise_pid" >>$seqres.full
210 dir="$SCRATCH_MNT/$snap_name/"
211 for file in `find $dir -name f\* -size +0 | sort -R`; do
212 extents=`_check_file_extents $file`
214 if [ $ret -ne 0 ]; then
217 for i in $extents; do
218 physical=`echo $i | cut -d '#' -f 1`
219 length=`echo $i | cut -d '#' -f 2`
220 logical=`echo $i | cut -d '#' -f 3`
221 flags=`echo $i | cut -d '#' -f 4`
222 # Skip inline extents, otherwise btrfs inspect-internal
223 # logical-resolve will fail (with errno ENOENT), as it
224 # can't find an extent with a start address of 0 in the
226 if [ $physical -eq 0 ]; then
227 echo "$flags" | grep -E '(^|,)inline(,|$)' \
230 if [ $ret -ne 0 ]; then
231 echo "Unexpected physical address 0 for non-inline extent, file $file, flags $flags"
234 _btrfs_inspect_check $file $physical $length \
238 if [ $ret -ne 0 ]; then
239 errcnt=`expr $errcnt + 1`
243 if [ $cnt -ge $nfiles ]; then
248 if [ $errcnt -gt 0 ]; then
249 _fail "test failed: $errcnt error(s)"
253 echo "*** test backref walking"
256 filesize=`expr 2000 \* 1024 \* 1024`
263 workout $filesize $nfiles $numprocs $snap_name $do_bg_noise