46304e7c6a6642278ba666b916670d0f01f78f97
[xfstests-dev.git] / crash / xfscrash
1 #!/bin/sh
2 #
3 # Copyright (c) 2000-2001 Silicon Graphics, Inc.  All Rights Reserved.
4 #
5 # This program is free software; you can redistribute it and/or modify it
6 # under the terms of version 2 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, but
10 # WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 #
13 # Further, this software is distributed without any warranty that it is
14 # free of the rightful claim of any third person regarding infringement
15 # or the like.  Any license provided herein, whether implied or
16 # otherwise, applies only to this software file.  Patent licenses, if
17 # any, provided herein do not apply to combinations of this program with
18 # other software, or any other product whatsoever.
19 #
20 # You should have received a copy of the GNU General Public License along
21 # with this program; if not, write the Free Software Foundation, Inc., 59
22 # Temple Place - Suite 330, Boston MA 02111-1307, USA.
23 #
24 # Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
25 # Mountain View, CA  94043, or:
26 #
27 # http://www.sgi.com
28 #
29 # For further information regarding this notice, see:
30 #
31 # http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
32 #
33 # xfscrash - control the XFS crash tests
34 #
35
36   #######################
37 ### configuration stuff ########################################################
38   #######################
39
40 # remount, repair or corrupt
41 MODE=remount
42 # where to find xfscrash
43 XFSCRASH=/xfscrash
44 # put log files here
45 LOG=$XFSCRASH
46 # put output to these places
47 OUTPUT="$LOG/xfscrash.log /dev/tty1 /dev/console"
48 # awk...
49 AWK_PROG=gawk
50 # clear FS if >= this percent full at start of run. 100 is a good
51 # number - only used on corrupt test so far
52 FULL_LIMIT=80
53   
54 case `hostname -s`
55 in
56     leesa)
57         # mount test partition here
58         TEST_MNT=/mnt/arch0
59         # build test partition here
60         TEST_DEV=/dev/hda6
61         # backup test partition to here (or empty)
62         BACKUP_DEV=/dev/hda8
63         # backup block size for dd
64         BACKUP_BS=1024k
65         # base stress time
66         STRESS_TIME=60
67         # stress random time
68         STRESS_RANDOM=60
69         ;;
70     lumpy)
71         # mount test partition here
72         TEST_MNT=/mnt/scratch_0
73         # build test partition here
74         TEST_DEV=/dev/sdc5
75         # backup test partition to here (or empty)
76         BACKUP_DEV=  ;#/dev/sdc6
77         # backup block size for dd
78         BACKUP_BS=10240k
79         # base stress time
80         STRESS_TIME=360
81         # stress random time
82         STRESS_RANDOM=360
83         ;;
84     *)
85         echo "!!! no configuration data for host `hostname -s`"
86         exit 1
87         ;;
88 esac
89
90 # avoid stress
91
92 AVOID="-f resvsp=0 -f unresvsp=0"
93
94 # DIY stress command
95 STRESS="/usr/local/bin/fsstress -d $TEST_MNT/stress -n 10000000 -p 1 $AVOID"
96 #STRESS="/usr/local/bin/randholes -l 10000000 -c 100000 -b 512 $TEST_MNT/stress/holes"
97
98 # stress command for the corrupt test
99 CORRUPT_STRESS="/usr/local/bin/fsstress -d $TEST_MNT/stress -n 10000 -p 1 $AVOID"
100
101 ###########################################################################
102
103 reboot=-1
104
105 _log()
106 {
107     tee -a $OUTPUT > /dev/null
108 }
109
110 _echo()
111 {
112     echo "$*" | _log
113 }
114
115 _mount()
116 {
117     _echo "   *** Mounting $TEST_DEV on $TEST_MNT"
118     if ! mount -t xfs $TEST_DEV $TEST_MNT
119     then
120         _echo "   !!! unable to mount"
121         exit 1
122     fi
123 }
124
125 _unmount()
126 {
127     _echo "   *** Unmounting $TEST_DEV"
128     if ! umount $TEST_DEV &> /dev/null
129     then
130         _echo "   !!! unable to unmount"
131         exit 1
132     fi
133 }
134
135 _check()
136 {
137     expect=$1
138     fail=0
139     
140     if [ $expect -eq 0 ]
141     then
142         _echo "   *** Checking FS (expecting clean fs)"
143     else
144         _echo "   *** Checking FS (expecting dirty fs)"
145     fi
146     
147     
148     if [ $expect -eq 0 ]
149     then
150         _echo "      *** xfs_check ($LOG/check_clean.out)"   
151         xfs_check $TEST_DEV &> $LOG/check_clean.out || fail=1
152         [ -s /tmp/xfs_check_clean.out ] && fail=1
153     else
154         _echo "      *** xfs_check ($LOG/check_dirty.out)"   
155         xfs_check $TEST_DEV &> $LOG/check_dirty.out || fail=1
156     fi
157     
158     if [ $fail -eq 0 -a $expect -eq 0 ]
159     then
160         _echo "      *** xfs_repair -n ($LOG/repair_clean.out)"   
161         xfs_repair -n $TEST_DEV &> $LOG/repair_clean.out || fail=1
162     fi
163     
164     if [ $fail -eq 0 ]
165     then
166         _echo "         *** FS checks ok"
167     else
168         if [ $expect -eq 0 ]
169         then
170             _echo "         !!! FS check failed - inconsistent FS"
171             _echo "         !!! (see $LOG/*.out for details)"
172             exit 1
173         else
174             _echo "         *** inconsistent fs (as expected)"
175         fi
176     fi
177 }
178
179 _check_core()
180 {        
181     if [ -e core ]
182     then
183         _echo "   !!! core file found!"
184         exit 1
185     fi
186 }
187
188 _repair()
189 {
190     rm -f core
191     _echo "   *** repair"
192     _echo "      *** repair pass 1 (RO)"
193     xfs_repair -n $TEST_DEV &> $LOG/repair_1.out \
194         && _echo "         !!! no errors found (eh?)" \
195         || _echo "         *** errors found (expected)"
196         
197     _check_core
198         
199     _echo "      *** repair pass 2 (RW)"
200     
201     if xfs_repair $TEST_DEV &> $LOG/repair_2.out
202     then
203         _echo "         *** FS checks ok (now)"
204     else
205         _echo "         !!! xfs_repair returned error code"
206         _echo "         !!! (see $LOG/repair_*.out for details)"
207         exit 1
208     fi
209         
210     _check_core
211         
212     _echo "      *** repair pass 3 (RO)"
213     if xfs_repair -n $TEST_DEV &> $LOG/repair_3.out
214     then
215         _echo "         *** FS checks ok"
216     else
217         _echo "         !!! errors found after repair (unexpected)"
218         _echo "         !!! (see $LOG/repair_*.out for details)"
219         exit 1
220     fi
221
222     _check_core
223 }
224
225 _cleanup()
226 {
227     rm -f $XFSCRASH/counter $XFSCRASH/start $XFSCRASH/stop $XFSCRASH/active 
228     
229     if [ $reboot != -1 ]
230     then
231         kill $reboot
232     fi
233     
234 }
235
236 _random()
237 {
238     od -tu -N 4 /dev/random | gawk -v v=$1 'NR==1 { print $2 % v }'
239 }
240
241 _backup()
242 {
243     if [ $count -ne 1 -a "$BACKUP_DEV" != "" ]
244     then
245         _echo "   *** Backing up $TEST_DEV to $BACKUP_DEV"
246         if ! dd if=$TEST_DEV of=$BACKUP_DEV bs=$BACKUP_BS &> $LOG/dd.out
247         then
248             _echo "   !!! unable to backup fs"
249             _echo "   !!! (see $LOG/dd.out)"
250             exit 1
251         fi
252     else
253         _echo "   *** skipping back up step"
254     fi
255 }
256
257 _logprint()
258 {
259     _echo "   *** dumping log to $LOG/logprint.out"
260     rm -f core
261     xfs_logprint $TEST_DEV &> $LOG/logprint.out
262     if [ -e core ]
263     then
264         _echo "      !!! xfs_logprint dumped core"
265         echo "" >> $LOG/logprint.out
266         echo "*** CORE DUMPED ***" >> $LOG/logprint.out
267         echo "" >> $LOG/logprint.out
268     fi
269     
270     _echo "   *** dumping log (-t -i) to $LOG/logprint_inode.out"
271     
272     rm -f core
273     xfs_logprint -t -i $TEST_DEV &> $LOG/logprint_inode.out
274     if [ -e core ]
275     then
276         _echo "      !!! xfs_logprint dumped core"
277         echo "" >> $LOG/logprint_inode.out
278         echo "*** CORE DUMPED ***" >> $LOG/logprint_inode.out
279         echo "" >> $LOG/logprint_inode.out
280     fi
281     
282     _echo "   *** dumping log (-t -b) to $LOG/logprint_buf.out"
283     
284     rm -f core
285     xfs_logprint -t -b $TEST_DEV &> $LOG/logprint_buf.out
286     if [ -e core ]
287     then
288         _echo "      !!! xfs_logprint dumped core"
289         echo "" >> $LOG/logprint_buf.out
290         echo "*** CORE DUMPED ***" >> $LOG/logprint_buf.out
291         echo "" >> $LOG/logprint_buf.out
292     fi
293 }
294 #
295 # _df_device : get an IRIX style df line for a given device 
296 #
297 #       - returns "" if not mounted
298 #       - returns fs type in field two (ala IRIX)
299 #       - joins line together if split by fancy df formatting
300 #       - strips header etc
301 #
302
303 _df_device()
304 {
305     if [ $# -ne 1 ]
306     then
307         echo "Usage: _df_device device" >&2
308         exit 1
309     fi
310     
311     df -T 2> /dev/null | $AWK_PROG -v what=$1 '
312         match($1,what) && NF==1 { 
313             v=$1
314             getline
315             print v, $0
316             exit
317         }
318         match($1,what) {
319             print
320             exit
321         }
322     '
323 }
324
325 #
326 # _df_dir : get an IRIX style df line for device where a directory resides
327 #
328 #       - returns fs type in field two (ala IRIX)
329 #       - joins line together if split by fancy df formatting
330 #       - strips header etc
331 #
332
333 _df_dir()
334 {
335     if [ $# -ne 1 ]
336     then
337         echo "Usage: _df_dir device" >&2
338         exit 1
339     fi
340     
341     df -T $1 2> /dev/null | $AWK_PROG -v what=$1 '
342         NR == 2 && NF==1 { 
343             v=$1
344             getline 
345             print v, $0;
346             exit 0
347         }
348         NR == 2 {
349             print;
350             exit 0
351         }
352         {}
353     '
354     # otherwise, nada
355 }
356
357 # return percentage used disk space for mounted device
358
359 _used()
360 {
361     if [ $# -ne 1 ]
362     then
363         echo "Usage: _used device" >&2
364         exit 1
365     fi
366     
367     _df_device $1 | $AWK_PROG '{ sub("%", "") ; print $6 }'
368 }
369
370 _check_free()
371 {
372      used=`_used $TEST_DEV`
373
374      if [ $used -ge $FULL_LIMIT ]    
375      then
376          _echo "      *** $used % used on $TEST_DEV - deleting files"
377          rm -rf $TEST_MNT/stress
378      fi
379 }       
380
381 # loop, stressing, unounting and checking
382 # no (expected) rebooting...
383 _corrupt()
384 {
385     count=0
386     
387     # don't want to restart if we reboot...
388     _cleanup
389     
390     while true
391     do
392
393         if [ -e $XFSCRASH/stop ]
394         then
395             _echo "### XFS Crash stopped "
396             exit 0
397         fi
398
399         _echo "*** run $count"
400         let "count = count + 1"
401         
402         _check 0
403         _mount
404         
405         _check_free
406         
407         $CORRUPT_STRESS | _log
408         
409         _unmount        
410     done
411 }
412
413 ###########################################################################
414     
415 _echo ""
416 _echo ""
417 echo "XFSCRASH [output to $OUTPUT]"
418 _echo ""
419
420 if [ "$1" = "start" ]
421 then
422     touch $XFSCRASH/start
423 fi
424
425 if [ "$1" = "stop" ]
426 then
427     touch $XFSCRASH/stop
428 fi
429
430
431 trap "_cleanup; exit \$status" 0 1 2 3 15
432
433
434 if [ -e $XFSCRASH/stop ]
435 then
436     _echo "### XFS Crash stopped "
437     exit 0
438 fi
439
440 if [ -e $XFSCRASH/start ]
441 then
442     _echo "### XFS Crash started "
443     _cleanup
444     rm -f $LOG/*.out $LOG/*.log core
445     
446     touch $XFSCRASH/active
447
448     _echo "   *** Building fresh XFS FS"
449     umount $TEST_DEV &> /dev/null
450     if ! mkfs -t xfs -f $TEST_DEV &> $LOG/mkfs.out
451     then
452         _echo "   !!! unable to mkfs"
453         _echo "   !!! (see $LOG/mkfs.out)"
454         exit 1
455     fi
456 fi
457
458 if [ ! -e $XFSCRASH/active ]
459 then
460     _echo "### XFS Crash inactive "
461     exit 0
462 fi
463
464
465 if [ -r $XFSCRASH/counter ]
466 then
467     count=`cat $XFSCRASH/counter`
468 else
469     count=0
470 fi
471 _echo "### Crash test run $count (mode=$MODE, log=$LOG/{*.out,*.log})"
472
473 let "count = count +1"
474 echo $count > $XFSCRASH/counter
475
476 # real test starts here
477
478 _echo "   *** Checking for R/O root"
479 if ! mount | grep "on / type" | grep -q "(ro)"
480 then
481     _echo "   !!! root not mounted readonly"
482     exit 1
483 fi
484
485 _echo "   *** Loading XFS modules"
486 if ! modprobe xfs
487 then
488     _echo "   !!! unable to modprobe xfs"
489     exit 1
490 fi
491
492 _echo "   *** Unmounting $TEST_DEV"
493 umount $TEST_DEV &> /dev/null
494
495 _logprint
496 if [ $MODE != "corrupt" ]
497 then
498     _backup
499 fi
500
501 case $MODE
502 in
503     remount)
504         _check 1 # expect errors
505         _mount
506         _unmount
507         ;;
508     repair)
509         _repair
510         ;;
511     corrupt)
512         _corrupt
513         exit 0
514         ;;
515     *)
516         _echo "xfscrash: MODE must be remount or repair"
517         exit 1
518         ;;
519 esac
520
521 _check 0 # don't expect errors
522 _mount
523
524 _echo "   *** Cleaning XFS FS"
525 if ! rm -rf $TEST_MNT/stress $TEST_MNT/lost+found &> $LOG/clean.out
526 then
527     _echo "   !!! unable to clean XFS FS"
528     _echo "   !!! (see $LOG/clean.out)"
529     exit 1
530 fi
531
532 _echo "   *** Making stress directory"
533 if ! mkdir $TEST_MNT/stress
534 then
535     _echo "   !!! unable to mkdir stress"
536     exit 1
537 fi
538
539 let "bang = STRESS_TIME + `_random $STRESS_RANDOM`"
540
541 _echo "   *** Preparing random reboot (in $bang seconds)"
542 (
543     sleep $bang
544     _echo "      *** BANG ****"
545     reboot -fn
546 ) &
547 reboot=$!
548
549 _echo "   *** Causing stress & waiting for the inevitable"
550 $STRESS | _log
551
552 exit 0