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