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