common: create _require_test_program to look for programs in src/
[xfstests-dev.git] / common / rc
1 ##/bin/bash
2 #-----------------------------------------------------------------------
3 #  Copyright (c) 2000-2006 Silicon Graphics, Inc.  All Rights Reserved.
4 #  This program is free software; you can redistribute it and/or modify
5 #  it under the terms of the GNU General Public License as published by
6 #  the Free Software Foundation; either version 2 of the License, or
7 #  (at your option) any later version.
8 #
9 #  This program is distributed in the hope that it will 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 to the Free Software
16 #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
17 #  USA
18 #
19 #  Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
20 #  Mountain View, CA 94043, USA, or: http://www.sgi.com
21 #-----------------------------------------------------------------------
22
23 BC=$(which bc 2> /dev/null) || BC=
24
25 # Valid test names start with 3 digits "NNN":
26 #  "[0-9]\{3\}"
27 # followed by an optional "-":
28 #  "-\?"
29 # followed by an optional combination of alphanumeric and "-" chars:
30 #  "[[:alnum:]-]*"
31 # e.g. 999-the-mark-of-fstests
32 #
33 VALID_TEST_ID="[0-9]\{3\}"
34 VALID_TEST_NAME="$VALID_TEST_ID-\?[[:alnum:]-]*"
35
36 _require_math()
37 {
38         if [ -z "$BC" ]; then
39                 _notrun "this test requires 'bc' tool for doing math operations"
40         fi
41 }
42
43 _math()
44 {
45         [ $# -le 0 ] && return
46         if [ "$BC" ]; then
47                 result=$(LANG=C echo "scale=0; $@" | "$BC" -q 2> /dev/null)
48         else
49                 _notrun "this test requires 'bc' tool for doing math operations"
50         fi
51         echo "$result"
52 }
53
54 dd()
55 {
56    if [ "$HOSTOS" == "Linux" ]
57    then 
58         command dd --help 2>&1 | grep noxfer >/dev/null
59         
60         if [ "$?" -eq 0 ]
61             then
62                 command dd status=noxfer $@
63             else
64                 command dd $@
65         fi
66    else
67         command dd $@
68    fi
69 }
70
71 _btrfs_get_subvolid()
72 {
73         mnt=$1
74         name=$2
75
76         $BTRFS_UTIL_PROG sub list $mnt | grep $name | awk '{ print $2 }'
77 }
78
79 # Prints the md5 checksum of a given file
80 _md5_checksum()
81 {
82         md5sum $1 | cut -d ' ' -f1
83 }
84
85 # Write a byte into a range of a file
86 _pwrite_byte() {
87         pattern="$1"
88         offset="$2"
89         len="$3"
90         file="$4"
91         xfs_io_args="$5"
92
93         "$XFS_IO_PROG" $xfs_io_args -f -c "pwrite -S $pattern $offset $len" "$file"
94 }
95
96 # mmap-write a byte into a range of a file
97 _mwrite_byte() {
98         pattern="$1"
99         offset="$2"
100         len="$3"
101         mmap_len="$4"
102         file="$5"
103
104         "$XFS_IO_PROG" -f -c "mmap -rw 0 $mmap_len" -c "mwrite -S $pattern $offset $len" "$file"
105 }
106
107 # ls -l w/ selinux sometimes puts a dot at the end:
108 # -rwxrw-r--. id1 id2 file1
109 # Also filter out lost+found directory on extN file system if present
110
111 _ls_l()
112 {
113         ls -l $* | sed "s/\(^[-rwxdlbcpsStT]*\)\. /\1 /" | grep -v 'lost+found'
114 }
115
116 # we need common/config
117 if [ "$iam" != "check" ]
118 then
119     if ! . ./common/config
120         then
121         echo "$iam: failed to source common/config"
122         exit 1
123     fi
124 fi
125
126 # check for correct setup
127 case "$FSTYP" in
128     xfs)
129          [ "$XFS_LOGPRINT_PROG" = "" ] && _fatal "xfs_logprint not found"
130          [ "$XFS_REPAIR_PROG" = "" ] && _fatal "xfs_repair not found"
131          [ "$XFS_DB_PROG" = "" ] && _fatal "xfs_db not found"
132          [ "$MKFS_XFS_PROG" = "" ] && _fatal "mkfs_xfs not found"
133          ;;
134     udf)
135          [ "$MKFS_UDF_PROG" = "" ] && _fatal "mkfs_udf/mkudffs not found"
136          ;;
137     btrfs)
138          [ "$MKFS_BTRFS_PROG" = "" ] && _fatal "mkfs.btrfs not found"
139          ;;
140     ext4)
141          [ "$MKFS_EXT4_PROG" = "" ] && _fatal "mkfs.ext4 not found"
142          ;;
143     f2fs)
144          [ "$MKFS_F2FS_PROG" = "" ] && _fatal "mkfs.f2fs not found"
145          ;;
146     nfs)
147          ;;
148     cifs)
149          ;;
150     overlay)
151          ;;
152     reiser4)
153          [ "$MKFS_REISER4_PROG" = "" ] && _fatal "mkfs.reiser4 not found"
154          ;;
155 esac
156
157 # make sure we have a standard umask
158 umask 022
159
160 _mount()
161 {
162     $MOUNT_PROG `_mount_ops_filter $*`
163 }
164
165 _scratch_options()
166 {
167     type=$1
168     SCRATCH_OPTIONS=""
169
170     if [ "$FSTYP" != "xfs" ]; then
171         return
172     fi
173
174     case $type in
175     mkfs)
176         [ "$HOSTOS" != "IRIX" ] && SCRATCH_OPTIONS="$SCRATCH_OPTIONS -f"
177         rt_opt="-r"
178         log_opt="-l"
179         ;;
180     mount)
181         rt_opt="-o"
182         log_opt="-o"
183         ;;
184     esac
185     [ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_RTDEV" ] && \
186         SCRATCH_OPTIONS="$SCRATCH_OPTIONS ${rt_opt}rtdev=$SCRATCH_RTDEV"
187     [ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_LOGDEV" ] && \
188         SCRATCH_OPTIONS="$SCRATCH_OPTIONS ${log_opt}logdev=$SCRATCH_LOGDEV"
189 }
190
191 _test_options()
192 {
193     type=$1
194     TEST_OPTIONS=""
195
196     if [ "$FSTYP" != "xfs" ]; then
197         return
198     fi
199
200     case $type in
201     mkfs)
202         rt_opt="-r"
203         log_opt="-l"
204         ;;
205     mount)
206         rt_opt="-o"
207         log_opt="-o"
208         ;;
209     esac
210     [ "$USE_EXTERNAL" = yes -a ! -z "$TEST_RTDEV" ] && \
211         TEST_OPTIONS="$TEST_OPTIONS ${rt_opt}rtdev=$TEST_RTDEV"
212     [ "$USE_EXTERNAL" = yes -a ! -z "$TEST_LOGDEV" ] && \
213         TEST_OPTIONS="$TEST_OPTIONS ${log_opt}logdev=$TEST_LOGDEV"
214 }
215
216 _mount_ops_filter()
217 {
218     params="$*"
219     
220     #get mount point to handle dmapi mtpt option correctly
221     let last_index=$#-1
222     [ $last_index -gt 0 ] && shift $last_index
223     FS_ESCAPED=$1
224     
225     # irix is fussy about how it is fed its mount options
226     # - multiple -o's are not allowed
227     # - no spaces between comma delimitered options
228     # the sed script replaces all -o's (except the first) with a comma
229     # not required for linux, but won't hurt
230     
231     echo $params | sed -e 's/[[:space:]]\+-o[[:space:]]*/UnIqUe/1; s/[[:space:]]\+-o[[:space:]]*/,/g; s/UnIqUe/ -o /1' \
232         | sed -e 's/dmapi/dmi/' \
233         | $PERL_PROG -ne "s#mtpt=[^,|^\n|^\s]*#mtpt=$FS_ESCAPED\1\2#; print;"
234
235 }
236
237 # Used for mounting non-scratch devices (e.g. loop, dm constructs)
238 # with the safe set of scratch mount options (e.g. loop image may be
239 # hosted on $SCRATCH_DEV, so can't use external scratch devices).
240 _common_dev_mount_options()
241 {
242         echo $MOUNT_OPTIONS $SELINUX_MOUNT_OPTIONS $*
243 }
244
245 _overlay_basic_mount_options()
246 {
247         echo "-o lowerdir=$1/$OVERLAY_LOWER_DIR,upperdir=$1/$OVERLAY_UPPER_DIR,workdir=$1/$OVERLAY_WORK_DIR"
248 }
249
250 _overlay_mount_options()
251 {
252         echo `_common_dev_mount_options` \
253              `_overlay_basic_mount_options $1` \
254              $OVERLAY_MOUNT_OPTIONS
255 }
256
257 _scratch_mount_options()
258 {
259         _scratch_options mount
260
261         if [ "$FSTYP" == "overlay" ]; then
262                 echo `_overlay_mount_options $SCRATCH_DEV`
263                 return 0
264         fi
265         echo `_common_dev_mount_options $*` $SCRATCH_OPTIONS \
266                                         $SCRATCH_DEV $SCRATCH_MNT
267 }
268
269 # Given a dir, set up 3 subdirectories and mount on the given mnt.
270 # The dir is used as the mount device so it can be seen from df or mount
271 _overlay_mount()
272 {
273         local dir=$1
274         local mnt=$2
275         shift 2
276         mkdir -p $dir/$OVERLAY_UPPER_DIR
277         mkdir -p $dir/$OVERLAY_LOWER_DIR
278         mkdir -p $dir/$OVERLAY_WORK_DIR
279
280         $MOUNT_PROG -t overlay $SELINUX_MOUNT_OPTIONS \
281                     -o lowerdir=$dir/$OVERLAY_LOWER_DIR \
282                     -o upperdir=$dir/$OVERLAY_UPPER_DIR \
283                     -o workdir=$dir/$OVERLAY_WORK_DIR   \
284                     $OVERLAY_MOUNT_OPTIONS $* \
285                     $dir $mnt
286 }
287
288 _overlay_test_mount()
289 {
290         _overlay_mount $TEST_DEV $TEST_DIR $*
291 }
292
293 _overlay_scratch_mount()
294 {
295         _overlay_mount $SCRATCH_DEV $SCRATCH_MNT $*
296 }
297
298 _overlay_test_unmount()
299 {
300         $UMOUNT_PROG $TEST_DIR
301 }
302
303 _overlay_scratch_unmount()
304 {
305         $UMOUNT_PROG $SCRATCH_MNT
306 }
307
308 _scratch_mount()
309 {
310     if [ "$FSTYP" == "overlay" ]; then
311         _overlay_scratch_mount $*
312         return $?
313     fi
314     _mount -t $FSTYP `_scratch_mount_options $*`
315 }
316
317 _scratch_unmount()
318 {
319         case "$FSTYP" in
320         overlay)
321                 _overlay_scratch_unmount
322                 ;;
323         btrfs)
324                 $UMOUNT_PROG $SCRATCH_MNT
325                 ;;
326         *)
327                 $UMOUNT_PROG $SCRATCH_DEV
328                 ;;
329         esac
330 }
331
332 _scratch_remount()
333 {
334     _scratch_unmount
335     _scratch_mount
336 }
337
338 _test_mount()
339 {
340     if [ "$FSTYP" == "overlay" ]; then
341         _overlay_test_mount $*
342         return $?
343     fi
344     _test_options mount
345     _mount -t $FSTYP $TEST_OPTIONS $TEST_FS_MOUNT_OPTS $SELINUX_MOUNT_OPTIONS $* $TEST_DEV $TEST_DIR
346 }
347
348 _test_unmount()
349 {
350         if [ "$FSTYP" == "overlay" ]; then
351                 _overlay_test_unmount
352         else
353                 $UMOUNT_PROG $TEST_DEV
354         fi
355 }
356
357 _test_remount()
358 {
359     _test_unmount
360     _test_mount
361 }
362
363 _scratch_mkfs_options()
364 {
365     _scratch_options mkfs
366     echo $SCRATCH_OPTIONS $MKFS_OPTIONS $* $SCRATCH_DEV
367 }
368
369 _scratch_metadump()
370 {
371         dumpfile=$1
372         options=
373
374         [ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_LOGDEV" ] && \
375                 options="-l $SCRATCH_LOGDEV"
376
377         xfs_metadump $options $SCRATCH_DEV $dumpfile
378 }
379
380 _setup_large_xfs_fs()
381 {
382         fs_size=$1
383         local tmp_dir=/tmp/
384
385         [ "$LARGE_SCRATCH_DEV" != yes ] && return 0
386         [ -z "$SCRATCH_DEV_EMPTY_SPACE" ] && SCRATCH_DEV_EMPTY_SPACE=0
387         [ $SCRATCH_DEV_EMPTY_SPACE -ge $fs_size ] && return 0
388
389         # calculate the size of the file we need to allocate.
390         # Default free space in the FS is 50GB, but you can specify more via
391         # SCRATCH_DEV_EMPTY_SPACE
392         file_size=$(($fs_size - 50*1024*1024*1024))
393         file_size=$(($file_size - $SCRATCH_DEV_EMPTY_SPACE))
394
395         # mount the filesystem, create the file, unmount it
396         _scratch_mount 2>&1 >$tmp_dir/mnt.err
397         local status=$?
398         if [ $status -ne 0 ]; then
399                 echo "mount failed"
400                 cat $tmp_dir/mnt.err >&2
401                 rm -f $tmp_dir/mnt.err
402                 return $status
403         fi
404         rm -f $tmp_dir/mnt.err
405
406         xfs_io -F -f \
407                 -c "truncate $file_size" \
408                 -c "falloc -k 0 $file_size" \
409                 -c "chattr +d" \
410                 $SCRATCH_MNT/.use_space 2>&1 > /dev/null
411         export NUM_SPACE_FILES=1
412         status=$?
413         _scratch_unmount
414         if [ $status -ne 0 ]; then
415                 echo "large file prealloc failed"
416                 cat $tmp_dir/mnt.err >&2
417                 return $status
418         fi
419         return 0
420 }
421
422 _scratch_mkfs_xfs_opts()
423 {
424         mkfs_opts=$*
425
426         # remove crc related mkfs options if mkfs.xfs doesn't support v5 xfs
427         if [ -n "$XFS_MKFS_HAS_NO_META_SUPPORT" ]; then
428                 mkfs_opts=`echo $mkfs_opts | sed "s/-m\s\+crc=.//"`
429         fi
430
431         _scratch_options mkfs
432
433         $MKFS_XFS_PROG $SCRATCH_OPTIONS $mkfs_opts $SCRATCH_DEV
434 }
435
436
437 _scratch_mkfs_xfs_supported()
438 {
439         mkfs_opts=$*
440
441         _scratch_options mkfs
442
443         $MKFS_XFS_PROG -N $MKFS_OPTIONS $SCRATCH_OPTIONS $mkfs_opts $SCRATCH_DEV
444 }
445
446 _scratch_mkfs_xfs()
447 {
448         # extra mkfs options can be added by tests
449         local extra_mkfs_options=$*
450
451         local tmp_dir=/tmp/
452
453         # save mkfs output in case conflict means we need to run again.
454         # only the output for the mkfs that applies should be shown
455         _scratch_mkfs_xfs_opts $MKFS_OPTIONS $extra_mkfs_options \
456                 2>$tmp_dir.mkfserr 1>$tmp_dir.mkfsstd
457         local mkfs_status=$?
458
459
460         # a mkfs failure may be caused by conflicts between
461         # $MKFS_OPTIONS and $extra_mkfs_options
462         if [ $mkfs_status -ne 0 -a ! -z "$extra_mkfs_options" ]; then
463                 (
464                 echo -n "** mkfs failed with extra mkfs options "
465                 echo "added to \"$MKFS_OPTIONS\" by test $seq **"
466                 echo -n "** attempting to mkfs using only test $seq "
467                 echo "options: $extra_mkfs_options **"
468                 ) >> $seqres.full
469
470                 # running mkfs again. overwrite previous mkfs output files
471                 _scratch_mkfs_xfs_opts $extra_mkfs_options \
472                         2>$tmp_dir.mkfserr 1>$tmp_dir.mkfsstd
473                 local mkfs_status=$?
474         fi
475
476         if [ $mkfs_status -eq 0 -a "$LARGE_SCRATCH_DEV" = yes ]; then
477                 # manually parse the mkfs output to get the fs size in bytes
478                 local fs_size
479                 fs_size=`cat $tmp_dir.mkfsstd | perl -ne '
480                         if (/^data\s+=\s+bsize=(\d+)\s+blocks=(\d+)/) {
481                                 my $size = $1 * $2;
482                                 print STDOUT "$size\n";
483                         }'`
484                 _setup_large_xfs_fs $fs_size
485                 mkfs_status=$?
486         fi
487
488         # output stored mkfs output, filtering unnecessary warnings from stderr
489         cat $tmp_dir.mkfsstd
490         cat $tmp_dir.mkfserr | sed \
491                 -e '/less than device physical sector/d' \
492                 -e '/switching to logical sector/d' \
493                 >&2
494         rm -f $tmp_dir.mkfserr $tmp_dir.mkfsstd
495
496         return $mkfs_status
497 }
498
499 # xfs_check script is planned to be deprecated. But, we want to
500 # be able to invoke "xfs_check" behavior in xfstests in order to
501 # maintain the current verification levels.
502 _xfs_check()
503 {
504     OPTS=" "
505     DBOPTS=" "
506     USAGE="Usage: xfs_check [-fsvV] [-l logdev] [-i ino]... [-b bno]... special"
507
508     while getopts "b:fi:l:stvV" c
509     do
510         case $c in
511             s) OPTS=$OPTS"-s ";;
512             t) OPTS=$OPTS"-t ";;
513             v) OPTS=$OPTS"-v ";;
514             i) OPTS=$OPTS"-i "$OPTARG" ";;
515             b) OPTS=$OPTS"-b "$OPTARG" ";;
516             f) DBOPTS=$DBOPTS" -f";;
517             l) DBOPTS=$DBOPTS" -l "$OPTARG" ";;
518             V) $XFS_DB_PROG -p xfs_check -V
519                 return $?
520                 ;;
521         esac
522     done
523     set -- extra $@
524     shift $OPTIND
525     case $# in
526         1)    ${XFS_DB_PROG}${DBOPTS} -F -i -p xfs_check -c "check$OPTS" $1
527                status=$?
528                ;;
529         2)    echo $USAGE 1>&1
530               status=2
531               ;;
532     esac
533     return $status
534 }
535
536 _setup_large_ext4_fs()
537 {
538         fs_size=$1
539         local tmp_dir=/tmp/
540
541         [ "$LARGE_SCRATCH_DEV" != yes ] && return 0
542         [ -z "$SCRATCH_DEV_EMPTY_SPACE" ] && SCRATCH_DEV_EMPTY_SPACE=0
543         [ $SCRATCH_DEV_EMPTY_SPACE -ge $fs_size ] && return 0
544
545         # Default free space in the FS is 50GB, but you can specify more via
546         # SCRATCH_DEV_EMPTY_SPACE
547         space_to_consume=$(($fs_size - 50*1024*1024*1024 - $SCRATCH_DEV_EMPTY_SPACE))
548
549         # mount the filesystem and create 16TB - 4KB files until we consume
550         # all the necessary space.
551         _scratch_mount 2>&1 >$tmp_dir/mnt.err
552         local status=$?
553         if [ $status -ne 0 ]; then
554                 echo "mount failed"
555                 cat $tmp_dir/mnt.err >&2
556                 rm -f $tmp_dir/mnt.err
557                 return $status
558         fi
559         rm -f $tmp_dir/mnt.err
560
561         file_size=$((16*1024*1024*1024*1024 - 4096))
562         nfiles=0
563         while [ $space_to_consume -gt $file_size ]; do
564
565                 xfs_io -F -f \
566                         -c "truncate $file_size" \
567                         -c "falloc -k 0 $file_size" \
568                         $SCRATCH_MNT/.use_space.$nfiles 2>&1
569                 status=$?
570                 if [ $status -ne 0 ]; then
571                         break;
572                 fi
573
574                 space_to_consume=$(( $space_to_consume - $file_size ))
575                 nfiles=$(($nfiles + 1))
576         done
577
578         # consume the remaining space.
579         if [ $space_to_consume -gt 0 ]; then
580                 xfs_io -F -f \
581                         -c "truncate $space_to_consume" \
582                         -c "falloc -k 0 $space_to_consume" \
583                         $SCRATCH_MNT/.use_space.$nfiles 2>&1
584                 status=$?
585         fi
586         export NUM_SPACE_FILES=$nfiles
587
588         _scratch_unmount
589         if [ $status -ne 0 ]; then
590                 echo "large file prealloc failed"
591                 cat $tmp_dir/mnt.err >&2
592                 return $status
593         fi
594         return 0
595 }
596
597 _scratch_mkfs_ext4()
598 {
599         # extra mkfs options can be added by tests
600         local extra_mkfs_options=$*
601
602         local tmp_dir=/tmp/
603
604         $MKFS_EXT4_PROG -F $MKFS_OPTIONS $extra_mkfs_options $SCRATCH_DEV \
605                         2>$tmp_dir.mkfserr 1>$tmp_dir.mkfsstd
606         local mkfs_status=$?
607
608         # a mkfs failure may be caused by conflicts between
609         # $MKFS_OPTIONS and $extra_mkfs_options
610         if [ $mkfs_status -ne 0 -a ! -z "$extra_mkfs_options" ]; then
611                 (
612                 echo -n "** mkfs failed with extra mkfs options "
613                 echo "added to \"$MKFS_OPTIONS\" by test $seq **"
614                 echo -n "** attempting to mkfs using only test $seq "
615                 echo "options: $extra_mkfs_options **"
616                 ) >> $seqres.full
617
618                 # running mkfs again. overwrite previous mkfs output files
619                 $MKFS_EXT4_PROG -F $extra_mkfs_options $SCRATCH_DEV \
620                                 2>$tmp_dir.mkfserr 1>$tmp_dir.mkfsstd
621                 local mkfs_status=$?
622         fi
623
624         if [ $mkfs_status -eq 0 -a "$LARGE_SCRATCH_DEV" = yes ]; then
625                 # manually parse the mkfs output to get the fs size in bytes
626                 fs_size=`cat $tmp_dir.mkfsstd | awk ' \
627                         /^Block size/ { split($2, a, "="); bs = a[2] ; } \
628                         / inodes, / { blks = $3 } \
629                         /reserved for the super user/ { resv = $1 } \
630                         END { fssize = bs * blks - resv; print fssize }'`
631
632                 _setup_large_ext4_fs $fs_size
633                 mkfs_status=$?
634         fi
635
636         # output stored mkfs output
637         cat $tmp_dir.mkfserr >&2
638         cat $tmp_dir.mkfsstd
639         rm -f $tmp_dir.mkfserr $tmp_dir.mkfsstd
640
641         return $mkfs_status
642 }
643
644 _test_mkfs()
645 {
646     case $FSTYP in
647     nfs*)
648         # do nothing for nfs
649         ;;
650     cifs)
651         # do nothing for cifs
652         ;;
653     overlay)
654         # do nothing for overlay
655         ;;
656     udf)
657         $MKFS_UDF_PROG $MKFS_OPTIONS $* $TEST_DEV > /dev/null
658         ;;
659     btrfs)
660         $MKFS_BTRFS_PROG $MKFS_OPTIONS $* $TEST_DEV > /dev/null
661         ;;
662     ext2|ext3|ext4)
663         $MKFS_PROG -t $FSTYP -- -F $MKFS_OPTIONS $* $TEST_DEV
664         ;;
665     *)
666         yes | $MKFS_PROG -t $FSTYP -- $MKFS_OPTIONS $* $TEST_DEV
667         ;;
668     esac
669 }
670
671 _mkfs_dev()
672 {
673     case $FSTYP in
674     nfs*)
675         # do nothing for nfs
676         ;;
677     overlay)
678         # do nothing for overlay
679         ;;
680     udf)
681         $MKFS_UDF_PROG $MKFS_OPTIONS $* 2>$tmp_dir.mkfserr 1>$tmp_dir.mkfsstd
682         ;;
683     btrfs)
684         $MKFS_BTRFS_PROG $MKFS_OPTIONS $* 2>$tmp_dir.mkfserr 1>$tmp_dir.mkfsstd
685         ;;
686     ext2|ext3|ext4)
687         $MKFS_PROG -t $FSTYP -- -F $MKFS_OPTIONS $* \
688                 2>$tmp_dir.mkfserr 1>$tmp_dir.mkfsstd
689         ;;
690
691     *)
692         yes | $MKFS_PROG -t $FSTYP -- $MKFS_OPTIONS $* \
693                 2>$tmp_dir.mkfserr 1>$tmp_dir.mkfsstd
694         ;;
695     esac
696
697     if [ $? -ne 0 ]; then
698         # output stored mkfs output
699         cat $tmp_dir.mkfserr >&2
700         cat $tmp_dir.mkfsstd
701         status=1
702         exit 1
703     fi
704     rm -f $tmp_dir.mkfserr $tmp_dir.mkfsstd
705 }
706
707 # remove all files in $SCRATCH_MNT, useful when testing on NFS/CIFS
708 _scratch_cleanup_files()
709 {
710         case $FSTYP in
711         overlay)
712                 # $SCRATCH_DEV is a valid directory in overlay case
713                 rm -rf $SCRATCH_DEV/*
714                 ;;
715         *)
716                 _scratch_mount
717                 rm -rf $SCRATCH_MNT/*
718                 _scratch_unmount
719                 ;;
720         esac
721 }
722
723 _scratch_mkfs()
724 {
725     case $FSTYP in
726     xfs)
727         _scratch_mkfs_xfs $*
728         ;;
729     nfs*)
730         # unable to re-create NFS, just remove all files in $SCRATCH_MNT to
731         # avoid EEXIST caused by the leftover files created in previous runs
732         _scratch_cleanup_files
733         ;;
734     cifs)
735         # unable to re-create CIFS, just remove all files in $SCRATCH_MNT to
736         # avoid EEXIST caused by the leftover files created in previous runs
737         _scratch_cleanup_files
738         ;;
739     overlay)
740         # unable to re-create overlay, remove all files in $SCRATCH_MNT to
741         # avoid EEXIST caused by the leftover files created in previous runs
742         _scratch_cleanup_files
743         ;;
744     udf)
745         $MKFS_UDF_PROG $MKFS_OPTIONS $* $SCRATCH_DEV > /dev/null
746         ;;
747     btrfs)
748         $MKFS_BTRFS_PROG $MKFS_OPTIONS $* $SCRATCH_DEV > /dev/null
749         ;;
750     ext2|ext3)
751         $MKFS_PROG -t $FSTYP -- -F $MKFS_OPTIONS $* $SCRATCH_DEV
752         ;;
753     ext4)
754         _scratch_mkfs_ext4 $*
755         ;;
756     tmpfs)
757         # do nothing for tmpfs
758         ;;
759     f2fs)
760         $MKFS_F2FS_PROG $MKFS_OPTIONS $* $SCRATCH_DEV > /dev/null
761         ;;
762     *)
763         yes | $MKFS_PROG -t $FSTYP -- $MKFS_OPTIONS $* $SCRATCH_DEV
764         ;;
765     esac
766 }
767
768 _scratch_pool_mkfs()
769 {
770     case $FSTYP in
771     btrfs)
772         # if dup profile is in mkfs options call _scratch_mkfs instead
773         # because dup profile only works with single device
774         if [[ "$*" =~ dup ]]; then
775             _scratch_mkfs $*
776         else
777             $MKFS_BTRFS_PROG $MKFS_OPTIONS $* $SCRATCH_DEV_POOL > /dev/null
778         fi
779         ;;
780     *)
781         echo "_scratch_pool_mkfs is not implemented for $FSTYP" 1>&2
782         ;;
783     esac
784 }
785
786 # Create fs of certain size on scratch device
787 # _scratch_mkfs_sized <size in bytes> [optional blocksize]
788 _scratch_mkfs_sized()
789 {
790     fssize=$1
791     blocksize=$2
792
793     case $FSTYP in
794     xfs)
795         def_blksz=`echo $MKFS_OPTIONS|sed -rn 's/.*-b ?size= ?+([0-9]+).*/\1/p'`
796         ;;
797     ext2|ext3|ext4|ext4dev|udf|btrfs|reiser4)
798         def_blksz=`echo $MKFS_OPTIONS| sed -rn 's/.*-b ?+([0-9]+).*/\1/p'`
799         ;;
800     esac
801
802     [ -n "$def_blksz" ] && blocksize=$def_blksz
803     [ -z "$blocksize" ] && blocksize=4096
804
805
806     re='^[0-9]+$'
807     if ! [[ $fssize =~ $re ]] ; then
808         _notrun "error: _scratch_mkfs_sized: fs size \"$fssize\" not an integer."
809     fi
810     if ! [[ $blocksize =~ $re ]] ; then
811         _notrun "error: _scratch_mkfs_sized: block size \"$blocksize\" not an integer."
812     fi
813
814     blocks=`expr $fssize / $blocksize`
815
816     if [ "$HOSTOS" == "Linux" ]; then
817         devsize=`blockdev --getsize64 $SCRATCH_DEV`
818         [ "$fssize" -gt "$devsize" ] && _notrun "Scratch device too small"
819     fi
820
821     case $FSTYP in
822     xfs)
823         # don't override MKFS_OPTIONS that set a block size.
824         echo $MKFS_OPTIONS |egrep -q "b?size="
825         if [ $? -eq 0 ]; then
826                 _scratch_mkfs_xfs -d size=$fssize
827         else
828                 _scratch_mkfs_xfs -d size=$fssize -b size=$blocksize
829         fi
830         ;;
831     ext2|ext3|ext4|ext4dev)
832         ${MKFS_PROG}.$FSTYP -F $MKFS_OPTIONS -b $blocksize $SCRATCH_DEV $blocks
833         ;;
834     udf)
835         $MKFS_UDF_PROG $MKFS_OPTIONS -b $blocksize $SCRATCH_DEV $blocks
836         ;;
837     btrfs)
838         local mixed_opt=
839         (( fssize <= 100 * 1024 * 1024 )) && mixed_opt='--mixed'
840         $MKFS_BTRFS_PROG $MKFS_OPTIONS $mixed_opt -b $fssize $SCRATCH_DEV
841         ;;
842     reiser4)
843         # mkfs.resier4 requires size in KB as input for creating filesystem
844         $MKFS_REISER4_PROG $MKFS_OPTIONS -y -b $blocksize $SCRATCH_DEV \
845                            `expr $fssize / 1024`
846         ;;
847     f2fs)
848         # mkfs.f2fs requires # of sectors as an input for the size
849         sector_size=`blockdev --getss $SCRATCH_DEV`
850         $MKFS_F2FS_PROG $MKFS_OPTIONS $SCRATCH_DEV `expr $fssize / $sector_size`
851         ;;
852     *)
853         _notrun "Filesystem $FSTYP not supported in _scratch_mkfs_sized"
854         ;;
855     esac
856 }
857
858 # Emulate an N-data-disk stripe w/ various stripe units
859 # _scratch_mkfs_geom <sunit bytes> <swidth multiplier> [optional blocksize]
860 _scratch_mkfs_geom()
861 {
862     sunit_bytes=$1
863     swidth_mult=$2
864     blocksize=$3
865     [ -z "$blocksize" ] && blocksize=4096
866
867     let sunit_blocks=$sunit_bytes/$blocksize
868     let swidth_blocks=$sunit_blocks*$swidth_mult
869
870     case $FSTYP in
871     xfs)
872         MKFS_OPTIONS+=" -b size=$blocksize, -d su=$sunit_bytes,sw=$swidth_mult"
873         ;;
874     ext4|ext4dev)
875         MKFS_OPTIONS+=" -b $blocksize -E stride=$sunit_blocks,stripe_width=$swidth_blocks"
876         ;;
877     *)
878         _notrun "can't mkfs $FSTYP with geometry"
879         ;;
880     esac
881     _scratch_mkfs
882 }
883
884 # Create fs of certain blocksize on scratch device
885 # _scratch_mkfs_blocksized blocksize
886 _scratch_mkfs_blocksized()
887 {
888     blocksize=$1
889
890     re='^[0-9]+$'
891     if ! [[ $blocksize =~ $re ]] ; then
892         _notrun "error: _scratch_mkfs_sized: block size \"$blocksize\" not an integer."
893     fi
894
895     case $FSTYP in
896     xfs)
897         _scratch_mkfs_xfs $MKFS_OPTIONS -b size=$blocksize
898         ;;
899     ext2|ext3|ext4|ocfs2)
900         ${MKFS_PROG}.$FSTYP -F $MKFS_OPTIONS -b $blocksize $SCRATCH_DEV
901         ;;
902     *)
903         _notrun "Filesystem $FSTYP not supported in _scratch_mkfs_blocksized"
904         ;;
905     esac
906 }
907
908 _scratch_resvblks()
909 {
910         case $FSTYP in
911         xfs)
912                 xfs_io -x -c "resblks $1" $SCRATCH_MNT
913                 ;;
914         *)
915                 ;;
916         esac
917 }
918
919 _scratch_xfs_db_options()
920 {
921     SCRATCH_OPTIONS=""
922     [ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_LOGDEV" ] && \
923         SCRATCH_OPTIONS="-l$SCRATCH_LOGDEV"
924     echo $SCRATCH_OPTIONS $* $SCRATCH_DEV
925 }
926
927 _scratch_xfs_logprint()
928 {
929     SCRATCH_OPTIONS=""
930     [ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_LOGDEV" ] && \
931         SCRATCH_OPTIONS="-l$SCRATCH_LOGDEV"
932     $XFS_LOGPRINT_PROG $SCRATCH_OPTIONS $* $SCRATCH_DEV
933 }
934
935 _scratch_xfs_check()
936 {
937     SCRATCH_OPTIONS=""
938     [ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_LOGDEV" ] && \
939         SCRATCH_OPTIONS="-l $SCRATCH_LOGDEV"
940     [ "$LARGE_SCRATCH_DEV" = yes ] && \
941         SCRATCH_OPTIONS=$SCRATCH_OPTIONS" -t"
942     _xfs_check $SCRATCH_OPTIONS $* $SCRATCH_DEV
943 }
944
945 _scratch_xfs_repair()
946 {
947     SCRATCH_OPTIONS=""
948     [ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_LOGDEV" ] && \
949         SCRATCH_OPTIONS="-l$SCRATCH_LOGDEV"
950     [ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_RTDEV" ] && \
951         SCRATCH_OPTIONS=$SCRATCH_OPTIONS" -r$SCRATCH_RTDEV"
952     [ "$LARGE_SCRATCH_DEV" = yes ] && SCRATCH_OPTIONS=$SCRATCH_OPTIONS" -t"
953     $XFS_REPAIR_PROG $SCRATCH_OPTIONS $* $SCRATCH_DEV
954 }
955
956 _get_pids_by_name()
957 {
958     if [ $# -ne 1 ]
959     then
960         echo "Usage: _get_pids_by_name process-name" 1>&2
961         exit 1
962     fi
963
964     # Algorithm ... all ps(1) variants have a time of the form MM:SS or
965     # HH:MM:SS before the psargs field, use this as the search anchor.
966     #
967     # Matches with $1 (process-name) occur if the first psarg is $1
968     # or ends in /$1 ... the matching uses sed's regular expressions,
969     # so passing a regex into $1 will work.
970
971     ps $PS_ALL_FLAGS \
972     | sed -n \
973         -e 's/$/ /' \
974         -e 's/[         ][      ]*/ /g' \
975         -e 's/^ //' \
976         -e 's/^[^ ]* //' \
977         -e "/[0-9]:[0-9][0-9]  *[^ ]*\/$1 /s/ .*//p" \
978         -e "/[0-9]:[0-9][0-9]  *$1 /s/ .*//p"
979 }
980
981 # fix malloc libs output
982 #
983 _fix_malloc()
984 {
985     # filter out the Electric Fence notice
986     $PERL_PROG -e '
987         while (<>) {
988             if (defined $o && /^\s+Electric Fence/) {
989                 chomp($o);
990                 print "$o";
991                 undef $o;
992                 next;
993             }
994             print $o if (defined $o);
995
996             $o=$_;
997         }
998         print $o if (defined $o);
999     '
1000 }
1001
1002 # check if run as root
1003 #
1004 _need_to_be_root()
1005 {
1006     id=`id | $SED_PROG -e 's/(.*//' -e 's/.*=//'`
1007     if [ "$id" -ne 0 ]
1008     then
1009         echo "Arrgh ... you need to be root (not uid=$id) to run this test"
1010         exit 1
1011     fi
1012 }
1013
1014
1015 #
1016 # _df_device : get an IRIX style df line for a given device
1017 #
1018 #       - returns "" if not mounted
1019 #       - returns fs type in field two (ala IRIX)
1020 #       - joins line together if split by fancy df formatting
1021 #       - strips header etc
1022 #
1023
1024 _df_device()
1025 {
1026     if [ $# -ne 1 ]
1027     then
1028         echo "Usage: _df_device device" 1>&2
1029         exit 1
1030     fi
1031
1032     # Note that we use "==" here so awk doesn't try to interpret an NFS over
1033     # IPv6 server as a regular expression.
1034     $DF_PROG 2>/dev/null | $AWK_PROG -v what=$1 '
1035         ($1==what) && (NF==1) {
1036             v=$1
1037             getline
1038             print v, $0
1039             exit
1040         }
1041         ($1==what) {
1042             print
1043             exit
1044         }
1045     '
1046 }
1047
1048 #
1049 # _df_dir : get an IRIX style df line for device where a directory resides
1050 #
1051 #       - returns fs type in field two (ala IRIX)
1052 #       - joins line together if split by fancy df formatting
1053 #       - strips header etc
1054 #
1055
1056 _df_dir()
1057 {
1058     if [ $# -ne 1 ]
1059     then
1060         echo "Usage: _df_dir device" 1>&2
1061         exit 1
1062     fi
1063
1064     $DF_PROG $1 2>/dev/null | $AWK_PROG -v what=$1 '
1065         NR == 2 && NF==1 {
1066             v=$1
1067             getline
1068             print v, $0;
1069             exit 0
1070         }
1071         NR == 2 {
1072             print;
1073             exit 0
1074         }
1075         {}
1076     '
1077     # otherwise, nada
1078 }
1079
1080 # return percentage used disk space for mounted device
1081
1082 _used()
1083 {
1084     if [ $# -ne 1 ]
1085     then
1086         echo "Usage: _used device" 1>&2
1087         exit 1
1088     fi
1089
1090     _df_device $1 | $AWK_PROG '{ sub("%", "") ; print $6 }'
1091 }
1092
1093 # return the FS type of a mounted device
1094 #
1095 _fs_type()
1096 {
1097     if [ $# -ne 1 ]
1098     then
1099         echo "Usage: _fs_type device" 1>&2
1100         exit 1
1101     fi
1102
1103     #
1104     # The Linux kernel shows NFSv4 filesystems in df output as
1105     # filesystem type nfs4, although we mounted it as nfs earlier.
1106     # Fix the filesystem type up here so that the callers don't
1107     # have to bother with this quirk.
1108     #
1109     _df_device $1 | $AWK_PROG '{ print $2 }' | sed -e 's/nfs4/nfs/'
1110 }
1111
1112 # return the FS mount options of a mounted device
1113 #
1114 # should write a version which just parses the output of mount for IRIX
1115 # compatibility, but since this isn't used at all, at the moment I'll leave
1116 # this for now
1117 #
1118 _fs_options()
1119 {
1120     if [ $# -ne 1 ]
1121     then
1122         echo "Usage: _fs_options device" 1>&2
1123         exit 1
1124     fi
1125
1126     $AWK_PROG -v dev=$1 '
1127         match($1,dev) { print $4 }
1128     ' </proc/mounts
1129 }
1130
1131 # returns device number if a file is a block device
1132 #
1133 _is_block_dev()
1134 {
1135     if [ $# -ne 1 ]
1136     then
1137         echo "Usage: _is_block_dev dev" 1>&2
1138         exit 1
1139     fi
1140
1141     _dev=$1
1142     if [ -L "${_dev}" ]; then
1143         _dev=`readlink -f "${_dev}"`
1144     fi
1145
1146     if [ -b "${_dev}" ]; then
1147         src/lstat64 "${_dev}" | $AWK_PROG '/Device type:/ { print $9 }'
1148     fi
1149 }
1150
1151 # Do a command, log it to $seqres.full, optionally test return status
1152 # and die if command fails. If called with one argument _do executes the
1153 # command, logs it, and returns its exit status. With two arguments _do
1154 # first prints the message passed in the first argument, and then "done"
1155 # or "fail" depending on the return status of the command passed in the
1156 # second argument. If the command fails and the variable _do_die_on_error
1157 # is set to "always" or the two argument form is used and _do_die_on_error
1158 # is set to "message_only" _do will print an error message to
1159 # $seqres.out and exit.
1160
1161 _do()
1162 {
1163     if [ $# -eq 1 ]; then
1164         _cmd=$1
1165     elif [ $# -eq 2 ]; then
1166         _note=$1
1167         _cmd=$2
1168         echo -n "$_note... "
1169     else
1170         echo "Usage: _do [note] cmd" 1>&2
1171         status=1; exit
1172     fi
1173
1174     (eval "echo '---' \"$_cmd\"") >>$seqres.full
1175     (eval "$_cmd") >$tmp._out 2>&1; ret=$?
1176     cat $tmp._out | _fix_malloc >>$seqres.full
1177     if [ $# -eq 2 ]; then
1178         if [ $ret -eq 0 ]; then
1179             echo "done"
1180         else
1181             echo "fail"
1182         fi
1183     fi
1184     if [ $ret -ne 0  ] \
1185         && [ "$_do_die_on_error" = "always" \
1186             -o \( $# -eq 2 -a "$_do_die_on_error" = "message_only" \) ]
1187     then
1188         [ $# -ne 2 ] && echo
1189         eval "echo \"$_cmd\" failed \(returned $ret\): see $seqres.full"
1190         status=1; exit
1191     fi
1192
1193     return $ret
1194 }
1195
1196 # bail out, setting up .notrun file. Need to kill the filesystem check files
1197 # here, otherwise they are set incorrectly for the next test.
1198 #
1199 _notrun()
1200 {
1201     echo "$*" > $seqres.notrun
1202     echo "$seq not run: $*"
1203     rm -f ${RESULT_DIR}/require_test
1204     rm -f ${RESULT_DIR}/require_scratch
1205     status=0
1206     exit
1207 }
1208
1209 # just plain bail out
1210 #
1211 _fail()
1212 {
1213     echo "$*" | tee -a $seqres.full
1214     echo "(see $seqres.full for details)"
1215     status=1
1216     exit 1
1217 }
1218
1219 # tests whether $FSTYP is one of the supported filesystems for a test
1220 #
1221 _supported_fs()
1222 {
1223     for f
1224     do
1225         if [ "$f" = "$FSTYP" -o "$f" = "generic" ]
1226         then
1227             return
1228         fi
1229     done
1230
1231     _notrun "not suitable for this filesystem type: $FSTYP"
1232 }
1233
1234
1235 # tests whether $FSTYP is one of the supported OSes for a test
1236 #
1237 _supported_os()
1238 {
1239     for h
1240     do
1241         if [ "$h" = "$HOSTOS" ]
1242         then
1243             return
1244         fi
1245     done
1246
1247     _notrun "not suitable for this OS: $HOSTOS"
1248 }
1249
1250 # this test needs a scratch partition - check we're ok & unmount it
1251 # No post-test check of the device is required. e.g. the test intentionally
1252 # finishes the test with the filesystem in a corrupt state
1253 _require_scratch_nocheck()
1254 {
1255     case "$FSTYP" in
1256         nfs*)
1257                 echo $SCRATCH_DEV | grep -q ":/" > /dev/null 2>&1
1258                 if [ -z "$SCRATCH_DEV" -o "$?" != "0" ]; then
1259                         _notrun "this test requires a valid \$SCRATCH_DEV"
1260                 fi
1261                 if [ ! -d "$SCRATCH_MNT" ]; then
1262                         _notrun "this test requires a valid \$SCRATCH_MNT"
1263                 fi
1264                 ;;
1265         cifs)
1266                 echo $SCRATCH_DEV | grep -q "//" > /dev/null 2>&1
1267                 if [ -z "$SCRATCH_DEV" -o "$?" != "0" ]; then
1268                         _notrun "this test requires a valid \$SCRATCH_DEV"
1269                 fi
1270                 if [ ! -d "$SCRATCH_MNT" ]; then
1271                      _notrun "this test requires a valid \$SCRATCH_MNT"
1272                 fi
1273                 ;;
1274         overlay)
1275                 if [ -z "$SCRATCH_DEV" -o ! -d "$SCRATCH_DEV" ]; then
1276                         _notrun "this test requires a valid \$SCRATCH_DEV as ovl base dir"
1277                 fi
1278                 if [ ! -d "$SCRATCH_MNT" ]; then
1279                         _notrun "this test requires a valid \$SCRATCH_MNT"
1280                 fi
1281                 ;;
1282         tmpfs)
1283                 if [ -z "$SCRATCH_DEV" -o ! -d "$SCRATCH_MNT" ];
1284                 then
1285                     _notrun "this test requires a valid \$SCRATCH_MNT and unique $SCRATCH_DEV"
1286                 fi
1287                 ;;
1288         *)
1289                  if [ -z "$SCRATCH_DEV" -o "`_is_block_dev "$SCRATCH_DEV"`" = "" ]
1290                  then
1291                      _notrun "this test requires a valid \$SCRATCH_DEV"
1292                  fi
1293                  if [ "`_is_block_dev "$SCRATCH_DEV"`" = "`_is_block_dev "$TEST_DEV"`" ]
1294                  then
1295                      _notrun "this test requires a valid \$SCRATCH_DEV"
1296                  fi
1297                 if [ ! -d "$SCRATCH_MNT" ]
1298                 then
1299                      _notrun "this test requires a valid \$SCRATCH_MNT"
1300                 fi
1301                  ;;
1302     esac
1303
1304     # mounted?
1305     # Note that we use -F here so grep doesn't try to interpret an NFS over
1306     # IPv6 server as a regular expression.
1307     mount_rec=`_mount | grep -F $SCRATCH_DEV`
1308     if [ "$mount_rec" ]
1309     then
1310         # if it's mounted, make sure its on $SCRATCH_MNT
1311         if ! echo $mount_rec | grep -q $SCRATCH_MNT
1312         then
1313             echo "\$SCRATCH_DEV=$SCRATCH_DEV is mounted but not on \$SCRATCH_MNT=$SCRATCH_MNT - aborting"
1314             echo "Already mounted result:"
1315             echo $mount_rec
1316             exit 1
1317         fi
1318         # and then unmount it
1319         if ! _scratch_unmount
1320         then
1321             echo "failed to unmount $SCRATCH_DEV"
1322             exit 1
1323         fi
1324     fi
1325     rm -f ${RESULT_DIR}/require_scratch
1326 }
1327
1328 # we need the scratch device and it should be checked post test.
1329 _require_scratch()
1330 {
1331         _require_scratch_nocheck
1332         touch ${RESULT_DIR}/require_scratch
1333 }
1334
1335
1336 # this test needs a test partition - check we're ok & mount it
1337 #
1338 _require_test()
1339 {
1340     case "$FSTYP" in
1341         nfs*)
1342                 echo $TEST_DEV | grep -q ":/" > /dev/null 2>&1
1343                 if [ -z "$TEST_DEV" -o "$?" != "0" ]; then
1344                         _notrun "this test requires a valid \$TEST_DIR"
1345                 fi
1346                 if [ ! -d "$TEST_DIR" ]; then
1347                         _notrun "this test requires a valid \$TEST_DIR"
1348                 fi
1349                 ;;
1350         cifs)
1351                 echo $TEST_DEV | grep -q "//" > /dev/null 2>&1
1352                 if [ -z "$TEST_DEV" -o "$?" != "0" ]; then
1353                         _notrun "this test requires a valid \$TEST_DEV"
1354                 fi
1355                 if [ ! -d "$TEST_DIR" ]; then
1356                      _notrun "this test requires a valid \$TEST_DIR"
1357                 fi
1358                 ;;
1359         overlay)
1360                 if [ -z "$TEST_DEV" -o ! -d "$TEST_DEV" ]; then
1361                         _notrun "this test requires a valid \$TEST_DEV as ovl base dir"
1362                 fi
1363                 if [ ! -d "$TEST_DIR" ]; then
1364                         _notrun "this test requires a valid \$TEST_DIR"
1365                 fi
1366                 ;;
1367         tmpfs)
1368                 if [ -z "$TEST_DEV" -o ! -d "$TEST_DIR" ];
1369                 then
1370                     _notrun "this test requires a valid \$TEST_DIR and unique $TEST_DEV"
1371                 fi
1372                 ;;
1373         *)
1374                  if [ -z "$TEST_DEV" ] || [ "`_is_block_dev "$TEST_DEV"`" = "" ]
1375                  then
1376                      _notrun "this test requires a valid \$TEST_DEV"
1377                  fi
1378                  if [ "`_is_block_dev "$SCRATCH_DEV"`" = "`_is_block_dev "$TEST_DEV"`" ]
1379                  then
1380                      _notrun "this test requires a valid \$TEST_DEV"
1381                  fi
1382                 if [ ! -d "$TEST_DIR" ]
1383                 then
1384                      _notrun "this test requires a valid \$TEST_DIR"
1385                 fi
1386                  ;;
1387     esac
1388
1389     # mounted?
1390     # Note that we use -F here so grep doesn't try to interpret an NFS over
1391     # IPv6 server as a regular expression.
1392     mount_rec=`_mount | grep -F $TEST_DEV`
1393     if [ "$mount_rec" ]
1394     then
1395         # if it's mounted, make sure its on $TEST_DIR
1396         if ! echo $mount_rec | grep -q $TEST_DIR
1397         then
1398             echo "\$TEST_DEV=$TEST_DEV is mounted but not on \$TEST_DIR=$TEST_DIR - aborting"
1399             echo "Already mounted result:"
1400             echo $mount_rec
1401             exit 1
1402         fi
1403     else
1404         out=`_mount_or_remount_rw "$MOUNT_OPTIONS" $TEST_DEV $TEST_DIR`
1405         if [ $? -ne 1 ]; then
1406                 echo $out
1407                 exit 1
1408         fi
1409     fi
1410     touch ${RESULT_DIR}/require_test
1411 }
1412
1413 # this test needs a logdev
1414 #
1415 _require_logdev()
1416 {
1417     [ -z "$SCRATCH_LOGDEV" -o ! -b "$SCRATCH_LOGDEV" ] && \
1418         _notrun "This test requires a valid \$SCRATCH_LOGDEV"
1419     [ "$USE_EXTERNAL" != yes ] && \
1420         _notrun "This test requires USE_EXTERNAL to be enabled"
1421
1422     # ensure its not mounted
1423     $UMOUNT_PROG $SCRATCH_LOGDEV 2>/dev/null
1424 }
1425
1426 # this test requires loopback device support
1427 #
1428 _require_loop()
1429 {
1430     if [ "$HOSTOS" != "Linux" ]
1431     then
1432         _notrun "This test requires linux for loopback device support"
1433     fi
1434
1435     modprobe loop >/dev/null 2>&1
1436     if grep loop /proc/devices >/dev/null 2>&1
1437     then
1438         :
1439     else
1440         _notrun "This test requires loopback device support"
1441     fi
1442 }
1443
1444 # this test requires ext2 filesystem support
1445 #
1446 _require_ext2()
1447 {
1448     if [ "$HOSTOS" != "Linux" ]
1449     then
1450         _notrun "This test requires linux for ext2 filesystem support"
1451     fi
1452
1453     modprobe ext2 >/dev/null 2>&1
1454     if grep ext2 /proc/filesystems >/dev/null 2>&1
1455     then
1456         :
1457     else
1458         _notrun "This test requires ext2 filesystem support"
1459     fi
1460 }
1461
1462 # this test requires that (large) loopback device files are not in use
1463 #
1464 _require_no_large_scratch_dev()
1465 {
1466     [ "$LARGE_SCRATCH_DEV" = yes ] && \
1467         _notrun "Large filesystem testing in progress, skipped this test"
1468 }
1469
1470 # this test requires that a realtime subvolume is in use, and
1471 # that the kernel supports realtime as well.
1472 #
1473 _require_realtime()
1474 {
1475     [ "$USE_EXTERNAL" = yes ] || \
1476         _notrun "External volumes not in use, skipped this test"
1477     [ "$SCRATCH_RTDEV" = "" ] && \
1478         _notrun "Realtime device required, skipped this test"
1479 }
1480
1481 # this test requires that a specified command (executable) exists
1482 # $1 - command, $2 - name for error message
1483 #
1484 # Note: the command string might have parameters, so strip them before checking
1485 # whether it is executable.
1486 _require_command()
1487 {
1488         if [ $# -eq 2 ]; then
1489                 _name="$2"
1490         elif [ $# -eq 1 ]; then
1491                 _name="$1"
1492         else
1493                 _fail "usage: _require_command <command> [<name>]"
1494         fi
1495
1496         _command=`echo "$1" | awk '{ print $1 }'`
1497         if [ ! -x "$_command" ]; then
1498                 _notrun "$_name utility required, skipped this test"
1499         fi
1500 }
1501
1502 # this test requires the device to be valid block device
1503 # $1 - device
1504 _require_block_device()
1505 {
1506         if [ -z "$1" ]; then
1507                 echo "Usage: _require_block_device <dev>" 1>&2
1508                 exit 1
1509         fi
1510         if [ "`_is_block_dev "$1"`" == "" ]; then
1511                 _notrun "require $1 to be valid block disk"
1512         fi
1513 }
1514
1515 # brd based ram disks erase the device when they receive a flush command when no
1516 # active references are present. This causes problems for DM devices sitting on
1517 # top of brd devices as DM doesn't hold active references to the brd device.
1518 _require_sane_bdev_flush()
1519 {
1520         echo $1 | grep -q "^/dev/ram[0-9]\+$"
1521         if [ $? -eq 0 ]; then
1522                 _notrun "This test requires a sane block device flush"
1523         fi
1524 }
1525
1526 # this test requires a specific device mapper target
1527 _require_dm_target()
1528 {
1529         _target=$1
1530
1531         # require SCRATCH_DEV to be a valid block device with sane BLKFLSBUF
1532         # behaviour
1533         _require_block_device $SCRATCH_DEV
1534         _require_sane_bdev_flush $SCRATCH_DEV
1535         _require_command "$DMSETUP_PROG" dmsetup
1536
1537         modprobe dm-$_target >/dev/null 2>&1
1538
1539         $DMSETUP_PROG targets 2>&1 | grep -q ^$_target
1540         if [ $? -ne 0 ]; then
1541                 _notrun "This test requires dm $_target support"
1542         fi
1543 }
1544
1545 # this test requires the projid32bit feature to be available in mkfs.xfs.
1546 #
1547 _require_projid32bit()
1548 {
1549        _scratch_mkfs_xfs_supported -i projid32bit=1 >/dev/null 2>&1 \
1550            || _notrun "mkfs.xfs doesn't have projid32bit feature"
1551 }
1552
1553 _require_projid16bit()
1554 {
1555         _scratch_mkfs_xfs_supported -i projid32bit=0 >/dev/null 2>&1 \
1556            || _notrun "16 bit project IDs not supported on $SCRATCH_DEV"
1557 }
1558
1559 # this test requires the crc feature to be available in mkfs.xfs
1560 #
1561 _require_xfs_mkfs_crc()
1562 {
1563         _scratch_mkfs_xfs_supported -m crc=1 >/dev/null 2>&1 \
1564            || _notrun "mkfs.xfs doesn't have crc feature"
1565 }
1566
1567 # this test requires the xfs kernel support crc feature
1568 #
1569 _require_xfs_crc()
1570 {
1571         _scratch_mkfs_xfs -m crc=1 >/dev/null 2>&1
1572         _scratch_mount >/dev/null 2>&1 \
1573            || _notrun "Kernel doesn't support crc feature"
1574         _scratch_unmount
1575 }
1576
1577 # this test requires the ext4 kernel support crc feature on scratch device
1578 #
1579 _require_scratch_ext4_crc()
1580 {
1581         _scratch_mkfs_ext4 >/dev/null 2>&1
1582         dumpe2fs -h $SCRATCH_DEV 2> /dev/null | grep -q metadata_csum || _notrun "metadata_csum not supported by this filesystem"
1583         _scratch_mount >/dev/null 2>&1 \
1584            || _notrun "Kernel doesn't support metadata_csum feature"
1585         _scratch_unmount
1586 }
1587
1588 # this test requires the xfs kernel support crc feature on scratch device
1589 #
1590 _require_scratch_xfs_crc()
1591 {
1592         _scratch_mkfs_xfs >/dev/null 2>&1
1593         _scratch_mount >/dev/null 2>&1 \
1594            || _notrun "Kernel doesn't support crc feature"
1595         xfs_info $SCRATCH_MNT | grep -q 'crc=1' || _notrun "crc feature not supported by this filesystem"
1596         _scratch_unmount
1597 }
1598
1599 # this test requires the bigalloc feature to be available in mkfs.ext4
1600 #
1601 _require_ext4_mkfs_bigalloc()
1602 {
1603         $MKFS_EXT4_PROG -F -O bigalloc -n $SCRATCH_DEV 512m >/dev/null 2>&1 \
1604            || _notrun "mkfs.ext4 doesn't have bigalloc feature"
1605 }
1606
1607 # this test requires the ext4 kernel support bigalloc feature
1608 #
1609 _require_ext4_bigalloc()
1610 {
1611         $MKFS_EXT4_PROG -F -O bigalloc $SCRATCH_DEV 512m >/dev/null 2>&1
1612         _scratch_mount >/dev/null 2>&1 \
1613            || _notrun "Ext4 kernel doesn't support bigalloc feature"
1614         _scratch_unmount
1615 }
1616
1617 # this test requires the finobt feature to be available in mkfs.xfs
1618 #
1619 _require_xfs_mkfs_finobt()
1620 {
1621         _scratch_mkfs_xfs_supported -m crc=1,finobt=1 >/dev/null 2>&1 \
1622            || _notrun "mkfs.xfs doesn't have finobt feature"
1623 }
1624
1625 # this test requires the xfs kernel support finobt feature
1626 #
1627 _require_xfs_finobt()
1628 {
1629         _scratch_mkfs_xfs -m crc=1,finobt=1 >/dev/null 2>&1
1630         _scratch_mount >/dev/null 2>&1 \
1631            || _notrun "Kernel doesn't support finobt feature"
1632         _scratch_unmount
1633 }
1634
1635 # this test requires xfs sysfs attribute support
1636 #
1637 _require_xfs_sysfs()
1638 {
1639         attr=$1
1640         sysfsdir=/sys/fs/xfs
1641
1642         if [ ! -e $sysfsdir ]; then
1643                 _notrun "no kernel support for XFS sysfs attributes"
1644         fi
1645
1646         if [ ! -z $1 ] && [ ! -e $sysfsdir/$attr ]; then
1647                 _notrun "sysfs attribute '$attr' is not supported"
1648         fi
1649 }
1650
1651 # this test requires the xfs sparse inode feature
1652 #
1653 _require_xfs_sparse_inodes()
1654 {
1655         _scratch_mkfs_xfs_supported -m crc=1 -i sparse > /dev/null 2>&1 \
1656                 || _notrun "mkfs.xfs does not support sparse inodes"
1657         _scratch_mkfs_xfs -m crc=1 -i sparse > /dev/null 2>&1
1658         _scratch_mount >/dev/null 2>&1 \
1659                 || _notrun "kernel does not support sparse inodes"
1660         _scratch_unmount
1661 }
1662
1663 # this test requires that external log/realtime devices are not in use
1664 #
1665 _require_nonexternal()
1666 {
1667     [ "$USE_EXTERNAL" = yes ] && \
1668         _notrun "External device testing in progress, skipped this test"
1669 }
1670
1671 # this test requires that a (specified) aio-dio executable exists
1672 # $1 - command (optional)
1673 #
1674 _require_aiodio()
1675 {
1676     if [ -z "$1" ]
1677     then
1678         AIO_TEST=src/aio-dio-regress/aiodio_sparse2
1679         [ -x $AIO_TEST ] || _notrun "aio-dio utilities required"
1680     else
1681         AIO_TEST=src/aio-dio-regress/$1
1682         [ -x $AIO_TEST ] || _notrun "$AIO_TEST not built"
1683     fi
1684     _require_odirect
1685 }
1686
1687 # this test requires that a test program exists under src/
1688 # $1 - command (require)
1689 #
1690 _require_test_program()
1691 {
1692     SRC_TEST=src/$1
1693     [ -x $SRC_TEST ] || _notrun "$SRC_TEST not built"
1694 }
1695
1696 # run an aio-dio program
1697 # $1 - command
1698 _run_aiodio()
1699 {
1700     if [ -z "$1" ]
1701     then
1702         echo "usage: _run_aiodio command_name" 2>&1
1703         status=1; exit 1
1704     fi
1705
1706     _require_aiodio $1
1707
1708     local testtemp=$TEST_DIR/aio-testfile
1709     rm -f $testtemp
1710     $AIO_TEST $testtemp 2>&1
1711     status=$?
1712     rm -f $testtemp
1713
1714     return $status
1715 }
1716
1717 # indicate whether YP/NIS is active or not
1718 #
1719 _yp_active()
1720 {
1721         local dn
1722         dn=$(domainname 2>/dev/null)
1723         test -n "${dn}" -a "${dn}" != "(none)"
1724         echo $?
1725 }
1726
1727 # cat the password file
1728 #
1729 _cat_passwd()
1730 {
1731         [ $(_yp_active) -eq 0 ] && ypcat passwd
1732         cat /etc/passwd
1733 }
1734
1735 # cat the group file
1736 #
1737 _cat_group()
1738 {
1739         [ $(_yp_active) -eq 0 ] && ypcat group
1740         cat /etc/group
1741 }
1742
1743 # check for a user on the machine, fsgqa as default
1744 #
1745 _require_user()
1746 {
1747     qa_user=fsgqa
1748     if [ -n "$1" ];then
1749         qa_user=$1
1750     fi
1751     _cat_passwd | grep -q $qa_user
1752     [ "$?" == "0" ] || _notrun "$qa_user user not defined."
1753     echo /bin/true | su $qa_user
1754     [ "$?" == "0" ] || _notrun "$qa_user cannot execute commands."
1755 }
1756
1757 # check for a group on the machine, fsgqa as default
1758 #
1759 _require_group()
1760 {
1761     qa_group=fsgqa
1762     if [ -n "$1" ];then
1763         qa_group=$1
1764     fi
1765     _cat_group | grep -q $qa_group
1766     [ "$?" == "0" ] || _notrun "$qa_group user not defined."
1767 }
1768
1769 _filter_user_do()
1770 {
1771         perl -ne "
1772 s,.*Permission\sdenied.*,Permission denied,;
1773 s,.*no\saccess\sto\stty.*,,;
1774 s,.*no\sjob\scontrol\sin\sthis\sshell.*,,;
1775 s,^\s*$,,;
1776         print;"
1777 }
1778
1779 _user_do()
1780 {
1781     if [ "$HOSTOS" == "IRIX" ]
1782         then
1783         echo $1 | /bin/bash "su $qa_user 2>&1" | _filter_user_do
1784     else
1785         echo $1 | su $qa_user 2>&1 | _filter_user_do
1786     fi
1787 }
1788
1789 _require_xfs_io_command()
1790 {
1791         if [ $# -ne 1 ]
1792         then
1793                 echo "Usage: _require_xfs_io_command command" 1>&2
1794                 exit 1
1795         fi
1796         command=$1
1797
1798         testfile=$TEST_DIR/$$.xfs_io
1799         case $command in
1800         "falloc" )
1801                 testio=`$XFS_IO_PROG -F -f -c "falloc 0 1m" $testfile 2>&1`
1802                 ;;
1803         "fpunch" | "fcollapse" | "zero" | "fzero" | "finsert" )
1804                 testio=`$XFS_IO_PROG -F -f -c "pwrite 0 20k" -c "fsync" \
1805                         -c "$command 4k 8k" $testfile 2>&1`
1806                 ;;
1807         "fiemap")
1808                 testio=`$XFS_IO_PROG -F -f -c "pwrite 0 20k" -c "fsync" \
1809                         -c "fiemap -v" $testfile 2>&1`
1810                 ;;
1811         "flink" )
1812                 testio=`$XFS_IO_PROG -T -F -c "flink $testfile" \
1813                         $TEST_DIR 2>&1`
1814                 echo $testio | egrep -q "invalid option|Is a directory" && \
1815                         _notrun "xfs_io $command support is missing"
1816                 ;;
1817         *)
1818                 testio=`$XFS_IO_PROG -c "$command help" 2>&1`
1819         esac
1820
1821         rm -f $testfile 2>&1 > /dev/null
1822         echo $testio | grep -q "not found" && \
1823                 _notrun "xfs_io $command support is missing"
1824         echo $testio | grep -q "Operation not supported" && \
1825                 _notrun "xfs_io $command failed (old kernel/wrong fs?)"
1826 }
1827
1828 # check that xfs_db supports a specific command
1829 _require_xfs_db_command()
1830 {
1831         if [ $# -ne 1 ]
1832         then
1833                 echo "Usage: _require_xfs_db_command command" 1>&2
1834                 exit 1
1835         fi
1836         command=$1
1837
1838         $XFS_DB_PROG -x -c "help" $SCRATCH_DEV | grep $command > /dev/null || \
1839                 _notrun "xfs_db $command support is missing"
1840 }
1841
1842 # check that kernel and filesystem support direct I/O
1843 _require_odirect()
1844 {
1845        testfile=$TEST_DIR/$$.direct
1846        $XFS_IO_PROG -F -f -d -c "pwrite 0 20k" $testfile > /dev/null 2>&1
1847        if [ $? -ne 0 ]; then
1848                _notrun "O_DIRECT is not supported"
1849        fi
1850        rm -f $testfile 2>&1 > /dev/null
1851 }
1852
1853 # Check that a fs has enough free space (in 1024b blocks)
1854 #
1855 _require_fs_space()
1856 {
1857         MNT=$1
1858         BLOCKS=$2       # in units of 1024
1859         let GB=$BLOCKS/1024/1024
1860
1861         FREE_BLOCKS=`df -klP $MNT | grep -v Filesystem | awk '{print $4}'`
1862         [ $FREE_BLOCKS -lt $BLOCKS ] && \
1863                 _notrun "This test requires at least ${GB}GB free on $MNT to run"
1864 }
1865
1866 #
1867 # Check if the filesystem supports sparse files.
1868 #
1869 # Unfortunately there is no better way to do this than a manual black list.
1870 #
1871 _require_sparse_files()
1872 {
1873     case $FSTYP in
1874     hfsplus)
1875         _notrun "Sparse files not supported by this filesystem type: $FSTYP"
1876         ;;
1877     *)
1878         ;;
1879     esac
1880 }
1881
1882 _require_debugfs()
1883 {
1884     #boot_params always present in debugfs
1885     [ -d "$DEBUGFS_MNT/boot_params" ] || _notrun "Debugfs not mounted"
1886 }
1887
1888 _require_fail_make_request()
1889 {
1890     [ -f "$DEBUGFS_MNT/fail_make_request/probability" ] \
1891         || _notrun "$DEBUGFS_MNT/fail_make_request \
1892  not found. Seems that CONFIG_FAIL_MAKE_REQUEST kernel config option not enabled"
1893 }
1894
1895 #
1896 # Check if the file system supports seek_data/hole
1897 #
1898 _require_seek_data_hole()
1899 {
1900     testfile=$TEST_DIR/$$.seek
1901     testseek=`$here/src/seek_sanity_test -t $testfile 2>&1`
1902     rm -f $testfile &>/dev/null
1903     echo $testseek | grep -q "Kernel does not support" && \
1904         _notrun "File system does not support llseek(2) SEEK_DATA/HOLE"
1905 }
1906
1907 # check that a FS on a device is mounted
1908 # if so, return mount point
1909 #
1910 _is_mounted()
1911 {
1912     if [ $# -ne 1 ]
1913     then
1914         echo "Usage: _is_mounted device" 1>&2
1915         exit 1
1916     fi
1917
1918     device=$1
1919
1920     if _mount | grep "$device " | $AWK_PROG -v pattern="type $FSTYP" '
1921         pattern        { print $3 ; exit 0 }
1922         END            { exit 1 }
1923     '
1924     then
1925         echo "_is_mounted: $device is not a mounted $FSTYP FS"
1926         exit 1
1927     fi
1928 }
1929
1930 # remount a FS to a new mode (ro or rw)
1931 #
1932 _remount()
1933 {
1934     if [ $# -ne 2 ]
1935     then
1936         echo "Usage: _remount device ro/rw" 1>&2
1937         exit 1
1938     fi
1939     device=$1
1940     mode=$2
1941
1942     if ! mount -o remount,$mode $device
1943     then
1944         echo "_remount: failed to remount filesystem on $device as $mode"
1945         exit 1
1946     fi
1947 }
1948
1949 # Run the appropriate repair/check on a filesystem
1950 #
1951 # if the filesystem is mounted, it's either remounted ro before being
1952 # checked or it's unmounted and then remounted
1953 #
1954
1955 # If set, we remount ro instead of unmounting for fsck
1956 USE_REMOUNT=0
1957
1958 _umount_or_remount_ro()
1959 {
1960     if [ $# -ne 1 ]
1961     then
1962         echo "Usage: _umount_or_remount_ro <device>" 1>&2
1963         exit 1
1964     fi
1965
1966     device=$1
1967     mountpoint=`_is_mounted $device`
1968
1969     if [ $USE_REMOUNT -eq 0 ]; then
1970         $UMOUNT_PROG $device
1971     else
1972         _remount $device ro
1973     fi
1974     echo "$mountpoint"
1975 }
1976
1977 _mount_or_remount_rw()
1978 {
1979         if [ $# -ne 3 ]; then
1980                 echo "Usage: _mount_or_remount_rw <opts> <dev> <mnt>" 1>&2
1981                 exit 1
1982         fi
1983         mount_opts=$1
1984         device=$2
1985         mountpoint=$3
1986
1987         if [ $USE_REMOUNT -eq 0 ]; then
1988                 if [ "$FSTYP" != "overlay" ]; then
1989                         _mount -t $FSTYP $mount_opts $device $mountpoint
1990                 else
1991                         _overlay_mount $device $mountpoint
1992                 fi
1993                 if [ $? -ne 0 ]; then
1994                         echo "!!! failed to remount $device on $mountpoint"
1995                         return 0 # ok=0
1996                 fi
1997         else
1998                 _remount $device rw
1999         fi
2000
2001         return 1 # ok=1
2002 }
2003
2004 # Check a generic filesystem in no-op mode; this assumes that the
2005 # underlying fsck program accepts "-n" for a no-op (check-only) run,
2006 # and that it will still return an errno for corruption in this mode.
2007 #
2008 # Filesystems which don't support this will need to define their
2009 # own check routine.
2010 #
2011 _check_generic_filesystem()
2012 {
2013     device=$1
2014
2015     # If type is set, we're mounted
2016     type=`_fs_type $device`
2017     ok=1
2018
2019     if [ "$type" = "$FSTYP" ]
2020     then
2021         # mounted ...
2022         mountpoint=`_umount_or_remount_ro $device`
2023     fi
2024
2025     fsck -t $FSTYP $FSCK_OPTIONS $device >$tmp.fsck 2>&1
2026     if [ $? -ne 0 ]
2027     then
2028         echo "_check_generic_filesystem: filesystem on $device is inconsistent (see $seqres.full)"
2029
2030         echo "_check_generic filesystem: filesystem on $device is inconsistent" >>$seqres.full
2031         echo "*** fsck.$FSTYP output ***"       >>$seqres.full
2032         cat $tmp.fsck                           >>$seqres.full
2033         echo "*** end fsck.$FSTYP output"       >>$seqres.full
2034
2035         ok=0
2036     fi
2037     rm -f $tmp.fsck
2038
2039     if [ $ok -eq 0 ]
2040     then
2041         echo "*** mount output ***"             >>$seqres.full
2042         _mount                                  >>$seqres.full
2043         echo "*** end mount output"             >>$seqres.full
2044     elif [ "$type" = "$FSTYP" ]
2045     then
2046         # was mounted ...
2047         _mount_or_remount_rw "$MOUNT_OPTIONS" $device $mountpoint
2048         ok=$?
2049     fi
2050
2051     if [ $ok -eq 0 ]; then
2052         status=1
2053         if [ "$iam" != "check" ]; then
2054                 exit 1
2055         fi
2056         return 1
2057     fi
2058
2059     return 0
2060 }
2061
2062 # run xfs_check and friends on a FS.
2063
2064 _check_xfs_filesystem()
2065 {
2066     if [ $# -ne 3 ]
2067     then
2068         echo "Usage: _check_xfs_filesystem device <logdev>|none <rtdev>|none" 1>&2
2069         exit 1
2070     fi
2071
2072     extra_mount_options=""
2073     extra_log_options=""
2074     extra_options=""
2075     device=$1
2076     if [ -f $device ];then
2077        extra_options="-f"
2078     fi
2079
2080     if [ "$2" != "none" ]; then
2081         extra_log_options="-l$2"
2082         extra_mount_options="-ologdev=$2"
2083     fi
2084
2085     if [ "$3" != "none" ]; then
2086         extra_rt_options="-r$3"
2087         extra_mount_options=$extra_mount_options" -ortdev=$3"
2088     fi
2089     extra_mount_options=$extra_mount_options" $MOUNT_OPTIONS"
2090
2091     [ "$FSTYP" != xfs ] && return 0
2092
2093     type=`_fs_type $device`
2094     ok=1
2095
2096     if [ "$type" = "xfs" ]
2097     then
2098         # mounted ...
2099         mountpoint=`_umount_or_remount_ro $device`
2100     fi
2101
2102     $XFS_LOGPRINT_PROG -t $extra_log_options $device 2>&1 \
2103                 | tee $tmp.logprint | grep -q "<CLEAN>"
2104     if [ $? -ne 0 -a "$HOSTOS" = "Linux" ]
2105     then
2106         echo "_check_xfs_filesystem: filesystem on $device has dirty log (see $seqres.full)"
2107
2108         echo "_check_xfs_filesystem: filesystem on $device has dirty log"   >>$seqres.full
2109         echo "*** xfs_logprint -t output ***"   >>$seqres.full
2110         cat $tmp.logprint                       >>$seqres.full
2111         echo "*** end xfs_logprint output"      >>$seqres.full
2112
2113         ok=0
2114     fi
2115
2116     # xfs_check runs out of memory on large files, so even providing the test
2117     # option (-t) to avoid indexing the free space trees doesn't make it pass on
2118     # large filesystems. Avoid it.
2119     if [ "$LARGE_SCRATCH_DEV" != yes ]; then
2120             _xfs_check $extra_log_options $device 2>&1 |\
2121                  _fix_malloc >$tmp.fs_check
2122     fi
2123     if [ -s $tmp.fs_check ]
2124     then
2125         echo "_check_xfs_filesystem: filesystem on $device is inconsistent (c) (see $seqres.full)"
2126
2127         echo "_check_xfs_filesystem: filesystem on $device is inconsistent" >>$seqres.full
2128         echo "*** xfs_check output ***"         >>$seqres.full
2129         cat $tmp.fs_check                       >>$seqres.full
2130         echo "*** end xfs_check output"         >>$seqres.full
2131
2132         ok=0
2133     fi
2134
2135     $XFS_REPAIR_PROG -n $extra_options $extra_log_options $extra_rt_options $device >$tmp.repair 2>&1
2136     if [ $? -ne 0 ]
2137     then
2138         echo "_check_xfs_filesystem: filesystem on $device is inconsistent (r) (see $seqres.full)"
2139
2140         echo "_check_xfs_filesystem: filesystem on $device is inconsistent" >>$seqres.full
2141         echo "*** xfs_repair -n output ***"     >>$seqres.full
2142         cat $tmp.repair | _fix_malloc           >>$seqres.full
2143         echo "*** end xfs_repair output"        >>$seqres.full
2144
2145         ok=0
2146     fi
2147     rm -f $tmp.fs_check $tmp.logprint $tmp.repair
2148
2149     if [ $ok -eq 0 ]
2150     then
2151         echo "*** mount output ***"             >>$seqres.full
2152         _mount                                  >>$seqres.full
2153         echo "*** end mount output"             >>$seqres.full
2154     elif [ "$type" = "xfs" ]
2155     then
2156         _mount_or_remount_rw "$extra_mount_options" $device $mountpoint
2157     fi
2158
2159     if [ $ok -eq 0 ]; then
2160         status=1
2161         if [ "$iam" != "check" ]; then
2162                 exit 1
2163         fi
2164         return 1
2165     fi
2166
2167     return 0
2168 }
2169
2170 # Filter the knowen errors the UDF Verifier reports.
2171 _udf_test_known_error_filter()
2172 {
2173         egrep -v "PVD  60  Error: Interchange Level: 1, Maximum Interchange Level: 0|FSD  28  Error: Interchange Level: 1, Maximum Interchange Level: 1,|PVD  72  Warning: Volume Set Identifier: \"\*IRIX UDF\",|Warning: [0-9]+ unused blocks NOT marked as unallocated."
2174
2175 }
2176
2177 _check_udf_filesystem()
2178 {
2179     [ "$DISABLE_UDF_TEST" == "1" ] && return
2180
2181     if [ $# -ne 1 -a $# -ne 2 ]
2182     then
2183         echo "Usage: _check_udf_filesystem device [last_block]" 1>&2
2184         exit 1
2185     fi
2186
2187     if [ ! -x $here/src/udf_test ]
2188     then
2189         echo "udf_test not installed, please download and build the Philips"
2190         echo "UDF Verification Software from http://www.extra.research.philips.com/udf/."
2191         echo "Then copy the udf_test binary to $here/src/."
2192         echo "If you do not wish to run udf_test then set environment variable DISABLE_UDF_TEST"
2193         echo "to 1."
2194         return
2195     fi
2196
2197     device=$1
2198     if [ $# -eq 2 ];
2199     then
2200         LAST_BLOCK=`expr \( $2 - 1 \)`
2201         OPT_ARG="-lastvalidblock $LAST_BLOCK"
2202     fi
2203
2204     rm -f $seqres.checkfs
2205     sleep 1 # Due to a problem with time stamps in udf_test
2206     $here/src/udf_test $OPT_ARG $device | tee $seqres.checkfs | egrep "Error|Warning" | \
2207         _udf_test_known_error_filter | \
2208         egrep -iv "Error count:.*[0-9]+.*total occurrences:.*[0-9]+|Warning count:.*[0-9]+.*total occurrences:.*[0-9]+" && \
2209         echo "Warning UDF Verifier reported errors see $seqres.checkfs." && return 1
2210     return 0
2211 }
2212
2213 _check_xfs_test_fs()
2214 {
2215     TEST_LOG="none"
2216     TEST_RT="none"
2217     [ "$USE_EXTERNAL" = yes -a ! -z "$TEST_LOGDEV" ] && \
2218         TEST_LOG="$TEST_LOGDEV"
2219
2220     [ "$USE_EXTERNAL" = yes -a ! -z "$TEST_RTDEV" ] && \
2221         TEST_RT="$TEST_RTDEV"
2222
2223     _check_xfs_filesystem $TEST_DEV $TEST_LOG $TEST_RT
2224
2225     # check for ipath consistency
2226     if $XFS_GROWFS_PROG -n $TEST_DIR | grep -q 'inode-paths=1'; then
2227         # errors go to stderr
2228         xfs_check_ipaths $TEST_DIR >/dev/null
2229         xfs_repair_ipaths -n $TEST_DIR >/dev/null
2230     fi
2231 }
2232
2233 _check_btrfs_filesystem()
2234 {
2235     device=$1
2236
2237     # If type is set, we're mounted
2238     type=`_fs_type $device`
2239     ok=1
2240
2241     if [ "$type" = "$FSTYP" ]
2242     then
2243         # mounted ...
2244         mountpoint=`_umount_or_remount_ro $device`
2245     fi
2246
2247     btrfsck $device >$tmp.fsck 2>&1
2248     if [ $? -ne 0 ]
2249     then
2250         echo "_check_btrfs_filesystem: filesystem on $device is inconsistent (see $seqres.full)"
2251
2252         echo "_check_btrfs_filesystem: filesystem on $device is inconsistent" >>$seqres.full
2253         echo "*** fsck.$FSTYP output ***"       >>$seqres.full
2254         cat $tmp.fsck                           >>$seqres.full
2255         echo "*** end fsck.$FSTYP output"       >>$seqres.full
2256
2257         ok=0
2258     fi
2259     rm -f $tmp.fsck
2260
2261     if [ $ok -eq 0 ]
2262     then
2263         echo "*** mount output ***"             >>$seqres.full
2264         _mount                                  >>$seqres.full
2265         echo "*** end mount output"             >>$seqres.full
2266     elif [ "$type" = "$FSTYP" ]
2267     then
2268         # was mounted ...
2269         _mount_or_remount_rw "$MOUNT_OPTIONS" $device $mountpoint
2270         ok=$?
2271     fi
2272
2273     if [ $ok -eq 0 ]; then
2274         status=1
2275         if [ "$iam" != "check" ]; then
2276                 exit 1
2277         fi
2278         return 1
2279     fi
2280
2281     return 0
2282 }
2283
2284 _check_test_fs()
2285 {
2286     case $FSTYP in
2287     xfs)
2288         _check_xfs_test_fs
2289         ;;
2290     nfs)
2291         # no way to check consistency for nfs
2292         ;;
2293     cifs)
2294         # no way to check consistency for cifs
2295         ;;
2296     overlay)
2297         # no way to check consistency for overlay
2298         ;;
2299     udf)
2300         # do nothing for now
2301         ;;
2302     btrfs)
2303         _check_btrfs_filesystem $TEST_DEV
2304         ;;
2305     tmpfs)
2306         # no way to check consistency for tmpfs
2307         ;;
2308     *)
2309         _check_generic_filesystem $TEST_DEV
2310         ;;
2311     esac
2312 }
2313
2314 _check_scratch_fs()
2315 {
2316     device=$SCRATCH_DEV
2317     [ $# -eq 1 ] && device=$1
2318
2319     case $FSTYP in
2320     xfs)
2321         SCRATCH_LOG="none"
2322         SCRATCH_RT="none"
2323         [ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_LOGDEV" ] && \
2324             SCRATCH_LOG="$SCRATCH_LOGDEV"
2325
2326         [ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_RTDEV" ] && \
2327             SCRATCH_RT="$SCRATCH_RTDEV"
2328
2329         _check_xfs_filesystem $device $SCRATCH_LOG $SCRATCH_RT
2330         ;;
2331     udf)
2332         _check_udf_filesystem $device $udf_fsize
2333         ;;
2334     nfs*)
2335         # Don't know how to check an NFS filesystem, yet.
2336         ;;
2337     cifs)
2338         # Don't know how to check a CIFS filesystem, yet.
2339         ;;
2340     overlay)
2341         # no way to check consistency for overlay
2342         ;;
2343     btrfs)
2344         _check_btrfs_filesystem $device
2345         ;;
2346     tmpfs)
2347         # no way to check consistency for tmpfs
2348         ;;
2349     *)
2350         _check_generic_filesystem $device
2351         ;;
2352     esac
2353 }
2354
2355 _full_fstyp_details()
2356 {
2357      [ -z "$FSTYP" ] && FSTYP=xfs
2358      if [ $FSTYP = xfs ]; then
2359         if [ -d /proc/fs/xfs ]; then
2360             if grep -q 'debug 0' /proc/fs/xfs/stat; then
2361                 FSTYP="$FSTYP (non-debug)"
2362             elif grep -q 'debug 1' /proc/fs/xfs/stat; then
2363                 FSTYP="$FSTYP (debug)"
2364             fi
2365         else
2366             if uname -a | grep -qi 'debug'; then
2367                 FSTYP="$FSTYP (debug)"
2368             else
2369                 FSTYP="$FSTYP (non-debug)"
2370             fi
2371         fi
2372      fi
2373      echo $FSTYP
2374 }
2375
2376 _full_platform_details()
2377 {
2378      os=`uname -s`
2379      host=`hostname -s`
2380      kernel=`uname -r`
2381      platform=`uname -m`
2382      echo "$os/$platform $host $kernel"
2383 }
2384
2385 _get_os_name()
2386 {
2387         if [ "`uname`" == "IRIX64" ] || [ "`uname`" == "IRIX" ]; then
2388                 echo 'irix'
2389         elif [ "`uname`" == "Linux" ]; then
2390                 echo 'linux'
2391         else
2392                 echo Unknown operating system: `uname`
2393                 exit
2394         fi
2395 }
2396
2397 _link_out_file_named()
2398 {
2399         export FEATURES=$2
2400         SUFFIX=$(perl -e '
2401                 my %feathash;
2402                 my $feature, $result, $suffix, $opts;
2403
2404                 foreach $feature (split(/,/, $ENV{"FEATURES"})) {
2405                         $feathash{$feature} = 1;
2406                 }
2407                 $result = "default";
2408                 while (<>) {
2409                         my $found = 1;
2410
2411                         chomp;
2412                         ($opts, $suffix) = split(/ *: */);
2413                         foreach my $opt (split(/,/, $opts)) {
2414                                 if (!exists($feathash{$opt})) {
2415                                         $found = 0;
2416                                         last;
2417                                 }
2418                         }
2419                         if ($found == 1) {
2420                                 $result = $suffix;
2421                                 last;
2422                         }
2423                 }
2424                 print $result
2425                 ' <$seqfull.cfg)
2426         rm -f $1
2427         SRC=$(basename $1)
2428         ln -fs $SRC.$SUFFIX $1
2429 }
2430
2431 _link_out_file()
2432 {
2433         if [ $# -eq 0 ]; then
2434                 FEATURES="$(_get_os_name)"
2435                 if [ -n "$MOUNT_OPTIONS" ]; then
2436                         FEATURES=$FEATURES,${MOUNT_OPTIONS##"-o "}
2437                 fi
2438         else
2439                 FEATURES=$1
2440         fi
2441
2442         _link_out_file_named $seqfull.out "$FEATURES"
2443 }
2444
2445 _die()
2446 {
2447         echo $@
2448         exit 1
2449 }
2450
2451 #takes files, randomdata
2452 _nfiles()
2453 {
2454         f=0
2455         while [ $f -lt $1 ]
2456         do
2457                 file=f$f
2458                 echo > $file
2459                 if [ $size -gt 0 ]; then
2460                     if [ "$2" == "false" ]; then
2461                         dd if=/dev/zero of=$file bs=1024 count=$size 2>&1 | _filter_dd
2462                     else
2463                         dd if=/dev/urandom of=$file bs=1024 count=$size 2>&1 | _filter_dd
2464                     fi
2465                 fi
2466                 let f=$f+1
2467         done
2468 }
2469
2470 # takes dirname, depth, randomdata
2471 _descend()
2472 {
2473         dirname=$1; depth=$2; randomdata=$3
2474         mkdir $dirname  || die "mkdir $dirname failed"
2475         cd $dirname
2476
2477         _nfiles $files $randomdata          # files for this dir and data type
2478
2479         [ $depth -eq 0 ] && return
2480         let deep=$depth-1 # go 1 down
2481
2482         [ $verbose = true ] && echo "descending, depth from leaves = $deep"
2483
2484         d=0
2485         while [ $d -lt $dirs ]
2486         do
2487                 _descend d$d $deep &
2488                 let d=$d+1
2489                 wait
2490         done
2491 }
2492
2493 # Populate a filesystem with inodes for performance experiments
2494 #
2495 # usage: populate [-v] [-n ndirs] [-f nfiles] [-d depth] [-r root] [-s size] [-x]
2496 #
2497 _populate_fs()
2498 {
2499     here=`pwd`
2500     dirs=5          # ndirs in each subdir till leaves
2501     size=0          # sizeof files in K
2502     files=100       # num files in _each_ subdir
2503     depth=2         # depth of tree from root to leaves
2504     verbose=false
2505     root=root       # path of initial root of directory tree
2506     randomdata=false # -x data type urandom or zero
2507
2508     OPTIND=1
2509     while getopts "d:f:n:r:s:v:x" c
2510     do
2511         case $c in
2512         d)      depth=$OPTARG;;
2513         n)      dirs=$OPTARG;;
2514         f)      files=$OPTARG;;
2515         s)      size=$OPTARG;;
2516         v)      verbose=true;;
2517         r)      root=$OPTARG;;
2518         x)      randomdata=true;;
2519         esac
2520     done
2521
2522     _descend $root $depth $randomdata
2523     wait
2524
2525     cd $here
2526
2527     [ $verbose = true ] && echo done
2528 }
2529
2530 # query whether the given file has the given inode flag set
2531 #
2532 _test_inode_flag()
2533 {
2534     flag=$1
2535     file=$2
2536
2537     if which $XFS_IO_PROG >/dev/null; then
2538         if $XFS_IO_PROG -r -c 'lsattr -v' "$file" | grep -q "$flag" ; then
2539             return 0
2540         fi
2541     fi
2542     return 1
2543 }
2544
2545 # query the given files extsize allocator hint in bytes (if any)
2546 #
2547 _test_inode_extsz()
2548 {
2549     file=$1
2550     blocks=""
2551
2552     if which $XFS_IO_PROG >/dev/null; then
2553         blocks=`$XFS_IO_PROG -r -c 'stat' "$file" | \
2554                 awk '/^xattr.extsize =/ { print $3 }'`
2555     fi
2556     [ -z "$blocks" ] && blocks="0"
2557     echo $blocks
2558 }
2559
2560 # scratch_dev_pool should contain the disks pool for the btrfs raid
2561 _require_scratch_dev_pool()
2562 {
2563         local i
2564         local ndevs
2565
2566         if [ -z "$SCRATCH_DEV_POOL" ]; then
2567                 _notrun "this test requires a valid \$SCRATCH_DEV_POOL"
2568         fi
2569
2570         if [ -z "$1" ]; then
2571                 ndevs=2
2572         else
2573                 ndevs=$1
2574         fi
2575
2576         # btrfs test case needs ndevs or more scratch_dev_pool; other FS not sure
2577         # so fail it
2578         case $FSTYP in
2579         btrfs)
2580                 if [ "`echo $SCRATCH_DEV_POOL|wc -w`" -lt $ndevs ]; then
2581                         _notrun "btrfs and this test needs $ndevs or more disks in SCRATCH_DEV_POOL"
2582                 fi
2583         ;;
2584         *)
2585                 _notrun "dev_pool is not supported by fstype \"$FSTYP\""
2586         ;;
2587         esac
2588
2589         for i in $SCRATCH_DEV_POOL; do
2590                 if [ "`_is_block_dev "$i"`" = "" ]; then
2591                         _notrun "this test requires valid block disk $i"
2592                 fi
2593                 if [ "`_is_block_dev "$i"`" = "`_is_block_dev "$TEST_DEV"`" ]; then
2594                         _notrun "$i is part of TEST_DEV, this test requires unique disks"
2595                 fi
2596                 if _mount | grep -q $i; then
2597                         if ! $UMOUNT_PROG $i; then
2598                             echo "failed to unmount $i - aborting"
2599                             exit 1
2600                         fi
2601                 fi
2602                 # to help better debug when something fails, we remove
2603                 # traces of previous btrfs FS on the dev.
2604                 dd if=/dev/zero of=$i bs=4096 count=100 > /dev/null 2>&1
2605         done
2606 }
2607
2608 # ensure devices in SCRATCH_DEV_POOL are of the same size
2609 # must be called after _require_scratch_dev_pool
2610 _require_scratch_dev_pool_equal_size()
2611 {
2612         local _size
2613         local _newsize
2614         local _dev
2615
2616         # SCRATCH_DEV has been set to the first device in SCRATCH_DEV_POOL
2617         _size=`_get_device_size $SCRATCH_DEV`
2618         for _dev in $SCRATCH_DEV_POOL; do
2619                 _newsize=`_get_device_size $_dev`
2620                 if [ $_size -ne $_newsize ]; then
2621                         _notrun "This test requires devices in SCRATCH_DEV_POOL have the same size"
2622                 fi
2623         done
2624 }
2625
2626 # We will check if the device is deletable
2627 _require_deletable_scratch_dev_pool()
2628 {
2629         local i
2630         local x
2631         for i in $SCRATCH_DEV_POOL; do
2632                 x=`echo $i | cut -d"/" -f 3`
2633                 if [ ! -f /sys/class/block/${x}/device/delete ]; then
2634                         _notrun "$i is a device which is not deletable"
2635                 fi
2636         done
2637 }
2638
2639 # We check for btrfs and (optionally) features of the btrfs command
2640 _require_btrfs()
2641 {
2642         cmd=$1
2643         _require_command "$BTRFS_UTIL_PROG" btrfs
2644         if [ -z "$1" ]; then
2645                 return 1;
2646         fi
2647         $BTRFS_UTIL_PROG $cmd --help >/dev/null 2>&1
2648         [ $? -eq 0 ] || _notrun "$BTRFS_UTIL_PROG too old (must support $cmd)"
2649 }
2650
2651 # Check that fio is present, and it is able to execute given jobfile
2652 _require_fio()
2653 {
2654         job=$1
2655
2656         _require_command "$FIO_PROG" fio
2657         if [ -z "$1" ]; then
2658                 return 1;
2659         fi
2660
2661         $FIO_PROG --warnings-fatal --showcmd $job >> $seqres.full 2>&1
2662         [ $? -eq 0 ] || _notrun "$FIO_PROG too old, see $seqres.full"
2663 }
2664
2665 # Does freeze work on this fs?
2666 _require_freeze()
2667 {
2668         xfs_freeze -f "$TEST_DIR" >/dev/null 2>&1
2669         result=$? 
2670         xfs_freeze -u "$TEST_DIR" >/dev/null 2>&1
2671         [ $result -eq 0 ] || _notrun "$FSTYP does not support freezing"
2672 }
2673
2674 # Does shutdown work on this fs?
2675 _require_scratch_shutdown()
2676 {
2677         [ -x src/godown ] || _notrun "src/godown executable not found"
2678
2679         _scratch_mkfs > /dev/null 2>&1
2680         _scratch_mount
2681         src/godown -f $SCRATCH_MNT 2>&1 \
2682                 || _notrun "$FSTYP does not support shutdown"
2683         _scratch_unmount
2684 }
2685
2686 # Does norecovery support by this fs?
2687 _require_norecovery()
2688 {
2689         _scratch_mount -o ro,norecovery || \
2690                 _notrun "$FSTYP does not support norecovery"
2691         _scratch_unmount
2692 }
2693
2694 # Does this filesystem support metadata journaling?
2695 # We exclude ones here that don't; otherwise we assume that it does, so the
2696 # test will run, fail, and motivate someone to update this test for a new
2697 # filesystem.
2698 #
2699 # It's possible that TEST_DEV and SCRATCH_DEV have different features (it'd be
2700 # odd, but possible) so check $TEST_DEV by default, but we can optionall pass
2701 # any dev we want.
2702 _require_metadata_journaling()
2703 {
2704         if [ -z $1 ]; then
2705                 DEV=$TEST_DEV
2706         else
2707                 DEV=$1
2708         fi
2709
2710         case "$FSTYP" in
2711         ext2|vfat|msdos)
2712                 _notrun "$FSTYP does not support metadata journaling"
2713                 ;;
2714         ext4)
2715                 # ext4 could be mkfs'd without a journal...
2716                 _require_dumpe2fs
2717                 $DUMPE2FS_PROG -h $DEV 2>&1 | grep -q has_journal || \
2718                         _notrun "$FSTYP on $DEV not configured with metadata journaling"
2719                 ;;
2720         *)
2721                 # by default we pass; if you need to, add your fs above!
2722                 ;;
2723         esac
2724 }
2725
2726 # Does fiemap support?
2727 _require_fiemap()
2728 {
2729         _require_xfs_io_command "fiemap"
2730 }
2731
2732 _count_extents()
2733 {
2734         $XFS_IO_PROG -c "fiemap" $1 | tail -n +2 | grep -v hole | wc -l
2735 }
2736
2737 _count_holes()
2738 {
2739         $XFS_IO_PROG -c "fiemap" $1 | tail -n +2 | grep hole | wc -l
2740 }
2741
2742 # arg 1 is dev to remove and is output of the below eg.
2743 # ls -l /sys/class/block/sdd | rev | cut -d "/" -f 3 | rev
2744 _devmgt_remove()
2745 {
2746         local lun=$1
2747         local disk=$2
2748
2749         echo 1 > /sys/class/scsi_device/${lun}/device/delete || _fail "Remove disk failed"
2750
2751         stat $disk > /dev/null 2>&1
2752         while [ $? -eq 0 ]; do
2753                 sleep 1
2754                 stat $disk > /dev/null 2>&1
2755         done
2756 }
2757
2758 # arg 1 is dev to add and is output of the below eg.
2759 # ls -l /sys/class/block/sdd | rev | cut -d "/" -f 3 | rev
2760 _devmgt_add()
2761 {
2762         local h
2763         local tdl
2764         # arg 1 will be in h:t:d:l format now in the h and "t d l" format
2765         h=`echo ${1} | cut -d":" -f 1`
2766         tdl=`echo ${1} | cut -d":" -f 2-|sed 's/:/ /g'`
2767
2768         echo ${tdl} >  /sys/class/scsi_host/host${h}/scan || _fail "Add disk failed"
2769
2770         # ensure the device comes online
2771         dev_back_oneline=0
2772         for i in `seq 1 10`; do
2773                 if [ -d /sys/class/scsi_device/${1}/device/block ]; then
2774                         dev=`ls /sys/class/scsi_device/${1}/device/block`
2775                         for j in `seq 1 10`;
2776                         do
2777                                 stat /dev/$dev > /dev/null 2>&1
2778                                 if [ $? -eq 0 ]; then
2779                                         dev_back_oneline=1
2780                                         break
2781                                 fi
2782                                 sleep 1
2783                         done
2784                         break
2785                 else
2786                         sleep 1
2787                 fi
2788         done
2789         if [ $dev_back_oneline -eq 0 ]; then
2790                 echo "/dev/$dev online failed" >> $seqres.full
2791         else
2792                 echo "/dev/$dev is back online" >> $seqres.full
2793         fi
2794 }
2795
2796 _require_fstrim()
2797 {
2798         if [ -z "$FSTRIM_PROG" ]; then
2799                 _notrun "This test requires fstrim utility."
2800         fi
2801 }
2802
2803 _require_batched_discard()
2804 {
2805         if [ $# -ne 1 ]; then
2806                 echo "Usage: _require_batched_discard mnt_point" 1>&2
2807                 exit 1
2808         fi
2809         _require_fstrim
2810         $FSTRIM_PROG $1 > /dev/null 2>&1 || _notrun "FITRIM not supported on $1"
2811 }
2812
2813 _require_dumpe2fs()
2814 {
2815         if [ -z "$DUMPE2FS_PROG" ]; then
2816                 _notrun "This test requires dumpe2fs utility."
2817         fi
2818 }
2819
2820 _require_ugid_map()
2821 {
2822         if [ ! -e /proc/self/uid_map ]; then
2823                 _notrun "This test requires procfs uid_map support."
2824         fi
2825         if [ ! -e /proc/self/gid_map ]; then
2826                 _notrun "This test requires procfs gid_map support."
2827         fi
2828 }
2829
2830 _require_fssum()
2831 {
2832         FSSUM_PROG=$here/src/fssum
2833         [ -x $FSSUM_PROG ] || _notrun "fssum not built"
2834 }
2835
2836 _require_cloner()
2837 {
2838         CLONER_PROG=$here/src/cloner
2839         [ -x $CLONER_PROG ] || \
2840                 _notrun "cloner binary not present at $CLONER_PROG"
2841 }
2842
2843 _require_atime()
2844 {
2845         if [ "$FSTYP" == "nfs" ]; then
2846                 _notrun "atime related mount options have no effect on NFS"
2847         fi
2848 }
2849
2850 _require_relatime()
2851 {
2852         _scratch_mkfs > /dev/null 2>&1
2853         _scratch_mount -o relatime || \
2854                 _notrun "relatime not supported by the current kernel"
2855         _scratch_unmount
2856 }
2857
2858 _require_userns()
2859 {
2860         [ -x src/nsexec ] || _notrun "src/nsexec executable not found"
2861         src/nsexec -U true 2>/dev/null || _notrun "userns not supported by this kernel"
2862 }
2863
2864 _create_loop_device()
2865 {
2866         file=$1
2867         dev=`losetup -f --show $file` || _fail "Cannot assign $file to a loop device"
2868         echo $dev
2869 }
2870
2871 _destroy_loop_device()
2872 {
2873         dev=$1
2874         losetup -d $dev || _fail "Cannot destroy loop device $dev"
2875 }
2876
2877 _scale_fsstress_args()
2878 {
2879     args=""
2880     while [ $# -gt 0 ]; do
2881         case "$1" in
2882             -n) args="$args $1 $(($2 * $TIME_FACTOR))"; shift ;;
2883             -p) args="$args $1 $(($2 * $LOAD_FACTOR))"; shift ;;
2884             *) args="$args $1" ;;
2885         esac
2886         shift
2887     done
2888     echo $args
2889 }
2890
2891 #
2892 # Return the logical block size if running on a block device,
2893 # else substitute the page size.
2894 #
2895 _min_dio_alignment()
2896 {
2897     dev=$1
2898
2899     if [ -b "$dev" ]; then
2900         blockdev --getss $dev
2901     else
2902         $here/src/feature -s
2903     fi
2904 }
2905
2906 run_check()
2907 {
2908         echo "# $@" >> $seqres.full 2>&1
2909         "$@" >> $seqres.full 2>&1 || _fail "failed: '$@'"
2910 }
2911
2912 _run_btrfs_util_prog()
2913 {
2914         run_check $BTRFS_UTIL_PROG $*
2915 }
2916
2917 _require_btrfs_send_stream_version()
2918 {
2919         $BTRFS_UTIL_PROG send 2>&1 | \
2920                 grep '^[ \t]*\-\-stream\-version <version>' > /dev/null 2>&1
2921         if [ $? -ne 0 ]; then
2922                 _notrun "Missing btrfs-progs send --stream-version command line option, skipped this test"
2923         fi
2924
2925         # test if btrfs kernel supports send stream version 2
2926         if [ ! -f /sys/fs/btrfs/send/stream_version ]; then
2927                 _notrun "Missing btrfs kernel patch for send stream version 2, skipped this test"
2928         fi
2929 }
2930
2931 _require_btrfs_mkfs_feature()
2932 {
2933         if [ -z $1 ]; then
2934                 echo "Missing feature name argument for _require_btrfs_mkfs_feature"
2935                 exit 1
2936         fi
2937         feat=$1
2938         $MKFS_BTRFS_PROG -O list-all 2>&1 | \
2939                 grep '^[ \t]*'"$feat"'\b' > /dev/null 2>&1
2940         [ $? -eq 0 ] || \
2941                 _notrun "Feature $feat not supported in the available version of mkfs.btrfs"
2942 }
2943
2944 _require_btrfs_fs_feature()
2945 {
2946         if [ -z $1 ]; then
2947                 echo "Missing feature name argument for _require_btrfs_fs_feature"
2948                 exit 1
2949         fi
2950         feat=$1
2951         modprobe btrfs > /dev/null 2>&1
2952         [ -e /sys/fs/btrfs/features/$feat ] || \
2953                 _notrun "Feature $feat not supported by the available btrfs version"
2954 }
2955
2956 _require_test_symlinks()
2957 {
2958         # IRIX UDF does not support symlinks
2959         [ "$HOSTOS" = "IRIX" -a "$FSTYP" = 'udf' ] && \
2960                 _notrun "Require symlinks support"
2961         target=`mktemp -p $TEST_DIR`
2962         link=`mktemp -p $TEST_DIR -u`
2963         ln -s `basename $target` $link
2964         if [ "$?" -ne 0 ]; then
2965                 rm -f $target
2966                 _notrun "Require symlinks support"
2967         fi
2968         rm -f $target $link
2969 }
2970
2971 _require_test_fcntl_advisory_locks()
2972 {
2973         [ "$FSTYP" != "cifs" ] && return 0
2974         cat /proc/mounts | grep $TEST_DEV | grep cifs | grep -q "nobrl" && return 0
2975         cat /proc/mounts | grep $TEST_DEV | grep cifs | grep -qE "nounix|forcemand" && \
2976                 _notrun "Require fcntl advisory locks support"
2977 }
2978
2979 # XFS ability to change UUIDs on V5/CRC filesystems
2980 #
2981 _require_meta_uuid()
2982 {
2983         # This will create a crc fs on $SCRATCH_DEV
2984         _require_xfs_crc
2985
2986         $XFS_DB_PROG -x -c "uuid restore" $SCRATCH_DEV 2>&1 \
2987            | grep -q "invalid UUID\|supported on V5 fs" \
2988            && _notrun "Userspace doesn't support meta_uuid feature"
2989
2990         $XFS_DB_PROG -x -c "uuid generate" $SCRATCH_DEV >/dev/null 2>&1
2991
2992         _scratch_mount >/dev/null 2>&1 \
2993            || _notrun "Kernel doesn't support meta_uuid feature"
2994         _scratch_unmount
2995 }
2996
2997 _require_btrfs_dev_del_by_devid()
2998 {
2999         $BTRFS_UTIL_PROG device delete --help | egrep devid > /dev/null 2>&1
3000         [ $? -eq 0 ] || _notrun "$BTRFS_UTIL_PROG too old "\
3001                         "(must support 'btrfs device delete <devid> /<mnt>')"
3002 }
3003
3004 _require_test_lsattr()
3005 {
3006         testio=$(lsattr -d $TEST_DIR 2>&1)
3007         echo $testio | grep -q "Operation not supported" && \
3008                 _notrun "lsattr not supported by test filesystem type: $FSTYP"
3009         echo $testio | grep -q "Inappropriate ioctl for device" && \
3010                 _notrun "lsattr not supported by test filesystem type: $FSTYP"
3011 }
3012
3013 _get_total_inode()
3014 {
3015         if [ -z "$1" ]; then
3016                 echo "Usage: _get_total_inode <mnt>"
3017                 exit 1
3018         fi
3019         local nr_inode;
3020         nr_inode=`$DF_PROG -i $1 | tail -1 | awk '{print $3}'`
3021         echo $nr_inode
3022 }
3023
3024 _get_used_inode()
3025 {
3026         if [ -z "$1" ]; then
3027                 echo "Usage: _get_used_inode <mnt>"
3028                 exit 1
3029         fi
3030         local nr_inode;
3031         nr_inode=`$DF_PROG -i $1 | tail -1 | awk '{print $4}'`
3032         echo $nr_inode
3033 }
3034
3035 _get_used_inode_percent()
3036 {
3037         if [ -z "$1" ]; then
3038                 echo "Usage: _get_used_inode_percent <mnt>"
3039                 exit 1
3040         fi
3041         local pct_inode;
3042         pct_inode=`$DF_PROG -i $1 | tail -1 | awk '{ print $6 }' | \
3043                    sed -e 's/%//'`
3044         echo $pct_inode
3045 }
3046
3047 _get_free_inode()
3048 {
3049         if [ -z "$1" ]; then
3050                 echo "Usage: _get_free_inode <mnt>"
3051                 exit 1
3052         fi
3053         local nr_inode;
3054         nr_inode=`$DF_PROG -i $1 | tail -1 | awk '{print $5}'`
3055         echo $nr_inode
3056 }
3057
3058 # get the available space in bytes
3059 #
3060 _get_available_space()
3061 {
3062         if [ -z "$1" ]; then
3063                 echo "Usage: _get_available_space <mnt>"
3064                 exit 1
3065         fi
3066         local avail_kb;
3067         avail_kb=`$DF_PROG $1 | tail -n1 | awk '{ print $5 }'`
3068         echo $((avail_kb * 1024))
3069 }
3070
3071 # get btrfs profile configs being tested
3072 #
3073 # A set of pre-set profile configs are exported via _btrfs_profile_configs
3074 # array. Default configs can be overridden by setting BTRFS_PROFILE_CONFIGS
3075 # var in the format "metadata_profile:data_profile", multiple configs can be
3076 # seperated by space, e.g.
3077 # export BTRFS_PROFILE_CONFIGS="raid0:raid0 raid1:raid1 dup:single"
3078 _btrfs_get_profile_configs()
3079 {
3080         if [ "$FSTYP" != "btrfs" ]; then
3081                 return
3082         fi
3083
3084         # no user specified btrfs profile configs, export the default configs
3085         if [ -z "$BTRFS_PROFILE_CONFIGS" ]; then
3086                 # default configs
3087                 _btrfs_profile_configs=(
3088                         "-m single -d single"
3089                         "-m dup -d single"
3090                         "-m raid0 -d raid0"
3091                         "-m raid1 -d raid0"
3092                         "-m raid1 -d raid1"
3093                         "-m raid10 -d raid10"
3094                         "-m raid5 -d raid5"
3095                         "-m raid6 -d raid6"
3096                 )
3097
3098                 # remove dup/raid5/raid6 profiles if we're doing device replace
3099                 # dup profile indicates only one device being used (SCRATCH_DEV),
3100                 # but we don't want to replace SCRATCH_DEV, which will be used in
3101                 # _scratch_mount/_check_scratch_fs etc.
3102                 # and raid5/raid6 doesn't support replace yet
3103                 if [ "$1" == "replace" ]; then
3104                         _btrfs_profile_configs=(
3105                                 "-m single -d single"
3106                                 "-m raid0 -d raid0"
3107                                 "-m raid1 -d raid0"
3108                                 "-m raid1 -d raid1"
3109                                 "-m raid10 -d raid10"
3110                                 # add these back when raid5/6 is working with replace
3111                                 #"-m raid5 -d raid5"
3112                                 #"-m raid6 -d raid6"
3113                         )
3114                 fi
3115                 export _btrfs_profile_configs
3116                 return
3117         fi
3118
3119         # parse user specified btrfs profile configs
3120         local i=0
3121         local cfg=""
3122         for cfg in $BTRFS_PROFILE_CONFIGS; do
3123                 # turn "metadata:data" format to "-m metadata -d data"
3124                 # and assign it to _btrfs_profile_configs array
3125                 cfg=`echo "$cfg" | sed -e 's/^/-m /' -e 's/:/ -d /'`
3126                 _btrfs_profile_configs[$i]="$cfg"
3127                 let i=i+1
3128         done
3129
3130         if [ "$1" == "replace" ]; then
3131                 if echo ${_btrfs_profile_configs[*]} | grep -q raid[56]; then
3132                         _notrun "RAID5/6 doesn't support btrfs device replace yet"
3133                 fi
3134                 if echo ${_btrfs_profile_configs[*]} | grep -q dup; then
3135                         _notrun "Do not set dup profile in btrfs device replace test"
3136                 fi
3137         fi
3138         export _btrfs_profile_configs
3139 }
3140
3141 # stress btrfs by running balance operation in a loop
3142 _btrfs_stress_balance()
3143 {
3144         local btrfs_mnt=$1
3145         while true; do
3146                 $BTRFS_UTIL_PROG balance start $btrfs_mnt
3147         done
3148 }
3149
3150 # stress btrfs by creating/mounting/umounting/deleting subvolume in a loop
3151 _btrfs_stress_subvolume()
3152 {
3153         local btrfs_dev=$1
3154         local btrfs_mnt=$2
3155         local subvol_name=$3
3156         local subvol_mnt=$4
3157
3158         mkdir -p $subvol_mnt
3159         while true; do
3160                 $BTRFS_UTIL_PROG subvolume create $btrfs_mnt/$subvol_name
3161                 $MOUNT_PROG -o subvol=$subvol_name $btrfs_dev $subvol_mnt
3162                 $UMOUNT_PROG $subvol_mnt
3163                 $BTRFS_UTIL_PROG subvolume delete $btrfs_mnt/$subvol_name
3164         done
3165 }
3166
3167 # stress btrfs by running scrub in a loop
3168 _btrfs_stress_scrub()
3169 {
3170         local btrfs_mnt=$1
3171         while true; do
3172                 $BTRFS_UTIL_PROG scrub start -B $btrfs_mnt
3173         done
3174 }
3175
3176 # stress btrfs by defragmenting every file/dir in a loop and compress file
3177 # contents while defragmenting if second argument is not "nocompress"
3178 _btrfs_stress_defrag()
3179 {
3180         local btrfs_mnt=$1
3181         local compress=$2
3182
3183         while true; do
3184                 if [ "$compress" == "nocompress" ]; then
3185                         find $btrfs_mnt \( -type f -o -type d \) -exec \
3186                         $BTRFS_UTIL_PROG filesystem defrag {} \;
3187                 else
3188                         find $btrfs_mnt \( -type f -o -type d \) -exec \
3189                         $BTRFS_UTIL_PROG filesystem defrag -clzo {} \;
3190                         find $btrfs_mnt \( -type f -o -type d \) -exec \
3191                         $BTRFS_UTIL_PROG filesystem defrag -czlib {} \;
3192                 fi
3193         done
3194 }
3195
3196 # stress btrfs by remounting it with different compression algorithms in a loop
3197 # run this with fsstress running at background could exercise the compression
3198 # code path and ensure no race when switching compression algorithm with constant
3199 # I/O activity.
3200 _btrfs_stress_remount_compress()
3201 {
3202         local btrfs_mnt=$1
3203         while true; do
3204                 for algo in no zlib lzo; do
3205                         $MOUNT_PROG -o remount,compress=$algo $btrfs_mnt
3206                 done
3207         done
3208 }
3209
3210 # stress btrfs by replacing devices in a loop
3211 # Note that at least 3 devices are needed in SCRATCH_DEV_POOL and the last
3212 # device should be free(not used by btrfs)
3213 _btrfs_stress_replace()
3214 {
3215         local btrfs_mnt=$1
3216
3217         # The device number in SCRATCH_DEV_POOL should be at least 3,
3218         # one is SCRATCH_DEV, one is to be replaced, one is free device
3219         # we won't replace SCRATCH_DEV, see below for reason
3220         if [ "`echo $SCRATCH_DEV_POOL | wc -w`" -lt 3 ]; then
3221                 echo "_btrfs_stress_replace requires at least 3 devices in SCRATCH_DEV_POOL"
3222                 return
3223         fi
3224
3225         # take the last device as the first free_dev
3226         local free_dev="`echo $SCRATCH_DEV_POOL | $AWK_PROG '{print $NF}'`"
3227
3228         # free_dev should be really free
3229         if $BTRFS_UTIL_PROG filesystem show $btrfs_mnt | grep -q "$free_dev"; then
3230                 echo "_btrfs_stress_replace: $free_dev is used by btrfs"
3231                 return
3232         fi
3233
3234         # dev_pool is device list being currently used by btrfs (excluding SCRATCH_DEV)
3235         # and can be replaced. We don't replace SCRATCH_DEV because it will be used in
3236         # _scratch_mount and _check_scratch_fs etc.
3237         local dev_pool=`echo $SCRATCH_DEV_POOL | sed -e "s# *$SCRATCH_DEV *##" \
3238                         -e "s# *$free_dev *##"`
3239
3240         # set the first device in dev_pool as the first src_dev to be replaced
3241         local src_dev=`echo $dev_pool | $AWK_PROG '{print $1}'`
3242
3243         echo "dev_pool=$dev_pool"
3244         echo "free_dev=$free_dev, src_dev=$src_dev"
3245         while true; do
3246                 echo "Replacing $src_dev with $free_dev"
3247                 $BTRFS_UTIL_PROG replace start -fB $src_dev $free_dev $btrfs_mnt
3248                 if [ $? -ne 0 ]; then
3249                         # don't update src_dev and free_dev if replace failed
3250                         continue
3251                 fi
3252                 dev_pool="$dev_pool $free_dev"
3253                 dev_pool=`echo $dev_pool | sed -e "s# *$src_dev *##"`
3254                 free_dev=$src_dev
3255                 src_dev=`echo $dev_pool | $AWK_PROG '{print $1}'`
3256         done
3257 }
3258
3259 # find the right option to force output in bytes, older versions of btrfs-progs
3260 # print that by default, newer print human readable numbers with unit suffix
3261 _btrfs_qgroup_units()
3262 {
3263         $BTRFS_UTIL_PROG qgroup show --help 2>&1 | grep -q -- --raw && echo "--raw"
3264 }
3265
3266 # return device size in kb
3267 _get_device_size()
3268 {
3269         grep `_short_dev $1` /proc/partitions | awk '{print $3}'
3270 }
3271
3272 # check dmesg log for WARNING/Oops/etc.
3273 _check_dmesg()
3274 {
3275         if [ ! -f ${RESULT_DIR}/check_dmesg ]; then
3276                 return 0
3277         fi
3278         rm -f ${RESULT_DIR}/check_dmesg
3279
3280         # default filter is a simple cat command, caller could provide a
3281         # customized filter and pass the name through the first argument, to
3282         # filter out intentional WARNINGs or Oopses
3283         filter=${1:-cat}
3284
3285         # search the dmesg log of last run of $seqnum for possible failures
3286         # use sed \cregexpc address type, since $seqnum contains "/"
3287         dmesg | tac | sed -ne "0,\#run fstests $seqnum at $date_time#p" | \
3288                 tac | $filter >$seqres.dmesg
3289         grep -q -e "kernel BUG at" \
3290              -e "WARNING:" \
3291              -e "BUG:" \
3292              -e "Oops:" \
3293              -e "possible recursive locking detected" \
3294              -e "Internal error" \
3295              -e "INFO: suspicious RCU usage" \
3296              -e "INFO: possible circular locking dependency detected" \
3297              $seqres.dmesg
3298         if [ $? -eq 0 ]; then
3299                 echo "_check_dmesg: something found in dmesg (see $seqres.dmesg)"
3300                 return 1
3301         else
3302                 rm -f $seqres.dmesg
3303                 return 0
3304         fi
3305 }
3306
3307 # don't check dmesg log after test
3308 _disable_dmesg_check()
3309 {
3310         rm -f ${RESULT_DIR}/check_dmesg
3311 }
3312
3313 init_rc()
3314 {
3315         if [ "$iam" == new ]
3316         then
3317                 return
3318         fi
3319         # make some further configuration checks here
3320         if [ "$TEST_DEV" = ""  ]
3321         then
3322                 echo "common/rc: Error: \$TEST_DEV is not set"
3323                 exit 1
3324         fi
3325
3326         # if $TEST_DEV is not mounted, mount it now as XFS
3327         if [ -z "`_fs_type $TEST_DEV`" ]
3328         then
3329                 # $TEST_DEV is not mounted
3330                 if ! _test_mount
3331                 then
3332                         echo "common/rc: retrying test device mount with external set"
3333                         [ "$USE_EXTERNAL" != "yes" ] && export USE_EXTERNAL=yes
3334                         if ! _test_mount
3335                         then
3336                                 echo "common/rc: could not mount $TEST_DEV on $TEST_DIR"
3337                                 exit 1
3338                         fi
3339                 fi
3340         fi
3341
3342         if [ "`_fs_type $TEST_DEV`" != "$FSTYP" ]
3343         then
3344                 echo "common/rc: Error: \$TEST_DEV ($TEST_DEV) is not a MOUNTED $FSTYP filesystem"
3345                 # raw $DF_PROG cannot handle NFS/CIFS/overlay correctly
3346                 _df_device $TEST_DEV
3347                 exit 1
3348         fi
3349         # Figure out if we need to add -F ("foreign", deprecated) option to xfs_io
3350         xfs_io -c stat $TEST_DIR 2>&1 | grep -q "is not on an XFS filesystem" && \
3351         export XFS_IO_PROG="$XFS_IO_PROG -F"
3352
3353         # xfs_copy doesn't work on v5 xfs yet without -d option
3354         if [ "$FSTYP" == "xfs" ] && [[ $MKFS_OPTIONS =~ crc=1 ]]; then
3355                 export XFS_COPY_PROG="$XFS_COPY_PROG -d"
3356         fi
3357 }
3358
3359 # get real device path name by following link
3360 _real_dev()
3361 {
3362         local _dev=$1
3363         if [ -b "$_dev" ] && [ -L "$_dev" ]; then
3364                 _dev=`readlink -f "$_dev"`
3365         fi
3366         echo $_dev
3367 }
3368
3369 # basename of a device
3370 _short_dev()
3371 {
3372         echo `basename $(_real_dev $1)`
3373 }
3374
3375 _sysfs_dev()
3376 {
3377         local _dev=$1
3378         local _maj=$(stat -c%t $_dev | tr [:lower:] [:upper:])
3379         local _min=$(stat -c%T $_dev | tr [:lower:] [:upper:])
3380         _maj=$(echo "ibase=16; $_maj" | bc)
3381         _min=$(echo "ibase=16; $_min" | bc)
3382         echo /sys/dev/block/$_maj:$_min
3383 }
3384
3385 get_block_size()
3386 {
3387         if [ -z $1 ] || [ ! -d $1 ]; then
3388                 echo "Missing mount point argument for get_block_size"
3389                 exit 1
3390         fi
3391         echo `stat -f -c %S $1`
3392 }
3393
3394 get_page_size()
3395 {
3396         echo $(getconf PAGE_SIZE)
3397 }
3398
3399
3400 run_fsx()
3401 {
3402         echo fsx $@
3403         args=`echo $@ | sed -e "s/ BSIZE / $bsize /g" -e "s/ PSIZE / $psize /g"`
3404         set -- $here/ltp/fsx $args $FSX_AVOID $TEST_DIR/junk
3405         echo "$@" >>$seqres.full
3406         rm -f $TEST_DIR/junk
3407         "$@" 2>&1 | tee -a $seqres.full >$tmp.fsx
3408         if [ ${PIPESTATUS[0]} -ne 0 ]; then
3409                 cat $tmp.fsx
3410                 exit 1
3411         fi
3412 }
3413
3414 init_rc
3415
3416 ################################################################################
3417 # make sure this script returns success
3418 /bin/true