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