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