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