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