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