update to handle striped v2 logs
[xfstests-dev.git] / 018
1 #! /bin/sh
2 # XFS QA Test No. 018
3 #
4 # xfs_logprint test
5 # - extended to test for various log version 2 scenarios
6 # - tests 1 case of user/group quotas
7 #
8 #-----------------------------------------------------------------------
9 # Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
10
11 # This program is free software; you can redistribute it and/or modify it
12 # under the terms of version 2 of the GNU General Public License as
13 # published by the Free Software Foundation.
14
15 # This program is distributed in the hope that it would be useful, but
16 # WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18
19 # Further, this software is distributed without any warranty that it is
20 # free of the rightful claim of any third person regarding infringement
21 # or the like.  Any license provided herein, whether implied or
22 # otherwise, applies only to this software file.  Patent licenses, if
23 # any, provided herein do not apply to combinations of this program with
24 # other software, or any other product whatsoever.
25
26 # You should have received a copy of the GNU General Public License along
27 # with this program; if not, write the Free Software Foundation, Inc., 59
28 # Temple Place - Suite 330, Boston MA 02111-1307, USA.
29
30 # Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
31 # Mountain View, CA  94043, or:
32
33 # http://www.sgi.com 
34
35 # For further information regarding this notice, see: 
36
37 # http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
38 #-----------------------------------------------------------------------
39 #
40 # creator
41 owner=dxm@sgi.com
42
43 seq=`basename $0`
44 echo "QA output created by $seq"
45
46 here=`pwd`
47 tmp=/tmp/$$
48 status=1        # failure is the default!
49
50 # get standard environment, filters and checks
51 . ./common.rc
52 . ./common.filter
53
54 _cleanup()
55 {
56     rm -f $tmp.*
57     if [ $status -eq 0 ]; then
58         # don't keep these files around unless something went wrong
59         rm -f $seq.trans* $seq.op* $seq.full
60     fi
61     echo "*** unmount"
62     umount $SCRATCH_MNT 2>/dev/null
63 }
64 trap "_cleanup; exit \$status" 0 1 2 3 15
65
66 _full()
67 {
68     echo ""            >>$seq.full      
69     echo "*** $* ***"  >>$seq.full
70     echo ""            >>$seq.full
71 }
72
73 # Handle the operations which get split over Log Record
74 # boundaries.
75 # Oper (379)..... flags: CONTINUE
76 # ...
77 # Oper (0)....... flags: WAS_CONT END
78 #
79 # or
80 #
81 # Oper (379)..... flags: none 
82 # ...
83 # Oper (0)....... flags: none 
84 #
85 _filter_opnum()
86 {
87     $AWK_PROG '
88 function extract_opnum(str) {
89         # e.g. "(379):" => "379"
90         gsub(/[():]/,"",str)
91         return str
92 }
93 BEGIN { 
94         opnum = -1
95         #debug = 1
96         }
97 /^Oper/ && debug {
98             printf "line = %s\n", $0
99         }
100 /^Oper/ {
101             was_cont = 0
102             prev_opnum = opnum
103             opnum = extract_opnum($2)
104         }
105 /^Oper/ && /flags: CONTINUE/ { 
106             $9 = "none" # overwrite CONTINUE flags
107             $2 = sprintf("(%d):", remember+opnum)       
108             remember += opnum
109             print
110             next        
111         }
112 /^Oper/ && /flags: WAS_CONT END/ {
113             # skip over was-continued op
114             # we assume there can be only 1
115             was_cont = 1
116             next        
117         }
118 (was_cont == 1) { 
119             # skip over any continued op stuff
120             next
121         }
122 /^Oper/ && /UNMOUNT/ {
123             remember = 0
124             opnum = -1
125             print
126             next
127         }
128 /^Oper/ && (opnum == 0) { 
129             # have operation 0 with NO continued op
130             remember += (prev_opnum+1)
131         }
132 /^Oper/ && debug { printf "line2 = %s, remember = %d, prev_opnum = %d\n", $0, remember, prev_opnum}
133 /^Oper/ && (remember > 0) {
134             # add in opnum accumulation from previous LRs 
135             $2 = sprintf("(%d):", remember+opnum)       
136             print
137             next
138         }
139         {print}
140     '
141 }
142
143 _filter_logprint()
144 {
145     sed '
146         s/data device: 0x[0-9a-f][0-9a-f]*/data device: <DEVICE>/;
147         s/log device: 0x[0-9a-f][0-9a-f]*/log device: <DEVICE>/;
148         s/log file: \".*\"/log device: <DEVICE>/;
149         s/daddr: [0-9][0-9]*/daddr: <DADDR>/;
150         s/length: [0-9][0-9]*/length: <LENGTH>/;
151         s/length: [0-9][0-9]*/length: <LENGTH>/;
152         s/^cycle num overwrites: .*$/cycle num overwrites: <TIDS>/;
153         s/tid: [0-9a-f][0-9a-f]*/tid: <TID>/;
154         s/tid:0x[0-9a-f][0-9a-f]*/tid:<TID>/;
155         s/q:0x[0-9a-f][0-9a-f]*/q:<Q>/;
156         s/a:0x[0-9a-f][0-9a-f]*/a:<A>/g;
157         s/blkno:0x[0-9a-f][0-9a-f]*/blkno:<BLKNO>/g;
158         s/blkno: [0-9][0-9]* (0x[0-9a-f]*)/blkno: <BLKNO> (<BLKNO>)/g;
159         s/blkno: [0-9][0-9]*/blkno: <BLKNO>/g;
160         s/boff: [0-9][0-9]*/boff: <BOFF>/g;
161         s/len: *[0-9][0-9]*/len:<LEN>/g;
162         /zeroed blocks/s/[0-9][0-9]*/<COUNT>/g;
163         /cleared blocks/s/[0-9][0-9]*/<COUNT>/g;
164         /log tail/s/[0-9][0-9]*/<COUNT>/g;
165         s/atime:[0-9a-fx]*  *mtime:[0-9a-fx]*  *ctime:[0-9a-fx]*/atime:<TIME>  mtime:<TIME>  ctime:<TIME>/;
166         s/atime 0x[0-9a-f]* mtime 0x[0-9a-f]* ctime 0x[0-9a-f]*/atime <TIME>  mtime <TIME>  ctime <TIME>/;
167         s/block [0-9][0-9]*/block <BLOCK>/;
168         s/icount: *[0-9][0-9]*  *ifree: *[0-9][0-9]*  *fdblks: *[0-9][0-9]*  *frext: *[0-9][0-9]*/icount:<COUNT> ifree:<FREE> fdblks:<BLOCKS> frext:<COUNT>/;
169         s/sunit: *[0-9][0-9]*  *swidth: *[0-9][0-9]*/sunit:<SUNIT> swidth:<SWIDTH>/;
170         s/1st: *[0-9][0-9]*  *last: *[0-9][0-9]*  *cnt: *[0-9][0-9]*  *freeblks: *[0-9][0-9]*  *longest: *[0-9][0-9]*/1st:<NUM> last:<NUM> cnt:<COUNT> freeblks:<COUNT> longest:<NUM>/;
171         s/^uuid: *[0-9a-f-][0-9a-f-]* *format: *.*$/uuid: <UUID> format: <FORMAT>/;
172         /flushiter:/d;
173         /version:/,/h_size:/d;
174         /override tail/s/[0-9][0-9]*/<TAIL_BLK>/;
175         /^---*/d;
176         /^===*/d;
177         /^~~~*/d;
178         /extended-header/d;
179         /LOG REC AT LSN/d;
180         /^[     ]*$/d;
181         s/  */ /g;
182         s/ $//;
183     ' \
184     | _fix_malloc
185 }
186
187 _check_log()
188 {
189     _full "clean_log : xfs_logprint"
190     _scratch_xfs_logprint -t | tee -a $seq.full \
191         | head | grep -q "<CLEAN>" || _fail "DIRTY LOG"
192 }
193
194 _print_operation()
195 {
196     raw=$seq.op.mnt$mnt.mkfs$mkfs.raw
197     filtered=$seq.op.mnt$mnt.mkfs$mkfs.filtered
198
199     echo "### xfs_logprint output ###" | tee $raw >$filtered
200     _scratch_xfs_logprint -c  2>&1 \
201     | tee -a $raw      \
202     | _filter_logprint \
203     | _filter_opnum    \
204     >>$filtered
205 }
206
207 # start at rec#2 "-s 2" so we skip over UMOUNT record which will always
208 # be a 512b single header at mkfs time
209 # and may not match with the FS mounted at a different LR size 
210 # => xlog_do_recovery_pass() can not handle the different hdr sizes
211 #    it assumes them all to be the same between the start..finish
212 # NB: On IRIX there is no UMOUNT record and so we could start from -s 0.
213
214 _print_transaction_inode()
215 {
216     _start=$1
217     raw=$seq.trans_inode.mnt$mnt.mkfs$mkfs.raw
218     filtered=$seq.trans_inode.mnt$mnt.mkfs$mkfs.filtered
219
220     echo "### xfs_logprint -t -i -s START output ###" | tee $raw >$filtered
221     _scratch_xfs_logprint -t -i -s $_start 2>&1 \
222     | tee -a $raw      \
223     | _filter_logprint \
224     >>$filtered
225 }
226
227 _print_transaction_buf()
228 {
229     _start=$1
230     raw=$seq.trans_buf.mnt$mnt.mkfs$mkfs.raw
231     filtered=$seq.trans_buf.mnt$mnt.mkfs$mkfs.filtered
232
233     echo "### xfs_logprint -t -b -s START output ###" | tee $raw >$filtered
234     _scratch_xfs_logprint -t -b -s $_start 2>&1 \
235     | tee -a $raw      \
236     | _filter_logprint \
237     >>$filtered
238 }
239
240
241 #
242 # will be run with different MKFS and MOUNT options
243 #
244 _mkfs_create_log()
245 {
246     _mkfs_opts=$1
247     _mnt_opts=$2
248
249     # create the FS
250     _full "mkfs"
251     extra_ops="-lsize=2000b $_mkfs_opts"
252     _scratch_mkfs_xfs $extra_ops >$tmp.mkfs0 2>&1
253     [ $? -ne 0 ] && \
254         _notrun "Cannot mkfs for this test using MKFS_OPTIONS specified: $MKFS_OPTIONS $extra_ops"
255
256     # check the mkfs settings
257     _filter_mkfs <$tmp.mkfs0 2>$tmp.mkfs
258     source $tmp.mkfs
259     [ $dbsize -eq 4096 ] \
260         || _notrun "Logprint test, tailored to 4K blocks ($dbsize in use)"
261     [ $isize -eq 256 ] \
262         || _notrun "Logprint test, tailored to 256b inodes ($isize in use)"
263
264     # mount the FS
265     _full " mount"
266     _scratch_mount $_mnt_opts >>$seq.full 2>&1 \
267         || _fail "mount failed: $_mnt_opts $MOUNT_OPTIONS"
268
269     # generate some log traffic - but not too much - life gets a little
270     # more complicated if the log wraps around. This traffic is
271     # pretty much arbitary, but could probably be made better than this.
272     touch $SCRATCH_MNT/{0,1,2,3,4,5,6,7,8,9}{0,1,2,3,4,5,6,7,8,9}
273         
274     # unmount the FS
275     _full "umount"
276     umount $SCRATCH_DEV >>$seq.full 2>&1 \
277         || _fail "umount failed"
278
279 }
280
281 _cmp_output()
282 {
283     echo "*** compare logprint: $1 with $2"
284     if ! diff $1 $2 >/dev/null; then
285         echo "FAILED: logprint output $1 differs to $2"
286         touch $tmp.error
287     fi
288 }
289
290 _clear_opts()
291 {
292     # clear opts
293     # - remove the log options in mkfs
294     # - remove the log options in mount
295     # - remove the quota options in mount
296     # leave any other options given
297     MKFS_OPTIONS=`echo $MKFS_OPTIONS | sed -e 's/-l[ ]*[^ $]*//g'`
298     MOUNT_OPTIONS=`echo $MOUNT_OPTIONS |\
299             sed -e 's/logbsize=[^ ,]*,*//g' \
300                 -e 's/usrquota,*//g'        \
301                 -e 's/grpquota,*//g'        \
302                 -e 's/quota,*//g'           \
303                 -e 's/uqnoenforce,*//g'     \
304                 -e 's/gqnoenforce,*//g'     \
305                 -e 's/-o *$//g'             \
306                 -e 's/-o *-/-/g'            \
307                 `
308         
309     # export opts
310     export MKFS_OPTIONS
311     export MOUNT_OPTIONS
312 }
313
314 #
315 # Op data of different Log Record sizes will mean that data is
316 # split at different points and in op printing it will not
317 # try and decode the data which has been split up.
318 # So we do a special diff processing to complain of differences
319 # if no split is involved.
320 #
321 # Example diff with forms of:
322 # "Left over region from split log item"
323 # "Not printing rest of data"
324 #
325 #   2149c2149
326 #   < Left over region from split log item
327 #   ---
328 #   > BUF DATA
329 #   2888c2888,2889
330 #   < INODE: #regs: 3 Not printing rest of data
331 #   ---
332 #   > INODE: #regs: 3 ino: 0x80 flags: 0x5 dsize: 16
333 #   >  blkno: <BLKNO> len:<LEN> boff: <BOFF>
334 #
335 _process_op_diff()
336 {
337     $AWK_PROG <$1 '
338         BEGIN { num_splits = 1 }
339         /^[0-9]/ {
340
341                 # ensure cmd is a change op
342                 cmd = $1
343                 gsub(/[0-9][0-9]*/,"", cmd)
344                 gsub(/,/,"", cmd)
345                 if (cmd != "c") {
346                         print "bad diff cmd: ", $0
347                         exit 1
348                 }
349
350                 # ensure a split happened in previous difference
351                 if (num_splits != 1 && num_splits != 2) {
352                         print num_splits, " split(s) found prior to diff cmd: ", $0
353                         num_splits = 1 # shut-up end condition
354                         exit 1
355                 }
356                 num_splits = 0
357
358                 next
359         }
360         /Left over region/ || /Not printing rest/ { 
361                 num_splits++
362                 next
363         }
364         { next }
365         END { 
366                 if (num_splits != 1 && num_splits != 2) {
367                         print num_splits, " split(s) found prior to diff end"
368                         exit 1
369                 }
370         }
371     '
372     return $?
373 }
374
375 _cmp_op_output()
376 {
377     echo "*** compare logprint: $1 with $2"
378
379     diff $1 $2 >$filtered.diff
380     if ! _process_op_diff $filtered.diff
381     then
382         echo "FAILED: logprint output $1 differs to $2 considering splits"
383         touch $tmp.error
384     fi
385 }
386
387
388 # real QA test starts here
389
390 # prelim
391 rm -f $seq.full $tmp.*
392 _require_scratch
393 _clear_opts
394 echo "*** init FS"
395 umount $SCRATCH_DEV >/dev/null 2>&1
396
397 cat >$tmp.seq.params <<EOF
398 # mkfs-opt        mount-opt            start-blk
399   -lversion=1     -ologbsize=32k       2
400   -lversion=2     -ologbsize=32k       2
401   -lversion=2     -ologbsize=64k       2
402   -lversion=2     -ologbsize=128k      2
403   -lversion=2     -ologbsize=256k      2
404 # NB: Stripe only affects LRs which weren't full when written out
405 #     So if we wrote out 32K LR then the stripe has no effect
406 #     In our case, it is likely that the LRs will be full but
407 #     it may no be the case in all QA environments where the LR
408 #     may be forced out early.
409   -lversion=2,su=4096 -ologbsize=32k   8
410 EOF
411
412 # do the work for various log params which
413 # should not effect the data content of the log
414 cat $tmp.seq.params \
415 | while read mkfs mnt start
416 do
417     if [ "$mkfs" != "#" ]; then 
418         _mkfs_create_log $mkfs $mnt
419         _check_log
420
421         _print_operation
422         _cmp_op_output $seq.noquota.op $filtered
423
424         _print_transaction_inode $start
425         _cmp_output $seq.noquota.trans_inode $filtered
426
427         _print_transaction_buf $start
428         _cmp_output $seq.noquota.trans_buf $filtered
429     fi
430 done
431
432 # do a simple quota test to ensure DQUOT data is happening
433 mkfs="-lversion=1"
434 mnt="-ousrquota,grpquota"
435 _mkfs_create_log $mkfs $mnt
436 _check_log
437 _print_transaction_inode 2
438 _cmp_output $seq.ugquota.trans_inode $filtered
439
440 # got thru it all so we may have success
441 if [ ! -e $tmp.error ]; then
442     status=0
443 fi
444
445 exit