xfs: inject errors at various parts of the deferred op completion
[xfstests-dev.git] / common / log
1 ##/bin/bash
2 #
3 # Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
4 #
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License as
7 # published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it would be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write the Free Software Foundation,
16 # Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17 #
18 #
19 # common routines for log testing
20 # Created by dxm@sgi.com & tes@sgi.com
21 #
22
23 fulldir=$seqres.fulldir
24 rm -rf $fulldir
25
26 _cleanup_logfiles()
27 {
28     if [ $status -eq 0 ]; then
29         # don't keep these files around unless something went wrong
30         rm -rf $fulldir
31     fi
32 }
33
34 _full()
35 {
36     echo ""            >>$seqres.full
37     echo "*** $* ***"  >>$seqres.full
38     echo ""            >>$seqres.full
39 }
40
41 _echofull()
42 {
43     echo ""            | tee -a $seqres.full
44     echo "*** $* ***"  | tee -a $seqres.full
45     echo ""            | tee -a $seqres.full
46 }
47
48 # Handle the operations which get split over Log Record
49 # boundaries.
50 # Oper (379)..... flags: CONTINUE
51 # ...
52 # Oper (0)....... flags: WAS_CONT END
53 #
54 # or
55 #
56 # Oper (379)..... flags: none 
57 # ...
58 # Oper (0)....... flags: none 
59 #
60 _filter_opnum()
61 {
62     $AWK_PROG '
63 BEGIN { 
64         debug = 0 
65         }
66 /^Oper/ && debug {
67             printf "line = %s\n", $0
68         }
69 /^Oper/ {
70             was_cont = 0
71         }
72 /^Oper/ && /flags: CONTINUE/ { 
73             # this will be the first op of split region
74             $9 = "none" # overwrite CONTINUE flags
75             print
76             print "Not printing rest"
77             was_cont = 1
78             next        
79         }
80 /^Oper/ && /flags: WAS_CONT END/ {
81             # this will be the last op of split region
82             # skip over was-continued op
83             # we assume there can be only 1
84             was_cont = 1
85             next        
86         }
87 (was_cont == 1) { 
88             # skip over any continued op stuff
89             next
90         }
91         {print}
92     '
93 }
94
95 #
96 # Filter out things that can change
97 # We have complexities which change when log is sync'ed at different
98 # times.
99 # Example1: DATA FORK EXTENTS
100 # These will not show up if inode is sync'ed sooner
101 #       /DATA FORK EXTENTS/d;
102 #       /INODE:/s/flags:0x5/flags:0x1/g;
103 # define XFS_ILOG_CORE   0x001   /* log standard inode fields */
104 # define XFS_ILOG_DEXT   0x004   /* log i_df.if_extents */
105 #
106 #
107
108 _filter_logprint()
109 {
110     _fix_malloc |\
111     sed '
112         s/ver:[0-9]/ver:<VERS>/;
113         s/version [0-9] format [0-9]/version <VERS> format <FORMAT>/;
114         s/data device: 0x[0-9a-f][0-9a-f]*/data device: <DEVICE>/;
115         s/log device: 0x[0-9a-f][0-9a-f]*/log device: <DEVICE>/;
116         s/log file: \".*\"/log device: <DEVICE>/;
117         s/daddr: [0-9][0-9]*/daddr: <DADDR>/;
118         s/length: [0-9][0-9]*/length: <LENGTH>/;
119         s/length: [0-9][0-9]*/length: <LENGTH>/;
120         s/^cycle num overwrites: .*$/cycle num overwrites: <TIDS>/;
121         s/tid: [0-9a-f][0-9a-f]*/tid: <TID>/;
122         s/tid:0x[0-9a-f][0-9a-f]*/tid:<TID>/;
123         s/q:0x[0-9a-f][0-9a-f]*/q:<Q>/;
124         s/a:0x[0-9a-f][0-9a-f]*/a:<A>/g;
125         s/blkno:0x[0-9a-f][0-9a-f]*/blkno:<BLKNO>/g;
126         s/blkno: *[0-9][0-9]* (0x[0-9a-f]*)/blkno: <BLKNO> (<BLKNO>)/g;
127         s/blkno: *[0-9][0-9]*/blkno: <BLKNO>/g;
128         s/boff: [0-9][0-9]*/boff: <BOFF>/g;
129         s/len: *[0-9][0-9]*/len:<LEN>/g;
130         /BUF:/s/[       ]*flags:.*$//;
131         /zeroed blocks/s/[0-9][0-9]*/<COUNT>/g;
132         /cleared blocks/d;
133         /log tail/s/[0-9][0-9]*/<COUNT>/g;
134         s/atime:[0-9a-fx]*  *mtime:[0-9a-fx]*  *ctime:[0-9a-fx]*/atime:<TIME>  mtime:<TIME>  ctime:<TIME>/;
135         s/atime 0x[0-9a-f]* mtime 0x[0-9a-f]* ctime 0x[0-9a-f]*/atime <TIME>  mtime <TIME>  ctime <TIME>/;
136         s/block [0-9][0-9]*/block <BLOCK>/;
137         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>/;
138         s/sunit: *[0-9][0-9]*  *swidth: *[0-9][0-9]*/sunit:<SUNIT> swidth:<SWIDTH>/;
139         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>/;
140         s/^uuid: *[0-9a-f-][0-9a-f-]* *format: *.*$/uuid: <UUID> format: <FORMAT>/;
141         /flushiter:/d;
142         /version:/,/h_size:/d;
143         /override tail/s/[0-9][0-9]*/<TAIL_BLK>/;
144         /^---*/d;
145         /^===*/d;
146         /^~~~*/d;
147         /extended-header/d;
148         /LOG REC AT LSN/d;
149         /DATA FORK EXTENTS/d;
150         s/BUF: cnt:[1-9][0-9]* total:[1-9][0-9]*.*/BUF: cnt:C total:T/;
151         s/INO: cnt:[1-9][0-9]* total:[1-9][0-9]*.*/INO: cnt:C total:T/;
152         s/#regs: *[1-9][0-9]*/#regs:R/;
153         /INODE:/s/flags:0x5/flags:0x1/g;
154         s/Oper ([0-9][0-9]*)/Oper (OPNUM)/;
155         /^[     ]*$/d;
156         s/  */ /g;
157         s/ $//;
158         s/newino: 0x[0-9a-f]*$/newino: <INO>/g
159         s/newino:0x[0-9a-f]*$/newino:<INO>/g
160         s/ino: 0x[0-9a-f]* flags:/ino: <INO> flags:/g
161         s/ino:0x[0-9a-f]* flags:/ino:<INO> flags:/g
162         s/onlink:[0-9][0-9]*/onlink:<ONLINK>/;
163         s/gen:-*[0-9][0-9]*/gen:<GEN>/;
164         s/gen 0x[0-9a-f][0-9a-f]*/gen <GEN>/;
165     '|\
166     awk '
167         # collapse BUF DATA group into 1 line
168         # for Oper data this can be over separate operations...ughh
169         /BUF DATA/ { 
170                 if (!buf_data) { # 1st one
171                     if (oper) { 
172                         print oper
173                         oper = 0
174                     }           
175                     print
176                 }
177                 buf_data = 1
178                 oper = 0 # wont need it now
179                 next
180         }
181         /^Oper/ { 
182                 # store it as we dont know if 2nd BUF DATA is to follow
183                 if (oper) {
184                     print oper
185                 }
186                 oper = $0
187                 next
188         }
189         /^TRANS/ && dummy_rec == 1 {
190                 # start printing again - dummy transaction over
191                 dummy_rec = 0
192         }
193         /DUMMY1/ {
194                 # filter out dummy transactions
195                 dummy_rec = 1
196                 next
197         }
198         {
199                 if (dummy_rec) {
200                     next
201                 }
202                 buf_data = 0
203                 if (oper) { # now we can print out oper
204                     print oper
205                     oper = 0    
206                 }
207                 print
208         }
209     '
210 }
211
212 _check_log()
213 {
214     _full "clean_log : xfs_logprint"
215     _scratch_xfs_logprint -t | tee -a $seqres.full \
216         | head | grep -q "<CLEAN>" || _fail "DIRTY LOG"
217 }
218
219 _scratch_xfs_logstate()
220 {
221     _scratch_xfs_logprint -t | tee -a $seqres.full | grep -q "<CLEAN>"
222     echo $?
223 }
224
225 _scratch_f2fs_logstate()
226 {
227     $DUMP_F2FS_PROG $SCRATCH_DEV | tee -a $seqres.full | grep -q "unmount"
228     echo $?
229 }
230
231 _scratch_dump_log()
232 {
233         case "$FSTYP" in
234         xfs)
235                 _scratch_xfs_logprint
236                 ;;
237         f2fs)
238                 $DUMP_F2FS_PROG $SCRATCH_DEV
239                 ;;
240         *)
241                 ;;
242         esac
243 }
244
245 _test_dump_log()
246 {
247         case "$FSTYP" in
248         xfs)
249                 _test_xfs_logprint
250                 ;;
251         f2fs)
252                 $DUMP_F2FS_PROG $TEST_DEV
253                 ;;
254         *)
255                 ;;
256         esac
257 }
258
259 _print_logstate()
260 {
261     case "$FSTYP" in
262     xfs)
263         dirty=$(_scratch_xfs_logstate)
264         ;;
265     f2fs)
266         dirty=$(_scratch_f2fs_logstate)
267         ;;
268     *)
269         ;;
270     esac
271
272     if [ $dirty -ne 0 ]; then
273         echo "dirty log"
274     else
275         echo "clean log"
276     fi
277 }
278
279 _print_operation()
280 {
281     mkdir $fulldir >/dev/null 2>&1
282     mntopt=`echo $MOUNT_OPTIONS | sed 's/ //g'`
283     mkfsopt=`echo $MKFS_OPTIONS | sed 's/ //g'`
284     raw=$fulldir/op.mnt$mntopt.mkfs$mkfsopt$sync_suffix.raw
285     filtered=$fulldir/op.mnt$mntopt.mkfs$mkfsopt$sync_suffix.filtered
286
287     echo "### xfs_logprint output ###" | tee $raw >$filtered
288     _scratch_xfs_logprint -c  2>&1 \
289     | tee -a $raw      \
290     | _filter_logprint \
291     | _filter_opnum    \
292     >>$filtered
293 }
294
295 # start at rec#2 "-s 2" so we skip over UMOUNT record which will always
296 # be a 512b single header at mkfs time
297 # and may not match with the FS mounted at a different LR size 
298 # => xlog_do_recovery_pass() can not handle the different hdr sizes
299 #    it assumes them all to be the same between the start..finish
300 # NB: On IRIX there is no UMOUNT record and so we could start from -s 0.
301
302 _print_transaction_inode()
303 {
304     _start=$1
305     mkdir $fulldir >/dev/null 2>&1
306     mntopt=`echo $MOUNT_OPTIONS | sed 's/ //g'`
307     mkfsopt=`echo $MKFS_OPTIONS | sed 's/ //g'`
308     raw=$fulldir/trans_inode.mnt$mntopt.mkfs$mkfsopt$sync_suffix.raw
309     filtered=$fulldir/trans_inode.mnt$mntopt.mkfs$mkfsopt$sync_suffix.filtered
310
311     echo "### xfs_logprint -t -i -s START output ###" | tee $raw >$filtered
312     _scratch_xfs_logprint -t -i -s $_start 2>&1 \
313     | tee -a $raw      \
314     | _filter_logprint \
315     >>$filtered
316 }
317
318 _print_transaction_buf()
319 {
320     _start=$1
321     mkdir $fulldir >/dev/null 2>&1
322     mntopt=`echo $MOUNT_OPTIONS | sed 's/ //g'`
323     mkfsopt=`echo $MKFS_OPTIONS | sed 's/ //g'`
324     raw=$fulldir/trans_buf.mnt$mntopt.mkfs$mkfsopt$sync_suffix.raw
325     filtered=$fulldir/trans_buf.mnt$mntopt.mkfs$mkfsopt$sync_suffix.filtered
326
327     echo "### xfs_logprint -t -b -s START output ###" | tee $raw >$filtered
328     _scratch_xfs_logprint -t -b -s $_start 2>&1 \
329     | tee -a $raw      \
330     | _filter_logprint \
331     >>$filtered
332 }
333
334 _mkfs_log()
335 {
336     # create the FS
337     # mkfs options to append to log size otion can be specified ($*)
338     export MKFS_OPTIONS="-l size=2000b -l lazy-count=1 $*"
339     _full "mkfs"
340     _scratch_mkfs_xfs >>$seqres.full 2>&1
341     if [ $? -ne 0 ] ; then 
342         _echofull "Cannot mkfs for this test using option specified: $MKFS_OPTIONS"
343         return 1
344     fi  
345
346     return 0
347 }
348
349
350 #
351 # mount fs and create some log traffic
352 #
353 _create_log()
354 {
355     # mount the FS
356     _full "mount"
357     _scratch_mount >>$seqres.full 2>&1
358     if [ $? -ne 0 ] ; then 
359         _echofull "mount failed: $MOUNT_OPTIONS"
360         return 1
361     fi
362
363     # generate some log traffic - but not too much - life gets a little
364     # more complicated if the log wraps around. This traffic is
365     # pretty much arbitary, but could probably be made better than this.
366     touch $SCRATCH_MNT/{0,1,2,3,4,5,6,7,8,9}{0,1,2,3,4,5,6,7,8,9}
367         
368     # unmount the FS
369     _full "umount"
370     _scratch_unmount >>$seqres.full 2>&1
371     if [ $? -ne 0 ] ; then 
372         _echofull "umount failed"
373         return 1
374     fi
375
376     return 0
377 }
378
379 #
380 # mount fs and create some log traffic with sync'ing
381 #
382 _create_log_sync()
383 {
384     # mount the FS
385     _full " mount"
386     _scratch_mount >>$seqres.full 2>&1
387     if [ $? -ne 0 ] ; then 
388         _echofull "mount failed: $MOUNT_OPTIONS"
389         return 1
390     fi
391
392     # generate some log traffic - but not too much
393     # add some syncs to get the log flushed to disk 
394     for file in $SCRATCH_MNT/{0,1,2,3,4,5,6,7,8,9}{0,1,2,3,4,5,6,7,8,9}; do
395         touch $file
396         sync
397     done
398
399     # unmount the FS
400     _full "umount"
401     _scratch_unmount >>$seqres.full 2>&1
402     if [ $? -ne 0 ] ; then 
403         _echofull "umount failed"
404         return 1
405     fi
406 }
407
408 _cmp_output()
409 {
410     echo "*** compare logprint: $1 with $2"
411     if ! diff $1 $2 >/dev/null; then
412         _fail "logprint output $1 differs to $2"
413     fi
414 }
415
416 #
417 # Op data of different Log Record sizes will mean that data is
418 # split at different points and in op printing it will not
419 # try and decode the data which has been split up.
420 # So we do a special diff processing to complain of differences
421 # if no split is involved.
422 #
423 # Example diff with forms of:
424 # "Left over region from split log item"
425 # "Not printing rest of data"
426 #
427 #   2149c2149
428 #   < Left over region from split log item
429 #   ---
430 #   > BUF DATA
431 #   2888c2888,2889
432 #   < INODE: #regs: 3 Not printing rest of data
433 #   ---
434 #   > INODE: #regs: 3 ino: 0x80 flags: 0x5 dsize: 16
435 #   >  blkno: <BLKNO> len:<LEN> boff: <BOFF>
436 #
437 _process_op_diff()
438 {
439     $AWK_PROG <$1 '
440         BEGIN { num_splits = 1; max_splits = 50 }
441         /^[0-9]/ {
442
443                 # ensure a split happened in previous difference
444                 if (num_splits < 1 || num_splits > max_splits) {
445                         print num_splits, " split(s) found prior to diff cmd: ", $0
446                         num_splits = 1 # shut-up end condition
447                         exit 1
448                 }
449                 num_splits = 0
450
451                 next
452         }
453         /Left over region/ || /Not printing rest/ { 
454                 num_splits++
455                 next
456         }
457         { next }
458         END { 
459                 if (num_splits < 1 || num_splits > max_splits) {
460                         print num_splits, " split(s) found prior to diff end"
461                         exit 1
462                 }
463         }
464     '
465     return $?
466 }
467
468 _cmp_op_output()
469 {
470     echo "*** compare logprint: $1 with $2"
471
472     diff $1 $2 >$filtered.diff
473     if ! _process_op_diff $filtered.diff
474     then
475         _fail "logprint output $1 differs to $2 considering splits"
476     fi
477 }
478
479 # return xfs log version of device
480 # e.g.
481 #   _log_version /dev/dsk/dks0d1s4
482 #
483 _log_version()
484 {
485     _dev=$1 
486     vers=`xfs_db -c 'sb 0' -c 'p versionnum' -r $_dev | $AWK_PROG '{print $3}'`
487     logver=`echo $vers | sed -e 's/0x[0-9a-f]\([0-9a-f]\)[0-9a-f][0-9a-f]/\1/'` 
488     if [ $logver = 4 -o $logver = 5 -o $logver = 6 -o $logver = 7 -o \
489          $logver = c -o $logver = d -o $logver = e -o $logver = f ]; then
490         echo 2
491     else
492         echo 1
493     fi
494 }
495
496 _require_v2log()
497 {
498     # test out mkfs to see if it supports "-l version=2"
499     export MKFS_OPTIONS="-l version=2"
500     if ! _scratch_mkfs_xfs >>$seqres.full 2>&1; then
501         _notrun "mkfs does not support v2 logs"
502     fi
503
504     # test out mount to see if it mounts a v2 log fs
505     export MOUNT_OPTIONS="-o logbsize=32k"
506     if ! _scratch_mount >>$seqres.full 2>&1; then
507         _notrun "mount/kernel does not support v2 logs"
508     fi
509
510     # check after unmount to see if it is clean
511     # i.e. it is not a 6.5.25 buggy version checking kernel
512     touch $SCRATCH_MNT/file
513     _scratch_unmount >>$seqres.full 2>&1
514     if _scratch_xfs_logprint -t | tee -a $seqres.full \
515         | head | grep -q "<DIRTY>"; then
516         _notrun "kernel does not support v2 logs"
517     fi
518  
519     # otherwise presume it does support v2 logs...:)
520 }
521
522 _require_logstate()
523 {
524     case "$FSTYP" in
525     xfs)
526         if [ -z "$XFS_LOGPRINT_PROG" ]; then
527             _notrun "This test requires xfs_logprint utility."
528         fi
529         ;;
530     f2fs)
531         if [ -z "$DUMP_F2FS_PROG" ]; then
532             _notrun "This test requires dump.f2fs utility."
533         fi
534         ;;
535     *)
536         _notrun "$FSTYP does not support log state probing."
537         ;;
538     esac
539 }
540
541 _xfs_log_config()
542 {
543     echo "# mkfs-opt             mount-opt"
544     echo "# ------------------------------"
545     echo "  version=2            logbsize=32k"
546     echo "  version=2,su=4096    logbsize=32k"
547     echo "  version=2,su=32768   logbsize=32k"
548     echo "  version=2,su=32768   logbsize=64k"
549     echo "  version=2            logbsize=64k"
550     echo "  version=2,su=64k     logbsize=64k"
551     echo "  version=2            logbsize=128k"
552     echo "  version=2,su=128k    logbsize=128k"
553     echo "  version=2            logbsize=256k"
554     echo "  version=2,su=256k    logbsize=256k"
555 }
556
557 _f2fs_log_config()
558 {
559     echo "# mkfs-opt             mount-opt"
560     echo "# ------------------------------"
561     echo "  test1     active_logs=6,background_gc=off"
562     echo "  test2     active_logs=6,background_gc=off,inline_data"
563     echo "  test3     active_logs=6,background_gc=off,inline_dentry"
564     echo "  test4     active_logs=6,background_gc=off,inline_data,inline_dentry"
565     echo "  test5     active_logs=6,background_gc=off,disable_roll_forward"
566     echo "  test6     active_logs=6,background_gc=off,discard,inline_data,inline_dentry"
567     echo "  test7     active_logs=6,background_gc=on"
568     echo "  test8     active_logs=6,background_gc=on,inline_data"
569     echo "  test9     active_logs=6,background_gc=on,inline_data,inline_dentry"
570     echo "  test10    active_logs=6,background_gc=on,discard,inline_data,inline_dentry"
571 }
572
573 _get_log_configs()
574 {
575     case "$FSTYP" in
576     xfs)
577         _xfs_log_config
578         ;;
579     f2fs)
580         _f2fs_log_config
581         ;;
582     *)
583         _notrun "$FSTYP does not support log configs."
584         ;;
585     esac
586 }
587
588 # make sure this script returns success
589 /bin/true