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