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