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