5be5411a5b5950a42fe184f5632a394a2ccc3032
[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 _print_logstate()
232 {
233     case "$FSTYP" in
234     xfs)
235         dirty=$(_scratch_xfs_logstate)
236         ;;
237     f2fs)
238         dirty=$(_scratch_f2fs_logstate)
239         ;;
240     *)
241         ;;
242     esac
243
244     if [ $dirty -ne 0 ]; then
245         echo "dirty log"
246     else
247         echo "clean log"
248     fi
249 }
250
251 _print_operation()
252 {
253     mkdir $fulldir >/dev/null 2>&1
254     mntopt=`echo $MOUNT_OPTIONS | sed 's/ //g'`
255     mkfsopt=`echo $MKFS_OPTIONS | sed 's/ //g'`
256     raw=$fulldir/op.mnt$mntopt.mkfs$mkfsopt$sync_suffix.raw
257     filtered=$fulldir/op.mnt$mntopt.mkfs$mkfsopt$sync_suffix.filtered
258
259     echo "### xfs_logprint output ###" | tee $raw >$filtered
260     _scratch_xfs_logprint -c  2>&1 \
261     | tee -a $raw      \
262     | _filter_logprint \
263     | _filter_opnum    \
264     >>$filtered
265 }
266
267 # start at rec#2 "-s 2" so we skip over UMOUNT record which will always
268 # be a 512b single header at mkfs time
269 # and may not match with the FS mounted at a different LR size 
270 # => xlog_do_recovery_pass() can not handle the different hdr sizes
271 #    it assumes them all to be the same between the start..finish
272 # NB: On IRIX there is no UMOUNT record and so we could start from -s 0.
273
274 _print_transaction_inode()
275 {
276     _start=$1
277     mkdir $fulldir >/dev/null 2>&1
278     mntopt=`echo $MOUNT_OPTIONS | sed 's/ //g'`
279     mkfsopt=`echo $MKFS_OPTIONS | sed 's/ //g'`
280     raw=$fulldir/trans_inode.mnt$mntopt.mkfs$mkfsopt$sync_suffix.raw
281     filtered=$fulldir/trans_inode.mnt$mntopt.mkfs$mkfsopt$sync_suffix.filtered
282
283     echo "### xfs_logprint -t -i -s START output ###" | tee $raw >$filtered
284     _scratch_xfs_logprint -t -i -s $_start 2>&1 \
285     | tee -a $raw      \
286     | _filter_logprint \
287     >>$filtered
288 }
289
290 _print_transaction_buf()
291 {
292     _start=$1
293     mkdir $fulldir >/dev/null 2>&1
294     mntopt=`echo $MOUNT_OPTIONS | sed 's/ //g'`
295     mkfsopt=`echo $MKFS_OPTIONS | sed 's/ //g'`
296     raw=$fulldir/trans_buf.mnt$mntopt.mkfs$mkfsopt$sync_suffix.raw
297     filtered=$fulldir/trans_buf.mnt$mntopt.mkfs$mkfsopt$sync_suffix.filtered
298
299     echo "### xfs_logprint -t -b -s START output ###" | tee $raw >$filtered
300     _scratch_xfs_logprint -t -b -s $_start 2>&1 \
301     | tee -a $raw      \
302     | _filter_logprint \
303     >>$filtered
304 }
305
306 _mkfs_log()
307 {
308     # create the FS
309     # mkfs options to append to log size otion can be specified ($*)
310     export MKFS_OPTIONS="-l size=2000b -l lazy-count=1 $*"
311     _full "mkfs"
312     _scratch_mkfs_xfs >>$seqres.full 2>&1
313     if [ $? -ne 0 ] ; then 
314         _echofull "Cannot mkfs for this test using option specified: $MKFS_OPTIONS"
315         return 1
316     fi  
317
318     return 0
319 }
320
321
322 #
323 # mount fs and create some log traffic
324 #
325 _create_log()
326 {
327     # mount the FS
328     _full "mount"
329     _scratch_mount >>$seqres.full 2>&1
330     if [ $? -ne 0 ] ; then 
331         _echofull "mount failed: $MOUNT_OPTIONS"
332         return 1
333     fi
334
335     # generate some log traffic - but not too much - life gets a little
336     # more complicated if the log wraps around. This traffic is
337     # pretty much arbitary, but could probably be made better than this.
338     touch $SCRATCH_MNT/{0,1,2,3,4,5,6,7,8,9}{0,1,2,3,4,5,6,7,8,9}
339         
340     # unmount the FS
341     _full "umount"
342     umount $SCRATCH_DEV >>$seqres.full 2>&1
343     if [ $? -ne 0 ] ; then 
344         _echofull "umount failed"
345         return 1
346     fi
347
348     return 0
349 }
350
351 #
352 # mount fs and create some log traffic with sync'ing
353 #
354 _create_log_sync()
355 {
356     # mount the FS
357     _full " mount"
358     _scratch_mount >>$seqres.full 2>&1
359     if [ $? -ne 0 ] ; then 
360         _echofull "mount failed: $MOUNT_OPTIONS"
361         return 1
362     fi
363
364     # generate some log traffic - but not too much
365     # add some syncs to get the log flushed to disk 
366     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
367         touch $file
368         sync
369     done
370
371     # unmount the FS
372     _full "umount"
373     umount $SCRATCH_DEV >>$seqres.full 2>&1
374     if [ $? -ne 0 ] ; then 
375         _echofull "umount failed"
376         return 1
377     fi
378 }
379
380 _cmp_output()
381 {
382     echo "*** compare logprint: $1 with $2"
383     if ! diff $1 $2 >/dev/null; then
384         _fail "logprint output $1 differs to $2"
385     fi
386 }
387
388 #
389 # Op data of different Log Record sizes will mean that data is
390 # split at different points and in op printing it will not
391 # try and decode the data which has been split up.
392 # So we do a special diff processing to complain of differences
393 # if no split is involved.
394 #
395 # Example diff with forms of:
396 # "Left over region from split log item"
397 # "Not printing rest of data"
398 #
399 #   2149c2149
400 #   < Left over region from split log item
401 #   ---
402 #   > BUF DATA
403 #   2888c2888,2889
404 #   < INODE: #regs: 3 Not printing rest of data
405 #   ---
406 #   > INODE: #regs: 3 ino: 0x80 flags: 0x5 dsize: 16
407 #   >  blkno: <BLKNO> len:<LEN> boff: <BOFF>
408 #
409 _process_op_diff()
410 {
411     $AWK_PROG <$1 '
412         BEGIN { num_splits = 1; max_splits = 50 }
413         /^[0-9]/ {
414
415                 # ensure a split happened in previous difference
416                 if (num_splits < 1 || num_splits > max_splits) {
417                         print num_splits, " split(s) found prior to diff cmd: ", $0
418                         num_splits = 1 # shut-up end condition
419                         exit 1
420                 }
421                 num_splits = 0
422
423                 next
424         }
425         /Left over region/ || /Not printing rest/ { 
426                 num_splits++
427                 next
428         }
429         { next }
430         END { 
431                 if (num_splits < 1 || num_splits > max_splits) {
432                         print num_splits, " split(s) found prior to diff end"
433                         exit 1
434                 }
435         }
436     '
437     return $?
438 }
439
440 _cmp_op_output()
441 {
442     echo "*** compare logprint: $1 with $2"
443
444     diff $1 $2 >$filtered.diff
445     if ! _process_op_diff $filtered.diff
446     then
447         _fail "logprint output $1 differs to $2 considering splits"
448     fi
449 }
450
451 # return xfs log version of device
452 # e.g.
453 #   _log_version /dev/dsk/dks0d1s4
454 #
455 _log_version()
456 {
457     _dev=$1 
458     vers=`xfs_db -c 'sb 0' -c 'p versionnum' -r $_dev | $AWK_PROG '{print $3}'`
459     logver=`echo $vers | sed -e 's/0x[0-9a-f]\([0-9a-f]\)[0-9a-f][0-9a-f]/\1/'` 
460     if [ $logver = 4 -o $logver = 5 -o $logver = 6 -o $logver = 7 -o \
461          $logver = c -o $logver = d -o $logver = e -o $logver = f ]; then
462         echo 2
463     else
464         echo 1
465     fi
466 }
467
468 _require_v2log()
469 {
470     # test out mkfs to see if it supports "-l version=2"
471     export MKFS_OPTIONS="-l version=2"
472     if ! _scratch_mkfs_xfs >>$seqres.full 2>&1; then
473         _notrun "mkfs does not support v2 logs"
474     fi
475
476     # test out mount to see if it mounts a v2 log fs
477     export MOUNT_OPTIONS="-o logbsize=32k"
478     if ! _scratch_mount >>$seqres.full 2>&1; then
479         _notrun "mount/kernel does not support v2 logs"
480     fi
481
482     # check after unmount to see if it is clean
483     # i.e. it is not a 6.5.25 buggy version checking kernel
484     touch $SCRATCH_MNT/file
485     umount $SCRATCH_DEV >>$seqres.full 2>&1
486     if _scratch_xfs_logprint -t | tee -a $seqres.full \
487         | head | grep -q "<DIRTY>"; then
488         _notrun "kernel does not support v2 logs"
489     fi
490  
491     # otherwise presume it does support v2 logs...:)
492 }
493
494 _require_logstate()
495 {
496     case "$FSTYP" in
497     xfs)
498         if [ -z "$XFS_LOGPRINT_PROG" ]; then
499             _notrun "This test requires xfs_logprint utility."
500         fi
501         ;;
502     f2fs)
503         if [ -z "$DUMP_F2FS_PROG" ]; then
504             _notrun "This test requires dump.f2fs utility."
505         fi
506         ;;
507     *)
508         _notrun "$FSTYP does not support log state probing."
509         ;;
510     esac
511 }
512
513 _xfs_log_config()
514 {
515     echo "# mkfs-opt             mount-opt"
516     echo "# ------------------------------"
517     echo "  version=2            logbsize=32k"
518     echo "  version=2,su=4096    logbsize=32k"
519     echo "  version=2,su=32768   logbsize=32k"
520     echo "  version=2,su=32768   logbsize=64k"
521     echo "  version=2            logbsize=64k"
522     echo "  version=2,su=64k     logbsize=64k"
523     echo "  version=2            logbsize=128k"
524     echo "  version=2,su=128k    logbsize=128k"
525     echo "  version=2            logbsize=256k"
526     echo "  version=2,su=256k    logbsize=256k"
527 }
528
529 _f2fs_log_config()
530 {
531     echo "# mkfs-opt             mount-opt"
532     echo "# ------------------------------"
533     echo "  test1     active_logs=6,background_gc=off"
534     echo "  test2     active_logs=6,background_gc=off,inline_data"
535     echo "  test3     active_logs=6,background_gc=off,inline_dentry"
536     echo "  test4     active_logs=6,background_gc=off,inline_data,inline_dentry"
537     echo "  test5     active_logs=6,background_gc=off,disable_roll_forward"
538     echo "  test6     active_logs=6,background_gc=off,discard,inline_data,inline_dentry"
539     echo "  test7     active_logs=6,background_gc=on"
540     echo "  test8     active_logs=6,background_gc=on,inline_data"
541     echo "  test9     active_logs=6,background_gc=on,inline_data,inline_dentry"
542     echo "  test10    active_logs=6,background_gc=on,discard,inline_data,inline_dentry"
543 }
544
545 _get_log_configs()
546 {
547     case "$FSTYP" in
548     xfs)
549         _xfs_log_config
550         ;;
551     f2fs)
552         _f2fs_log_config
553         ;;
554     *)
555         _notrun "$FSTYP does not support log configs."
556         ;;
557     esac
558 }
559
560 # make sure this script returns success
561 /bin/true