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