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