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