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