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