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