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