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