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