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