280: test freeze deadlock w/ quotas
[xfstests-dev.git] / 276
1 #! /bin/bash
2 # FSQA Test No. 276
3 #
4 # Run fsstress to create a reasonably strange file system, make a
5 # snapshot and run more fsstress. Then select some files from that fs,
6 # run filefrag to get the extent mapping and follow the backrefs.
7 # We check to end up back at the original file with the correct offset.
8 #
9 #-----------------------------------------------------------------------
10 # Copyright (C) 2011 STRATO.  All rights reserved.
11 #
12 # This program is free software; you can redistribute it and/or
13 # modify it under the terms of the GNU General Public License as
14 # published by the Free Software Foundation.
15 #
16 # This program is distributed in the hope that it would be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 # GNU General Public License for more details.
20 #
21 # You should have received a copy of the GNU General Public License
22 # along with this program; if not, write the Free Software Foundation,
23 # Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
24 #
25 #-----------------------------------------------------------------------
26 #
27 # creator
28 owner=list.btrfs@jan-o-sch.net
29
30 seq=`basename $0`
31 echo "QA output created by $seq"
32
33 here=`pwd`
34 tmp=/tmp/$$
35 status=1
36
37 _cleanup()
38 {
39         echo "*** unmount"
40         umount $SCRATCH_MNT 2>/dev/null
41         rm -f $tmp.*
42 }
43 trap "_cleanup; exit \$status" 0 1 2 3 15
44
45 # get standard environment, filters and checks
46 . ./common.rc
47 . ./common.filter
48
49 # real QA test starts here
50 _need_to_be_root
51 _supported_fs btrfs
52 _supported_os Linux
53 _require_scratch
54
55 _require_nobigloopfs
56 _require_btrfs inspect-internal
57 _require_command "/usr/sbin/filefrag"
58
59 rm -f $seq.full
60
61 FILEFRAG_FILTER='if (/, blocksize (\d+)/) {$blocksize = $1; next} ($ext, '\
62 '$logical, $physical, $expected, $length, $flags) = (/^\s*(\d+)\s+(\d+)'\
63 '\s+(\d+)\s+(?:(\d+)\s+)?(\d+)\s+(.*)/) or next; $flags =~ '\
64 '/(?:^|,)inline(?:,|$)/ and next; print $physical * $blocksize, "#", '\
65 '$length * $blocksize, "#", $logical * $blocksize, " "'
66
67 # this makes filefrag output script readable by using a perl helper.
68 # output is one extent per line, with three numbers separated by '#'
69 # the numbers are: physical, length, logical (all in bytes)
70 # sample output: "1234#10#5678" -> physical 1234, length 10, logical 5678
71 _filter_extents()
72 {
73         tee -a $seq.full | $PERL_PROG -ne "$FILEFRAG_FILTER"
74 }
75
76 _check_file_extents()
77 {
78         cmd="filefrag -vx $1"
79         echo "# $cmd" >> $seq.full
80         out=`$cmd | _filter_extents`
81         if [ -z "$out" ]; then
82                 return 1
83         fi
84         echo "after filter: $out" >> $seq.full
85         echo $out
86         return 0
87 }
88
89 # use a logical address and walk the backrefs back to the inode.
90 # compare to the expected result.
91 # returns 0 on success, 1 on error (with output made)
92 _btrfs_inspect_addr()
93 {
94         mp=$1
95         addr=$2
96         expect_addr=$3
97         expect_inum=$4
98         file=$5
99         cmd="$BTRFS_UTIL_PROG inspect-internal logical-resolve -P $addr $mp"
100         echo "# $cmd" >> $seq.full
101         out=`$cmd`
102         echo "$out" >> $seq.full
103         grep_expr="inode $expect_inum offset $expect_addr root"
104         echo "$out" | grep "^$grep_expr 5$" >/dev/null
105         ret=$?
106         if [ $ret -eq 0 ]; then
107                 # look for a root number that is not 5
108                 echo "$out" | grep "^$grep_expr \([0-46-9][0-9]*\|5[0-9]\+\)$" \
109                         >/dev/null
110                 ret=$?
111         fi
112         if [ $ret -eq 0 ]; then
113                 return 0
114         fi
115         echo "unexpected output from"
116         echo "  $cmd"
117         echo "expected inum: $expect_inum, expected address: $expect_addr,"\
118                 "file: $file, got:"
119         echo "$out"
120         return 1
121 }
122
123 # use an inode number and walk the backrefs back to the file name.
124 # compare to the expected result.
125 # returns 0 on success, 1 on error (with output made)
126 _btrfs_inspect_inum()
127 {
128         file=$1
129         inum=$2
130         snap_name=$3
131         mp="$SCRATCH_MNT/$snap_name"
132         cmd="$BTRFS_UTIL_PROG inspect-internal inode-resolve $inum $mp"
133         echo "# $cmd" >> $seq.full
134         out=`$cmd`
135         echo "$out" >> $seq.full
136         grep_expr="^$file$"
137         cnt=`echo "$out" | grep "$grep_expr" | wc -l`
138         if [ $cnt -ge "1" ]; then
139                 return 0
140         fi
141         echo "unexpected output from"
142         echo "  $cmd"
143         echo "expected path: $file, got:"
144         echo "$out"
145         return 1
146 }
147
148 _btrfs_inspect_check()
149 {
150         file=$1
151         physical=$2
152         length=$3
153         logical=$4
154         snap_name=$5
155         cmd="stat -c %i $file"
156         echo "# $cmd" >> $seq.full
157         inum=`$cmd`
158         echo "$inum" >> $seq.full
159         _btrfs_inspect_addr $SCRATCH_MNT $physical $logical $inum $file
160         ret=$?
161         if [ $ret -eq 0 ]; then
162                 _btrfs_inspect_inum $file $inum $snap_name
163                 ret=$?
164         fi
165         return $ret
166 }
167
168 run_check()
169 {
170         echo "# $@" >> $seq.full 2>&1
171         "$@" >> $seq.full 2>&1 || _fail "failed: '$@'"
172 }
173
174 workout()
175 {
176         fsz=$1
177         nfiles=$2
178         procs=$3
179         snap_name=$4
180
181         umount $SCRATCH_DEV >/dev/null 2>&1
182         echo "*** mkfs -dsize=$fsz"    >>$seq.full
183         echo ""                                     >>$seq.full
184         _scratch_mkfs_sized $fsz >>$seq.full 2>&1 \
185                 || _fail "size=$fsz mkfs failed"
186         run_check _scratch_mount
187         # -w ensures that the only ops are ones which cause write I/O
188         run_check $FSSTRESS_PROG -d $SCRATCH_MNT -w -p $procs -n 1000 \
189                 $FSSTRESS_AVOID
190
191         run_check $BTRFS_UTIL_PROG subvol snap $SCRATCH_MNT \
192                 $SCRATCH_MNT/$snap_name
193
194         run_check umount $SCRATCH_DEV >/dev/null 2>&1
195         run_check _scratch_mount "-o compress=lzo"
196
197         # make some noise but ensure we're not touching existing data
198         # extents.
199         run_check $FSSTRESS_PROG -d $SCRATCH_MNT -p $procs -n 2000 \
200                 -z -f chown=3 -f link=1 -f mkdir=2 -f mknod=2 \
201                 -f rename=2 -f setxattr=1 -f symlink=2
202         clean_dir="$SCRATCH_MNT/next"
203         mkdir $clean_dir
204         # now make more files to get a higher tree
205         run_check $FSSTRESS_PROG -d $clean_dir -w -p $procs -n 2000 \
206                 $FSSTRESS_AVOID
207         run_check umount $SCRATCH_DEV >/dev/null 2>&1
208         run_check _scratch_mount "-o atime"
209
210         cnt=0
211         errcnt=0
212         dir="$SCRATCH_MNT/$snap_name/"
213         for file in `find $dir -name f\* -size +0 | sort -R`; do
214                 extents=`_check_file_extents $file`
215                 ret=$?
216                 if [ $ret -ne 0 ]; then
217                         continue;
218                 fi
219                 for i in $extents; do
220                         physical=$i
221                         length=$i
222                         logical=$i
223                         physical=`echo $physical | sed -e 's/#.*//'`
224                         length=`echo $length | sed -e 's/[^#]+#//'`
225                         length=`echo $length | sed -e 's/#.*//'`
226                         logical=`echo $logical | sed -e 's/.*#//'`
227                         _btrfs_inspect_check $file $physical $length $logical \
228                                                 $snap_name
229                         ret=$?
230                         if [ $ret -ne 0 ]; then
231                                 errcnt=`expr $errcnt + 1`
232                         fi
233                 done
234                 cnt=`expr $cnt + 1`
235                 if [ $cnt -ge $nfiles ]; then
236                         break
237                 fi
238         done
239         if [ $errcnt -gt 0 ]; then
240                 _fail "test failed: $errcnt error(s)"
241         fi
242 }
243
244 echo "*** test backref walking"
245
246 snap_name="snap1"
247 filesize=`expr 2000 \* 1024 \* 1024`
248 nfiles=4
249 numprocs=1
250
251 workout $filesize $nfiles $numprocs $snap_name
252
253 echo "*** done"
254 status=0
255 exit