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