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