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