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