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