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