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