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