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