common: add cifs support
[xfstests-dev.git] / common / rc
1 ##/bin/bash
2 #-----------------------------------------------------------------------
3 #  Copyright (c) 2000-2006 Silicon Graphics, Inc.  All Rights Reserved.
4 #  This program is free software; you can redistribute it and/or modify
5 #  it under the terms of the GNU General Public License as published by
6 #  the Free Software Foundation; either version 2 of the License, or
7 #  (at your option) any later version.
8 #
9 #  This program is distributed in the hope that it will be useful,
10 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 #  GNU General Public License for more details.
13 #
14 #  You should have received a copy of the GNU General Public License
15 #  along with this program; if not, write to the Free Software
16 #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
17 #  USA
18 #
19 #  Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
20 #  Mountain View, CA 94043, USA, or: http://www.sgi.com
21 #-----------------------------------------------------------------------
22
23 BC=$(which bc 2> /dev/null) || BC=
24
25 _require_math()
26 {
27         if [ -z "$BC" ]; then
28                 _notrun "this test requires 'bc' tool for doing math operations"
29         fi
30 }
31
32 _math()
33 {
34         [ $# -le 0 ] && return
35         if [ "$BC" ]; then
36                 result=$(LANG=C echo "scale=0; $@" | "$BC" -q 2> /dev/null)
37         else
38                 _notrun "this test requires 'bc' tool for doing math operations"
39         fi
40         echo "$result"
41 }
42
43 dd()
44 {
45    if [ "$HOSTOS" == "Linux" ]
46    then 
47         command dd --help | grep noxfer > /dev/null 2>&1
48         
49         if [ "$?" -eq 0 ]
50             then
51                 command dd status=noxfer $@
52             else
53                 command dd $@
54         fi
55    else
56         command dd $@
57    fi
58 }
59
60 _btrfs_get_subvolid()
61 {
62         mnt=$1
63         name=$2
64
65         $BTRFS_UTIL_PROG sub list $mnt | grep $name | awk '{ print $2 }'
66 }
67
68 # Prints the md5 checksum of a given file
69 _md5_checksum()
70 {
71         md5sum $1 | cut -d ' ' -f1
72 }
73
74
75 # ls -l w/ selinux sometimes puts a dot at the end:
76 # -rwxrw-r--. id1 id2 file1
77 # Also filter out lost+found directory on extN file system if present
78
79 _ls_l()
80 {
81         ls -l $* | sed "s/\(^[-rwxdlbcpsStT]*\)\. /\1 /" | grep -v 'lost+found'
82 }
83
84 # we need common/config
85 if [ "$iam" != "check" ]
86 then
87     if ! . ./common/config
88         then
89         echo "$iam: failed to source common/config"
90         exit 1
91     fi
92 fi
93
94 # check for correct setup
95 case "$FSTYP" in
96     xfs)
97          [ "$XFS_LOGPRINT_PROG" = "" ] && _fatal "xfs_logprint not found"
98          [ "$XFS_REPAIR_PROG" = "" ] && _fatal "xfs_repair not found"
99          [ "$XFS_DB_PROG" = "" ] && _fatal "xfs_db not found"
100          [ "$MKFS_XFS_PROG" = "" ] && _fatal "mkfs_xfs not found"
101          ;;
102     udf)
103          [ "$MKFS_UDF_PROG" = "" ] && _fatal "mkfs_udf/mkudffs not found"
104          ;;
105     btrfs)
106          [ "$MKFS_BTRFS_PROG" = "" ] && _fatal "mkfs.btrfs not found"
107          ;;
108     nfs)
109          ;;
110     cifs)
111          ;;
112 esac
113
114 # make sure we have a standard umask
115 umask 022
116
117 _mount()
118 {
119     $MOUNT_PROG `_mount_ops_filter $*`
120 }
121
122 _scratch_options()
123 {
124     type=$1
125     SCRATCH_OPTIONS=""
126
127     if [ "$FSTYP" != "xfs" ]; then
128         return
129     fi
130
131     case $type in
132     mkfs)
133         [ "$HOSTOS" != "IRIX" ] && SCRATCH_OPTIONS="$SCRATCH_OPTIONS -f"
134         rt_opt="-r"
135         log_opt="-l"
136         ;;
137     mount)
138         rt_opt="-o"
139         log_opt="-o"
140         ;;
141     esac
142     [ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_RTDEV" ] && \
143         SCRATCH_OPTIONS="$SCRATCH_OPTIONS ${rt_opt}rtdev=$SCRATCH_RTDEV"
144     [ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_LOGDEV" ] && \
145         SCRATCH_OPTIONS="$SCRATCH_OPTIONS ${log_opt}logdev=$SCRATCH_LOGDEV"
146 }
147
148 _test_options()
149 {
150     type=$1
151     TEST_OPTIONS=""
152
153     if [ "$FSTYP" != "xfs" ]; then
154         return
155     fi
156
157     case $type in
158     mkfs)
159         rt_opt="-r"
160         log_opt="-l"
161         ;;
162     mount)
163         rt_opt="-o"
164         log_opt="-o"
165         ;;
166     esac
167     [ "$USE_EXTERNAL" = yes -a ! -z "$TEST_RTDEV" ] && \
168         TEST_OPTIONS="$TEST_OPTIONS ${rt_opt}rtdev=$TEST_RTDEV"
169     [ "$USE_EXTERNAL" = yes -a ! -z "$TEST_LOGDEV" ] && \
170         TEST_OPTIONS="$TEST_OPTIONS ${log_opt}logdev=$TEST_LOGDEV"
171 }
172
173 _mount_ops_filter()
174 {
175     params="$*"
176     
177     #get mount point to handle dmapi mtpt option correctly
178     let last_index=$#-1
179     [ $last_index -gt 0 ] && shift $last_index
180     FS_ESCAPED=$1
181     
182     # irix is fussy about how it is fed its mount options
183     # - multiple -o's are not allowed
184     # - no spaces between comma delimitered options
185     # the sed script replaces all -o's (except the first) with a comma
186     # not required for linux, but won't hurt
187     
188     echo $params | sed -e 's/[[:space:]]\+-o[[:space:]]*/UnIqUe/1; s/[[:space:]]\+-o[[:space:]]*/,/g; s/UnIqUe/ -o /1' \
189         | sed -e 's/dmapi/dmi/' \
190         | $PERL_PROG -ne "s#mtpt=[^,|^\n|^\s]*#mtpt=$FS_ESCAPED\1\2#; print;"
191
192 }
193
194 _scratch_mount_options()
195 {
196     _scratch_options mount
197
198     echo $SCRATCH_OPTIONS $MOUNT_OPTIONS $SELINUX_MOUNT_OPTIONS $* $SCRATCH_DEV $SCRATCH_MNT
199 }
200
201 _scratch_mount()
202 {
203     _mount -t $FSTYP `_scratch_mount_options $*`
204 }
205
206 _scratch_unmount()
207 {
208     $UMOUNT_PROG $SCRATCH_DEV
209 }
210
211 _scratch_remount()
212 {
213     _scratch_unmount
214     _scratch_mount
215 }
216
217 _test_mount()
218 {
219     _test_options mount
220     _mount -t $FSTYP $TEST_OPTIONS $TEST_FS_MOUNT_OPTS $SELINUX_MOUNT_OPTIONS $* $TEST_DEV $TEST_DIR
221 }
222
223 _test_remount()
224 {
225     $UMOUNT_PROG $TEST_DEV
226     _test_mount
227 }
228
229 _scratch_mkfs_options()
230 {
231     _scratch_options mkfs
232     echo $SCRATCH_OPTIONS $MKFS_OPTIONS $* $SCRATCH_DEV
233 }
234
235 _scratch_metadump()
236 {
237         dumpfile=$1
238         options=
239
240         [ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_LOGDEV" ] && \
241                 options="-l $SCRATCH_LOGDEV"
242
243         xfs_metadump $options $SCRATCH_DEV $dumpfile
244 }
245
246 _setup_large_xfs_fs()
247 {
248         fs_size=$1
249         local tmp_dir=/tmp/
250
251         [ "$LARGE_SCRATCH_DEV" != yes ] && return 0
252         [ -z "$SCRATCH_DEV_EMPTY_SPACE" ] && SCRATCH_DEV_EMPTY_SPACE=0
253         [ $SCRATCH_DEV_EMPTY_SPACE -ge $fs_size ] && return 0
254
255         # calculate the size of the file we need to allocate.
256         # Default free space in the FS is 50GB, but you can specify more via
257         # SCRATCH_DEV_EMPTY_SPACE
258         file_size=$(($fs_size - 50*1024*1024*1024))
259         file_size=$(($file_size - $SCRATCH_DEV_EMPTY_SPACE))
260
261         # mount the filesystem, create the file, unmount it
262         _scratch_mount 2>&1 >$tmp_dir/mnt.err
263         local status=$?
264         if [ $status -ne 0 ]; then
265                 echo "mount failed"
266                 cat $tmp_dir/mnt.err >&2
267                 rm -f $tmp_dir/mnt.err
268                 return $status
269         fi
270         rm -f $tmp_dir/mnt.err
271
272         xfs_io -F -f \
273                 -c "truncate $file_size" \
274                 -c "falloc -k 0 $file_size" \
275                 -c "chattr +d" \
276                 $SCRATCH_MNT/.use_space 2>&1 > /dev/null
277         export NUM_SPACE_FILES=1
278         status=$?
279         umount $SCRATCH_MNT
280         if [ $status -ne 0 ]; then
281                 echo "large file prealloc failed"
282                 cat $tmp_dir/mnt.err >&2
283                 return $status
284         fi
285         return 0
286 }
287
288 _scratch_mkfs_xfs_opts()
289 {
290         mkfs_opts=$*
291
292         _scratch_options mkfs
293
294         $MKFS_XFS_PROG $SCRATCH_OPTIONS $mkfs_opts $SCRATCH_DEV
295 }
296
297
298 _scratch_mkfs_xfs_supported()
299 {
300         mkfs_opts=$*
301
302         _scratch_options mkfs
303
304         $MKFS_XFS_PROG -N $MKFS_OPTIONS $SCRATCH_OPTIONS $mkfs_opts $SCRATCH_DEV
305 }
306
307 _scratch_mkfs_xfs()
308 {
309         # extra mkfs options can be added by tests
310         local extra_mkfs_options=$*
311
312         local tmp_dir=/tmp/
313
314         # save mkfs output in case conflict means we need to run again.
315         # only the output for the mkfs that applies should be shown
316         _scratch_mkfs_xfs_opts $MKFS_OPTIONS $extra_mkfs_options \
317                 2>$tmp_dir.mkfserr 1>$tmp_dir.mkfsstd
318         local mkfs_status=$?
319
320
321         # a mkfs failure may be caused by conflicts between
322         # $MKFS_OPTIONS and $extra_mkfs_options
323         if [ $mkfs_status -ne 0 -a ! -z "$extra_mkfs_options" ]; then
324                 (
325                 echo -n "** mkfs failed with extra mkfs options "
326                 echo "added to \"$MKFS_OPTIONS\" by test $seq **"
327                 echo -n "** attempting to mkfs using only test $seq "
328                 echo "options: $extra_mkfs_options **"
329                 ) >> $seqres.full
330
331                 # running mkfs again. overwrite previous mkfs output files
332                 _scratch_mkfs_xfs_opts $extra_mkfs_options \
333                         2>$tmp_dir.mkfserr 1>$tmp_dir.mkfsstd
334                 local mkfs_status=$?
335         fi
336
337         if [ $mkfs_status -eq 0 -a "$LARGE_SCRATCH_DEV" = yes ]; then
338                 # manually parse the mkfs output to get the fs size in bytes
339                 local fs_size
340                 fs_size=`cat $tmp_dir.mkfsstd | perl -ne '
341                         if (/^data\s+=\s+bsize=(\d+)\s+blocks=(\d+)/) {
342                                 my $size = $1 * $2;
343                                 print STDOUT "$size\n";
344                         }'`
345                 _setup_large_xfs_fs $fs_size
346                 mkfs_status=$?
347         fi
348
349         # output stored mkfs output
350         cat $tmp_dir.mkfserr >&2
351         cat $tmp_dir.mkfsstd
352         rm -f $tmp_dir.mkfserr $tmp_dir.mkfsstd
353
354         return $mkfs_status
355 }
356
357 # xfs_check script is planned to be deprecated. But, we want to
358 # be able to invoke "xfs_check" behavior in xfstests in order to
359 # maintain the current verification levels.
360 _xfs_check()
361 {
362     OPTS=" "
363     DBOPTS=" "
364     USAGE="Usage: xfs_check [-fsvV] [-l logdev] [-i ino]... [-b bno]... special"
365
366     while getopts "b:fi:l:stvV" c
367     do
368         case $c in
369             s) OPTS=$OPTS"-s ";;
370             t) OPTS=$OPTS"-t ";;
371             v) OPTS=$OPTS"-v ";;
372             i) OPTS=$OPTS"-i "$OPTARG" ";;
373             b) OPTS=$OPTS"-b "$OPTARG" ";;
374             f) DBOPTS=$DBOPTS" -f";;
375             l) DBOPTS=$DBOPTS" -l "$OPTARG" ";;
376             V) $XFS_DB_PROG -p xfs_check -V
377                 return $?
378                 ;;
379         esac
380     done
381     set -- extra $@
382     shift $OPTIND
383     case $# in
384         1)    ${XFS_DB_PROG}${DBOPTS} -F -i -p xfs_check -c "check$OPTS" $1
385                status=$?
386                ;;
387         2)    echo $USAGE 1>&1
388               status=2
389               ;;
390     esac
391     return $status
392 }
393
394 _setup_large_ext4_fs()
395 {
396         fs_size=$1
397         local tmp_dir=/tmp/
398
399         [ "$LARGE_SCRATCH_DEV" != yes ] && return 0
400         [ -z "$SCRATCH_DEV_EMPTY_SPACE" ] && SCRATCH_DEV_EMPTY_SPACE=0
401         [ $SCRATCH_DEV_EMPTY_SPACE -ge $fs_size ] && return 0
402
403         # Default free space in the FS is 50GB, but you can specify more via
404         # SCRATCH_DEV_EMPTY_SPACE
405         space_to_consume=$(($fs_size - 50*1024*1024*1024 - $SCRATCH_DEV_EMPTY_SPACE))
406
407         # mount the filesystem and create 16TB - 4KB files until we consume
408         # all the necessary space.
409         _scratch_mount 2>&1 >$tmp_dir/mnt.err
410         local status=$?
411         if [ $status -ne 0 ]; then
412                 echo "mount failed"
413                 cat $tmp_dir/mnt.err >&2
414                 rm -f $tmp_dir/mnt.err
415                 return $status
416         fi
417         rm -f $tmp_dir/mnt.err
418
419         file_size=$((16*1024*1024*1024*1024 - 4096))
420         nfiles=0
421         while [ $space_to_consume -gt $file_size ]; do
422
423                 xfs_io -F -f \
424                         -c "truncate $file_size" \
425                         -c "falloc -k 0 $file_size" \
426                         $SCRATCH_MNT/.use_space.$nfiles 2>&1
427                 status=$?
428                 if [ $status -ne 0 ]; then
429                         break;
430                 fi
431
432                 space_to_consume=$(( $space_to_consume - $file_size ))
433                 nfiles=$(($nfiles + 1))
434         done
435
436         # consume the remaining space.
437         if [ $space_to_consume -gt 0 ]; then
438                 xfs_io -F -f \
439                         -c "truncate $space_to_consume" \
440                         -c "falloc -k 0 $space_to_consume" \
441                         $SCRATCH_MNT/.use_space.$nfiles 2>&1
442                 status=$?
443         fi
444         export NUM_SPACE_FILES=$nfiles
445
446         umount $SCRATCH_MNT
447         if [ $status -ne 0 ]; then
448                 echo "large file prealloc failed"
449                 cat $tmp_dir/mnt.err >&2
450                 return $status
451         fi
452         return 0
453 }
454
455 _scratch_mkfs_ext4()
456 {
457         # extra mkfs options can be added by tests
458         local extra_mkfs_options=$*
459
460         local tmp_dir=/tmp/
461
462         /sbin/mkfs -t ext4 -- -F $MKFS_OPTIONS $extra_mkfs_options $SCRATCH_DEV \
463                         2>$tmp_dir.mkfserr 1>$tmp_dir.mkfsstd
464         local mkfs_status=$?
465
466         # a mkfs failure may be caused by conflicts between
467         # $MKFS_OPTIONS and $extra_mkfs_options
468         if [ $mkfs_status -ne 0 -a ! -z "$extra_mkfs_options" ]; then
469                 (
470                 echo -n "** mkfs failed with extra mkfs options "
471                 echo "added to \"$MKFS_OPTIONS\" by test $seq **"
472                 echo -n "** attempting to mkfs using only test $seq "
473                 echo "options: $extra_mkfs_options **"
474                 ) >> $seqres.full
475
476                 # running mkfs again. overwrite previous mkfs output files
477                 /sbin/mkfs -t ext4 -- -F $extra_mkfs_options $SCRATCH_DEV \
478                                 2>$tmp_dir.mkfserr 1>$tmp_dir.mkfsstd
479                 local mkfs_status=$?
480         fi
481
482         if [ $mkfs_status -eq 0 -a "$LARGE_SCRATCH_DEV" = yes ]; then
483                 # manually parse the mkfs output to get the fs size in bytes
484                 fs_size=`cat $tmp_dir.mkfsstd | awk ' \
485                         /^Block size/ { split($2, a, "="); bs = a[2] ; } \
486                         / inodes, / { blks = $3 } \
487                         /reserved for the super user/ { resv = $1 } \
488                         END { fssize = bs * blks - resv; print fssize }'`
489
490                 _setup_large_ext4_fs $fs_size
491                 mkfs_status=$?
492         fi
493
494         # output stored mkfs output
495         cat $tmp_dir.mkfserr >&2
496         cat $tmp_dir.mkfsstd
497         rm -f $tmp_dir.mkfserr $tmp_dir.mkfsstd
498
499         return $mkfs_status
500 }
501
502 _test_mkfs()
503 {
504     case $FSTYP in
505     nfs*)
506         # do nothing for nfs
507         ;;
508     cifs)
509         # do nothing for cifs
510         ;;
511     udf)
512         $MKFS_UDF_PROG $MKFS_OPTIONS $* $TEST_DEV > /dev/null
513         ;;
514     btrfs)
515         $MKFS_BTRFS_PROG $MKFS_OPTIONS $* $TEST_DEV > /dev/null
516         ;;
517     *)
518         yes | $MKFS_PROG -t $FSTYP -- $MKFS_OPTIONS $* $TEST_DEV
519         ;;
520     esac
521 }
522
523 _mkfs_dev()
524 {
525     case $FSTYP in
526     nfs*)
527         # do nothing for nfs
528         ;;
529     udf)
530         $MKFS_UDF_PROG $MKFS_OPTIONS $* 2>$tmp_dir.mkfserr 1>$tmp_dir.mkfsstd
531         ;;
532     btrfs)
533         $MKFS_BTRFS_PROG $MKFS_OPTIONS $* 2>$tmp_dir.mkfserr 1>$tmp_dir.mkfsstd
534         ;;
535     *)
536         yes | $MKFS_PROG -t $FSTYP -- $MKFS_OPTIONS $* \
537                 2>$tmp_dir.mkfserr 1>$tmp_dir.mkfsstd
538         ;;
539     esac
540
541     if [ $? -ne 0 ]; then
542         # output stored mkfs output
543         cat $tmp_dir.mkfserr >&2
544         cat $tmp_dir.mkfsstd
545         status=1
546         exit 1
547     fi
548     rm -f $tmp_dir.mkfserr $tmp_dir.mkfsstd
549 }
550
551 _scratch_mkfs()
552 {
553     case $FSTYP in
554     xfs)
555         _scratch_mkfs_xfs $*
556         ;;
557     nfs*)
558         # do nothing for nfs
559         ;;
560     cifs)
561         # do nothing for cifs
562         ;;
563     udf)
564         $MKFS_UDF_PROG $MKFS_OPTIONS $* $SCRATCH_DEV > /dev/null
565         ;;
566     btrfs)
567         $MKFS_BTRFS_PROG $MKFS_OPTIONS $* $SCRATCH_DEV > /dev/null
568         ;;
569     ext4)
570         _scratch_mkfs_ext4 $*
571         ;;
572     tmpfs)
573         # do nothing for tmpfs
574         ;;
575     *)
576         yes | $MKFS_PROG -t $FSTYP -- $MKFS_OPTIONS $* $SCRATCH_DEV
577         ;;
578     esac
579 }
580
581 _scratch_pool_mkfs()
582 {
583     case $FSTYP in
584     btrfs)
585         $MKFS_BTRFS_PROG $MKFS_OPTIONS $* $SCRATCH_DEV_POOL > /dev/null
586         ;;
587     *)
588         echo "_scratch_pool_mkfs is not implemented for $FSTYP" 1>&2
589         ;;
590     esac
591 }
592
593 # Create fs of certain size on scratch device
594 # _scratch_mkfs_sized <size in bytes> [optional blocksize]
595 _scratch_mkfs_sized()
596 {
597     fssize=$1
598     blocksize=$2
599
600     case $FSTYP in
601     xfs)
602         def_blksz=`echo $MKFS_OPTIONS|sed -rn 's/.*-b ?size= ?+([0-9]+).*/\1/p'`
603         ;;
604     ext2|ext3|ext4|ext4dev|udf|btrfs)
605         def_blksz=`echo $MKFS_OPTIONS| sed -rn 's/.*-b ?+([0-9]+).*/\1/p'`
606         ;;
607     esac
608
609     [ -n "$def_blksz" ] && blocksize=$def_blksz
610     [ -z "$blocksize" ] && blocksize=4096
611
612
613     re='^[0-9]+$'
614     if ! [[ $fssize =~ $re ]] ; then
615         _notrun "error: _scratch_mkfs_sized: fs size \"$fssize\" not an integer."
616     fi
617     if ! [[ $blocksize =~ $re ]] ; then
618         _notrun "error: _scratch_mkfs_sized: block size \"$blocksize\" not an integer."
619     fi
620
621     blocks=`expr $fssize / $blocksize`
622
623     if [ "$HOSTOS" == "Linux" ]; then
624         devsize=`blockdev --getsize64 $SCRATCH_DEV`
625         [ "$fssize" -gt "$devsize" ] && _notrun "Scratch device too small"
626     fi
627
628     case $FSTYP in
629     xfs)
630         # don't override MKFS_OPTIONS that set a block size.
631         echo $MKFS_OPTIONS |egrep -q "b?size="
632         if [ $? -eq 0 ]; then
633                 _scratch_mkfs_xfs -d size=$fssize
634         else
635                 _scratch_mkfs_xfs -d size=$fssize -b size=$blocksize
636         fi
637         ;;
638     ext2|ext3|ext4|ext4dev)
639         yes | ${MKFS_PROG}.$FSTYP $MKFS_OPTIONS -b $blocksize $SCRATCH_DEV $blocks
640         ;;
641     udf)
642         $MKFS_UDF_PROG $MKFS_OPTIONS -b $blocksize $SCRATCH_DEV $blocks
643         ;;
644     btrfs)
645         $MKFS_BTRFS_PROG $MKFS_OPTIONS -b $fssize $SCRATCH_DEV
646         ;;
647     *)
648         _notrun "Filesystem $FSTYP not supported in _scratch_mkfs_sized"
649         ;;
650     esac
651 }
652
653 # Emulate an N-data-disk stripe w/ various stripe units
654 # _scratch_mkfs_geom <sunit bytes> <swidth multiplier> [optional blocksize]
655 _scratch_mkfs_geom()
656 {
657     sunit_bytes=$1
658     swidth_mult=$2
659     blocksize=$3
660     [ -z "$blocksize" ] && blocksize=4096
661
662     let sunit_blocks=$sunit_bytes/$blocksize
663     let swidth_blocks=$sunit_blocks*$swidth_mult
664
665     case $FSTYP in
666     xfs)
667         MKFS_OPTIONS+=" -b size=$blocksize, -d su=$sunit_bytes,sw=$swidth_mult"
668         ;;
669     ext4|ext4dev)
670         MKFS_OPTIONS+=" -b $blocksize -E stride=$sunit_blocks,stripe_width=$swidth_blocks"
671         ;;
672     *)
673         _notrun "can't mkfs $FSTYP with geometry"
674         ;;
675     esac
676     _scratch_mkfs
677 }
678
679 _scratch_resvblks()
680 {
681         case $FSTYP in
682         xfs)
683                 xfs_io -x -c "resblks $1" $SCRATCH_MNT
684                 ;;
685         *)
686                 ;;
687         esac
688 }
689
690 _scratch_xfs_db_options()
691 {
692     SCRATCH_OPTIONS=""
693     [ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_LOGDEV" ] && \
694         SCRATCH_OPTIONS="-l$SCRATCH_LOGDEV"
695     echo $SCRATCH_OPTIONS $* $SCRATCH_DEV
696 }
697
698 _scratch_xfs_logprint()
699 {
700     SCRATCH_OPTIONS=""
701     [ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_LOGDEV" ] && \
702         SCRATCH_OPTIONS="-l$SCRATCH_LOGDEV"
703     $XFS_LOGPRINT_PROG $SCRATCH_OPTIONS $* $SCRATCH_DEV
704 }
705
706 _scratch_xfs_check()
707 {
708     SCRATCH_OPTIONS=""
709     [ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_LOGDEV" ] && \
710         SCRATCH_OPTIONS="-l $SCRATCH_LOGDEV"
711     [ "$LARGE_SCRATCH_DEV" = yes ] && \
712         SCRATCH_OPTIONS=$SCRATCH_OPTIONS" -t"
713     _xfs_check $SCRATCH_OPTIONS $* $SCRATCH_DEV
714 }
715
716 _scratch_xfs_repair()
717 {
718     SCRATCH_OPTIONS=""
719     [ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_LOGDEV" ] && \
720         SCRATCH_OPTIONS="-l$SCRATCH_LOGDEV"
721     [ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_RTDEV" ] && \
722         SCRATCH_OPTIONS=$SCRATCH_OPTIONS" -r$SCRATCH_RTDEV"
723     [ "$LARGE_SCRATCH_DEV" = yes ] && SCRATCH_OPTIONS=$SCRATCH_OPTIONS" -t"
724     $XFS_REPAIR_PROG $SCRATCH_OPTIONS $* $SCRATCH_DEV
725 }
726
727 _get_pids_by_name()
728 {
729     if [ $# -ne 1 ]
730     then
731         echo "Usage: _get_pids_by_name process-name" 1>&2
732         exit 1
733     fi
734
735     # Algorithm ... all ps(1) variants have a time of the form MM:SS or
736     # HH:MM:SS before the psargs field, use this as the search anchor.
737     #
738     # Matches with $1 (process-name) occur if the first psarg is $1
739     # or ends in /$1 ... the matching uses sed's regular expressions,
740     # so passing a regex into $1 will work.
741
742     ps $PS_ALL_FLAGS \
743     | sed -n \
744         -e 's/$/ /' \
745         -e 's/[         ][      ]*/ /g' \
746         -e 's/^ //' \
747         -e 's/^[^ ]* //' \
748         -e "/[0-9]:[0-9][0-9]  *[^ ]*\/$1 /s/ .*//p" \
749         -e "/[0-9]:[0-9][0-9]  *$1 /s/ .*//p"
750 }
751
752 # fix malloc libs output
753 #
754 _fix_malloc()
755 {
756     # filter out the Electric Fence notice
757     $PERL_PROG -e '
758         while (<>) {
759             if (defined $o && /^\s+Electric Fence/) {
760                 chomp($o);
761                 print "$o";
762                 undef $o;
763                 next;
764             }
765             print $o if (defined $o);
766
767             $o=$_;
768         }
769         print $o if (defined $o);
770     '
771 }
772
773 # check if run as root
774 #
775 _need_to_be_root()
776 {
777     id=`id | $SED_PROG -e 's/(.*//' -e 's/.*=//'`
778     if [ "$id" -ne 0 ]
779     then
780         echo "Arrgh ... you need to be root (not uid=$id) to run this test"
781         exit 1
782     fi
783 }
784
785
786 #
787 # _df_device : get an IRIX style df line for a given device
788 #
789 #       - returns "" if not mounted
790 #       - returns fs type in field two (ala IRIX)
791 #       - joins line together if split by fancy df formatting
792 #       - strips header etc
793 #
794
795 _df_device()
796 {
797     if [ $# -ne 1 ]
798     then
799         echo "Usage: _df_device device" 1>&2
800         exit 1
801     fi
802
803     $DF_PROG 2>/dev/null | $AWK_PROG -v what=$1 '
804         match($1,what) && NF==1 {
805             v=$1
806             getline
807             print v, $0
808             exit
809         }
810         match($1,what) {
811             print
812             exit
813         }
814     '
815 }
816
817 #
818 # _df_dir : get an IRIX style df line for device where a directory resides
819 #
820 #       - returns fs type in field two (ala IRIX)
821 #       - joins line together if split by fancy df formatting
822 #       - strips header etc
823 #
824
825 _df_dir()
826 {
827     if [ $# -ne 1 ]
828     then
829         echo "Usage: _df_dir device" 1>&2
830         exit 1
831     fi
832
833     $DF_PROG $1 2>/dev/null | $AWK_PROG -v what=$1 '
834         NR == 2 && NF==1 {
835             v=$1
836             getline
837             print v, $0;
838             exit 0
839         }
840         NR == 2 {
841             print;
842             exit 0
843         }
844         {}
845     '
846     # otherwise, nada
847 }
848
849 # return percentage used disk space for mounted device
850
851 _used()
852 {
853     if [ $# -ne 1 ]
854     then
855         echo "Usage: _used device" 1>&2
856         exit 1
857     fi
858
859     _df_device $1 | $AWK_PROG '{ sub("%", "") ; print $6 }'
860 }
861
862 # return the FS type of a mounted device
863 #
864 _fs_type()
865 {
866     if [ $# -ne 1 ]
867     then
868         echo "Usage: _fs_type device" 1>&2
869         exit 1
870     fi
871
872     #
873     # The Linux kernel shows NFSv4 filesystems in df output as
874     # filesystem type nfs4, although we mounted it as nfs earlier.
875     # Fix the filesystem type up here so that the callers don't
876     # have to bother with this quirk.
877     #
878     _df_device $1 | $AWK_PROG '{ print $2 }' | sed -e 's/nfs4/nfs/'
879 }
880
881 # return the FS mount options of a mounted device
882 #
883 # should write a version which just parses the output of mount for IRIX
884 # compatibility, but since this isn't used at all, at the moment I'll leave
885 # this for now
886 #
887 _fs_options()
888 {
889     if [ $# -ne 1 ]
890     then
891         echo "Usage: _fs_options device" 1>&2
892         exit 1
893     fi
894
895     $AWK_PROG -v dev=$1 '
896         match($1,dev) { print $4 }
897     ' </proc/mounts
898 }
899
900 # returns device number if a file is a block device
901 #
902 _is_block_dev()
903 {
904     if [ $# -ne 1 ]
905     then
906         echo "Usage: _is_block_dev dev" 1>&2
907         exit 1
908     fi
909
910     _dev=$1
911     if [ -L "${_dev}" ]; then
912         _dev=`readlink -f ${_dev}`
913     fi
914
915     if [ -b "${_dev}" ]; then
916         src/lstat64 ${_dev} | $AWK_PROG '/Device type:/ { print $9 }'
917     fi
918 }
919
920 # Do a command, log it to $seqres.full, optionally test return status
921 # and die if command fails. If called with one argument _do executes the
922 # command, logs it, and returns its exit status. With two arguments _do
923 # first prints the message passed in the first argument, and then "done"
924 # or "fail" depending on the return status of the command passed in the
925 # second argument. If the command fails and the variable _do_die_on_error
926 # is set to "always" or the two argument form is used and _do_die_on_error
927 # is set to "message_only" _do will print an error message to
928 # $seqres.out and exit.
929
930 _do()
931 {
932     if [ $# -eq 1 ]; then
933         _cmd=$1
934     elif [ $# -eq 2 ]; then
935         _note=$1
936         _cmd=$2
937         echo -n "$_note... "
938     else
939         echo "Usage: _do [note] cmd" 1>&2
940         status=1; exit
941     fi
942
943     (eval "echo '---' \"$_cmd\"") >>$seqres.full
944     (eval "$_cmd") >$tmp._out 2>&1; ret=$?
945     cat $tmp._out | _fix_malloc >>$seqres.full
946     if [ $# -eq 2 ]; then
947         if [ $ret -eq 0 ]; then
948             echo "done"
949         else
950             echo "fail"
951         fi
952     fi
953     if [ $ret -ne 0  ] \
954         && [ "$_do_die_on_error" = "always" \
955             -o \( $# -eq 2 -a "$_do_die_on_error" = "message_only" \) ]
956     then
957         [ $# -ne 2 ] && echo
958         eval "echo \"$_cmd\" failed \(returned $ret\): see $seqres.full"
959         status=1; exit
960     fi
961
962     return $ret
963 }
964
965 # bail out, setting up .notrun file. Need to kill the filesystem check files
966 # here, otherwise they are set incorrectly for the next test.
967 #
968 _notrun()
969 {
970     echo "$*" > $seqres.notrun
971     echo "$seq not run: $*"
972     rm -f ${RESULT_DIR}/require_test
973     rm -f ${RESULT_DIR}/require_scratch
974     status=0
975     exit
976 }
977
978 # just plain bail out
979 #
980 _fail()
981 {
982     echo "$*" | tee -a $seqres.full
983     echo "(see $seqres.full for details)"
984     status=1
985     exit 1
986 }
987
988 # tests whether $FSTYP is one of the supported filesystems for a test
989 #
990 _supported_fs()
991 {
992     for f
993     do
994         if [ "$f" = "$FSTYP" -o "$f" = "generic" ]
995         then
996             return
997         fi
998     done
999
1000     _notrun "not suitable for this filesystem type: $FSTYP"
1001 }
1002
1003
1004 # tests whether $FSTYP is one of the supported OSes for a test
1005 #
1006 _supported_os()
1007 {
1008     for h
1009     do
1010         if [ "$h" = "$HOSTOS" ]
1011         then
1012             return
1013         fi
1014     done
1015
1016     _notrun "not suitable for this OS: $HOSTOS"
1017 }
1018
1019 # this test needs a scratch partition - check we're ok & unmount it
1020 # No post-test check of the device is required. e.g. the test intentionally
1021 # finishes the test with the filesystem in a corrupt state
1022 _require_scratch_nocheck()
1023 {
1024     case "$FSTYP" in
1025         nfs*)
1026                  _notrun "requires a scratch device"
1027                  ;;
1028         cifs)
1029                 _notrun "requires a scratch device"
1030                 ;;
1031         tmpfs)
1032                 if [ -z "$SCRATCH_DEV" -o ! -d "$SCRATCH_MNT" ];
1033                 then
1034                     _notrun "this test requires a valid \$SCRATCH_MNT and unique $SCRATCH_DEV"
1035                 fi
1036                 ;;
1037         *)
1038                  if [ -z "$SCRATCH_DEV" -o "`_is_block_dev $SCRATCH_DEV`" = "" ]
1039                  then
1040                      _notrun "this test requires a valid \$SCRATCH_DEV"
1041                  fi
1042                  if [ "`_is_block_dev $SCRATCH_DEV`" = "`_is_block_dev $TEST_DEV`" ]
1043                  then
1044                      _notrun "this test requires a valid \$SCRATCH_DEV"
1045                  fi
1046                 if [ ! -d "$SCRATCH_MNT" ]
1047                 then
1048                      _notrun "this test requires a valid \$SCRATCH_MNT"
1049                 fi
1050                  ;;
1051     esac
1052
1053     # mounted?
1054     if _mount | grep -q $SCRATCH_DEV
1055     then
1056         # if it's mounted, make sure its on $SCRATCH_MNT
1057         if ! _mount | grep $SCRATCH_DEV | grep -q $SCRATCH_MNT
1058         then
1059             echo "\$SCRATCH_DEV is mounted but not on \$SCRATCH_MNT - aborting"
1060             exit 1
1061         fi
1062         # and then unmount it
1063         if ! $UMOUNT_PROG $SCRATCH_DEV
1064         then
1065             echo "failed to unmount $SCRATCH_DEV"
1066             exit 1
1067         fi
1068     fi
1069     rm -f ${RESULT_DIR}/require_scratch
1070 }
1071
1072 # we need the scratch device and it should be checked post test.
1073 _require_scratch()
1074 {
1075         _require_scratch_nocheck
1076         touch ${RESULT_DIR}/require_scratch
1077 }
1078
1079
1080 # this test needs a test partition - check we're ok & unmount it
1081 #
1082 _require_test()
1083 {
1084     case "$FSTYP" in
1085         nfs*)
1086                  _notrun "requires a test device"
1087                  ;;
1088         cifs)
1089                 echo $TEST_DEV | grep -q "//" > /dev/null 2>&1
1090                 if [ -z "$TEST_DEV" -o "$?" != "0" ]; then
1091                         _notrun "this test requires a valid \$TEST_DEV"
1092                 fi
1093                 if [ ! -d "$TEST_DIR" ]; then
1094                      _notrun "this test requires a valid \$TEST_DIR"
1095                 fi
1096                 ;;
1097         tmpfs)
1098                 if [ -z "$TEST_DEV" -o ! -d "$TEST_DIR" ];
1099                 then
1100                     _notrun "this test requires a valid \$TEST_DIR and unique $TEST_DEV"
1101                 fi
1102                 ;;
1103         *)
1104                  if [ -z "$TEST_DEV" -o "`_is_block_dev $TEST_DEV`" = "" ]
1105                  then
1106                      _notrun "this test requires a valid \$TEST_DEV"
1107                  fi
1108                  if [ "`_is_block_dev $SCRATCH_DEV`" = "`_is_block_dev $TEST_DEV`" ]
1109                  then
1110                      _notrun "this test requires a valid \$TEST_DEV"
1111                  fi
1112                 if [ ! -d "$TEST_DIR" ]
1113                 then
1114                      _notrun "this test requires a valid \$TEST_DIR"
1115                 fi
1116                  ;;
1117     esac
1118
1119     # mounted?
1120     if _mount | grep -q $TEST_DEV
1121     then
1122         # if it's mounted, make sure its on $TEST_DIR
1123         if ! _mount | grep $TEST_DEV | grep -q $TEST_DIR
1124         then
1125             echo "\$TEST_DEV is mounted but not on \$TEST_DIR - aborting"
1126             exit 1
1127         fi
1128     else
1129         out=`_mount_or_remount_rw "$MOUNT_OPTIONS" $TEST_DEV $TEST_DIR`
1130         if [ $? -ne 1 ]; then
1131                 echo $out
1132                 exit 1
1133         fi
1134     fi
1135     touch ${RESULT_DIR}/require_test
1136 }
1137
1138 # this test needs a logdev
1139 #
1140 _require_logdev()
1141 {
1142     [ -z "$SCRATCH_LOGDEV" -o ! -b "$SCRATCH_LOGDEV" ] && \
1143         _notrun "This test requires a valid \$SCRATCH_LOGDEV"
1144     [ "$USE_EXTERNAL" != yes ] && \
1145         _notrun "This test requires USE_EXTERNAL to be enabled"
1146
1147     # ensure its not mounted
1148     $UMOUNT_PROG $SCRATCH_LOGDEV 2>/dev/null
1149 }
1150
1151 # this test requires loopback device support
1152 #
1153 _require_loop()
1154 {
1155     if [ "$HOSTOS" != "Linux" ]
1156     then
1157         _notrun "This test requires linux for loopback device support"
1158     fi
1159
1160     modprobe loop >/dev/null 2>&1
1161     if grep loop /proc/devices >/dev/null 2>&1
1162     then
1163         :
1164     else
1165         _notrun "This test requires loopback device support"
1166     fi
1167 }
1168
1169 # this test requires ext2 filesystem support
1170 #
1171 _require_ext2()
1172 {
1173     if [ "$HOSTOS" != "Linux" ]
1174     then
1175         _notrun "This test requires linux for ext2 filesystem support"
1176     fi
1177
1178     modprobe ext2 >/dev/null 2>&1
1179     if grep ext2 /proc/filesystems >/dev/null 2>&1
1180     then
1181         :
1182     else
1183         _notrun "This test requires ext2 filesystem support"
1184     fi
1185 }
1186
1187 # this test requires that (large) loopback device files are not in use
1188 #
1189 _require_no_large_scratch_dev()
1190 {
1191     [ "$LARGE_SCRATCH_DEV" = yes ] && \
1192         _notrun "Large filesystem testing in progress, skipped this test"
1193 }
1194
1195 # this test requires that a realtime subvolume is in use, and
1196 # that the kernel supports realtime as well.
1197 #
1198 _require_realtime()
1199 {
1200     [ "$USE_EXTERNAL" = yes ] || \
1201         _notrun "External volumes not in use, skipped this test"
1202     [ "$SCRATCH_RTDEV" = "" ] && \
1203         _notrun "Realtime device required, skipped this test"
1204 }
1205
1206 # this test requires that a specified command (executable) exists
1207 # $1 - command, $2 - name for error message
1208 #
1209 _require_command()
1210 {
1211     [ -n "$1" ] && _cmd="$1" || _cmd="$2"
1212     [ -n "$1" -a -x "$1" ] || _notrun "$_cmd utility required, skipped this test"
1213 }
1214
1215 # this test requires the device mapper flakey target
1216 #
1217 _require_dm_flakey()
1218 {
1219     _require_command $DMSETUP_PROG
1220
1221     modprobe dm-flakey >/dev/null 2>&1
1222     $DMSETUP_PROG targets | grep flakey >/dev/null 2>&1
1223     if [ $? -eq 0 ]
1224     then
1225         :
1226     else
1227         _notrun "This test requires dm flakey support"
1228     fi
1229 }
1230
1231 # this test requires the projid32bit feature to be available in mkfs.xfs.
1232 #
1233 _require_projid32bit()
1234 {
1235        _scratch_mkfs_xfs_supported -i projid32bit=1 >/dev/null 2>&1 \
1236            || _notrun "mkfs.xfs doesn't have projid32bit feature"
1237 }
1238
1239 _require_projid16bit()
1240 {
1241         _scratch_mkfs_xfs_supported -i projid32bit=0 >/dev/null 2>&1 \
1242            || _notrun "16 bit project IDs not supported on $SCRATCH_DEV"
1243 }
1244
1245 # this test requires the crc feature to be available in mkfs.xfs
1246 #
1247 _require_xfs_mkfs_crc()
1248 {
1249         _scratch_mkfs_xfs_supported -m crc=1 >/dev/null 2>&1 \
1250            || _notrun "mkfs.xfs doesn't have crc feature"
1251 }
1252
1253 # this test requires the xfs kernel support crc feature
1254 #
1255 _require_xfs_crc()
1256 {
1257         _scratch_mkfs_xfs -m crc=1 >/dev/null 2>&1
1258         _scratch_mount >/dev/null 2>&1 \
1259            || _notrun "Kernel doesn't support crc feature"
1260         umount $SCRATCH_MNT
1261 }
1262
1263 # this test requires the bigalloc feature to be available in mkfs.ext4
1264 #
1265 _require_ext4_mkfs_bigalloc()
1266 {
1267         _scratch_mkfs_ext4 -O bigalloc >/dev/null 2>&1 \
1268            || _notrun "mkfs.ext4 doesn't have bigalloc feature"
1269 }
1270
1271 # this test requires the ext4 kernel support bigalloc feature
1272 #
1273 _require_ext4_bigalloc()
1274 {
1275         _scratch_mkfs_ext4 -O bigalloc >/dev/null 2>&1
1276         _scratch_mount >/dev/null 2>&1 \
1277            || _notrun "Ext4 kernel doesn't support bigalloc feature"
1278         umount $SCRATCH_MNT
1279 }
1280
1281 # this test requires the finobt feature to be available in mkfs.xfs
1282 #
1283 _require_xfs_mkfs_finobt()
1284 {
1285         _scratch_mkfs_xfs_supported -m crc=1,finobt=1 >/dev/null 2>&1 \
1286            || _notrun "mkfs.xfs doesn't have finobt feature"
1287 }
1288
1289 # this test requires the xfs kernel support finobt feature
1290 #
1291 _require_xfs_finobt()
1292 {
1293         _scratch_mkfs_xfs -m crc=1,finobt=1 >/dev/null 2>&1
1294         _scratch_mount >/dev/null 2>&1 \
1295            || _notrun "Kernel doesn't support finobt feature"
1296         umount $SCRATCH_MNT
1297 }
1298
1299 # this test requires xfs sysfs attribute support
1300 #
1301 _require_xfs_sysfs()
1302 {
1303         attr=$1
1304         sysfsdir=/sys/fs/xfs
1305         testdev=`_short_dev $TEST_DEV`
1306
1307         if [ ! -e $sysfsdir ]; then
1308                 _notrun "no kernel support for XFS sysfs attributes"
1309         fi
1310
1311         if [ ! -z $1 ] && [ ! -e $sysfsdir/$testdev/$attr ]; then
1312                 _notrun "sysfs attribute '$attr' is not supported"
1313         fi
1314 }
1315
1316 # this test requires that external log/realtime devices are not in use
1317 #
1318 _require_nonexternal()
1319 {
1320     [ "$USE_EXTERNAL" = yes ] && \
1321         _notrun "External device testing in progress, skipped this test"
1322 }
1323
1324 # this test requires that a (specified) aio-dio executable exists
1325 # $1 - command (optional)
1326 #
1327 _require_aiodio()
1328 {
1329     if [ -z "$1" ]
1330     then
1331         AIO_TEST=src/aio-dio-regress/aiodio_sparse2
1332         [ -x $AIO_TEST ] || _notrun "aio-dio utilities required"
1333     else
1334         AIO_TEST=src/aio-dio-regress/$1
1335         [ -x $AIO_TEST ] || _notrun "$AIO_TEST not built"
1336     fi
1337 }
1338
1339 # run an aio-dio program
1340 # $1 - command
1341 _run_aiodio()
1342 {
1343     if [ -z "$1" ]
1344     then
1345         echo "usage: _run_aiodio command_name" 2>&1
1346         status=1; exit 1
1347     fi
1348
1349     _require_aiodio $1
1350
1351     local testtemp=$TEST_DIR/aio-testfile
1352     rm -f $testtemp
1353     $AIO_TEST $testtemp 2>&1
1354     status=$?
1355     rm -f $testtemp
1356
1357     return $status
1358 }
1359
1360 # indicate whether YP/NIS is active or not
1361 #
1362 _yp_active()
1363 {
1364         local dn
1365         dn=$(domainname 2>/dev/null)
1366         test -n "${dn}" -a "${dn}" != "(none)"
1367         echo $?
1368 }
1369
1370 # cat the password file
1371 #
1372 _cat_passwd()
1373 {
1374         [ $(_yp_active) -eq 0 ] && ypcat passwd
1375         cat /etc/passwd
1376 }
1377
1378 # cat the group file
1379 #
1380 _cat_group()
1381 {
1382         [ $(_yp_active) -eq 0 ] && ypcat group
1383         cat /etc/group
1384 }
1385
1386 # check for the fsgqa user on the machine
1387 #
1388 _require_user()
1389 {
1390     qa_user=fsgqa
1391     _cat_passwd | grep -q $qa_user
1392     [ "$?" == "0" ] || _notrun "$qa_user user not defined."
1393     echo /bin/true | su $qa_user
1394     [ "$?" == "0" ] || _notrun "$qa_user cannot execute commands."
1395 }
1396
1397 # check for the fsgqa group on the machine
1398 #
1399 _require_group()
1400 {
1401     qa_group=fsgqa
1402     _cat_group | grep -q $qa_group
1403     [ "$?" == "0" ] || _notrun "$qa_group user not defined."
1404 }
1405
1406 _filter_user_do()
1407 {
1408         perl -ne "
1409 s,.*Permission\sdenied.*,Permission denied,;
1410 s,.*no\saccess\sto\stty.*,,;
1411 s,.*no\sjob\scontrol\sin\sthis\sshell.*,,;
1412 s,^\s*$,,;
1413         print;"
1414 }
1415
1416 _user_do()
1417 {
1418     if [ "$HOSTOS" == "IRIX" ]
1419         then
1420         echo $1 | /bin/bash "su $qa_user 2>&1" | _filter_user_do
1421     else
1422         echo $1 | su $qa_user 2>&1 | _filter_user_do
1423     fi
1424 }
1425
1426 _require_xfs_io_command()
1427 {
1428         if [ $# -ne 1 ]
1429         then
1430                 echo "Usage: _require_xfs_io_command command" 1>&2
1431                 exit 1
1432         fi
1433         command=$1
1434
1435         testfile=$TEST_DIR/$$.xfs_io
1436         case $command in
1437         "falloc" )
1438                 testio=`$XFS_IO_PROG -F -f -c "falloc 0 1m" $testfile 2>&1`
1439                 ;;
1440         "fpunch" | "fcollapse" | "zero" | "fzero" )
1441                 testio=`$XFS_IO_PROG -F -f -c "pwrite 0 20k" -c "fsync" \
1442                         -c "$command 4k 8k" $testfile 2>&1`
1443                 ;;
1444         "fiemap")
1445                 testio=`$XFS_IO_PROG -F -f -c "pwrite 0 20k" -c "fsync" \
1446                         -c "fiemap -v" $testfile 2>&1`
1447                 ;;
1448         "flink" )
1449                 testio=`$XFS_IO_PROG -T -F -c "flink $testfile" \
1450                         $TEST_DIR 2>&1`
1451                 echo $testio | egrep -q "invalid option|Is a directory" && \
1452                         _notrun "xfs_io $command support is missing"
1453                 ;;
1454         *)
1455                 testio=`$XFS_IO_PROG -c "$command help" 2>&1`
1456         esac
1457
1458         rm -f $testfile 2>&1 > /dev/null
1459         echo $testio | grep -q "not found" && \
1460                 _notrun "xfs_io $command support is missing"
1461         echo $testio | grep -q "Operation not supported" && \
1462                 _notrun "xfs_io $command failed (old kernel/wrong fs?)"
1463 }
1464
1465 # Check that a fs has enough free space (in 1024b blocks)
1466 #
1467 _require_fs_space()
1468 {
1469         MNT=$1
1470         BLOCKS=$2       # in units of 1024
1471         let GB=$BLOCKS/1024/1024
1472
1473         FREE_BLOCKS=`df -klP $MNT | grep -v Filesystem | awk '{print $4}'`
1474         [ $FREE_BLOCKS -lt $BLOCKS ] && \
1475                 _notrun "This test requires at least ${GB}GB free on $MNT to run"
1476 }
1477
1478 #
1479 # Check if the filesystem supports sparse files.
1480 #
1481 # Unfortunately there is no better way to do this than a manual black list.
1482 #
1483 _require_sparse_files()
1484 {
1485     case $FSTYP in
1486     hfsplus)
1487         _notrun "Sparse files not supported by this filesystem type: $FSTYP"
1488         ;;
1489     *)
1490         ;;
1491     esac
1492 }
1493
1494 _require_debugfs()
1495 {
1496     #boot_params always present in debugfs
1497     [ -d "$DEBUGFS_MNT/boot_params" ] || _notrun "Debugfs not mounted"
1498 }
1499
1500 _require_fail_make_request()
1501 {
1502     [ -f "$DEBUGFS_MNT/fail_make_request/probability" ] \
1503         || _notrun "$DEBUGFS_MNT/fail_make_request \
1504  not found. Seems that CONFIG_FAIL_MAKE_REQUEST kernel config option not enabled"
1505 }
1506
1507 #
1508 # Check if the file system supports seek_data/hole
1509 #
1510 _require_seek_data_hole()
1511 {
1512     testfile=$TEST_DIR/$$.seek
1513     testseek=`$here/src/seek_sanity_test -t $testfile 2>&1`
1514     rm -f $testfile &>/dev/null
1515     echo $testseek | grep -q "Kernel does not support" && \
1516         _notrun "File system does not support llseek(2) SEEK_DATA/HOLE"
1517 }
1518
1519 # check that a FS on a device is mounted
1520 # if so, return mount point
1521 #
1522 _is_mounted()
1523 {
1524     if [ $# -ne 1 ]
1525     then
1526         echo "Usage: _is_mounted device" 1>&2
1527         exit 1
1528     fi
1529
1530     device=$1
1531
1532     if _mount | grep "$device " | $AWK_PROG -v pattern="type $FSTYP" '
1533         pattern        { print $3 ; exit 0 }
1534         END            { exit 1 }
1535     '
1536     then
1537         echo "_is_mounted: $device is not a mounted $FSTYP FS"
1538         exit 1
1539     fi
1540 }
1541
1542 # remount a FS to a new mode (ro or rw)
1543 #
1544 _remount()
1545 {
1546     if [ $# -ne 2 ]
1547     then
1548         echo "Usage: _remount device ro/rw" 1>&2
1549         exit 1
1550     fi
1551     device=$1
1552     mode=$2
1553
1554     if ! mount -o remount,$mode $device
1555     then
1556         echo "_remount: failed to remount filesystem on $device as $mode"
1557         exit 1
1558     fi
1559 }
1560
1561 # Run the appropriate repair/check on a filesystem
1562 #
1563 # if the filesystem is mounted, it's either remounted ro before being
1564 # checked or it's unmounted and then remounted
1565 #
1566
1567 # If set, we remount ro instead of unmounting for fsck
1568 USE_REMOUNT=0
1569
1570 _umount_or_remount_ro()
1571 {
1572     if [ $# -ne 1 ]
1573     then
1574         echo "Usage: _umount_or_remount_ro <device>" 1>&2
1575         exit 1
1576     fi
1577
1578     device=$1
1579     mountpoint=`_is_mounted $device`
1580
1581     if [ $USE_REMOUNT -eq 0 ]; then
1582         $UMOUNT_PROG $device
1583     else
1584         _remount $device ro
1585     fi
1586     echo "$mountpoint"
1587 }
1588
1589 _mount_or_remount_rw()
1590 {
1591     if [ $# -ne 3 ]
1592     then
1593         echo "Usage: _mount_or_remount_rw <opts> <device> <mountpoint>" 1>&2
1594         exit 1
1595     fi
1596     mount_opts=$1
1597     device=$2
1598     mountpoint=$3
1599
1600     if [ $USE_REMOUNT -eq 0 ]
1601     then
1602         if ! _mount -t $FSTYP $mount_opts $device $mountpoint
1603         then
1604             echo "!!! failed to remount $device on $mountpoint"
1605             return 0 # ok=0
1606         fi
1607     else
1608         _remount $device rw
1609     fi
1610
1611     return 1 # ok=1
1612 }
1613
1614 # Check a generic filesystem in no-op mode; this assumes that the
1615 # underlying fsck program accepts "-n" for a no-op (check-only) run,
1616 # and that it will still return an errno for corruption in this mode.
1617 #
1618 # Filesystems which don't support this will need to define their
1619 # own check routine.
1620 #
1621 _check_generic_filesystem()
1622 {
1623     device=$1
1624
1625     # If type is set, we're mounted
1626     type=`_fs_type $device`
1627     ok=1
1628
1629     if [ "$type" = "$FSTYP" ]
1630     then
1631         # mounted ...
1632         mountpoint=`_umount_or_remount_ro $device`
1633     fi
1634
1635     fsck -t $FSTYP $FSCK_OPTIONS $device >$tmp.fsck 2>&1
1636     if [ $? -ne 0 ]
1637     then
1638         echo "_check_generic_filesystem: filesystem on $device is inconsistent (see $seqres.full)"
1639
1640         echo "_check_generic filesystem: filesystem on $device is inconsistent" >>$seqres.full
1641         echo "*** fsck.$FSTYP output ***"       >>$seqres.full
1642         cat $tmp.fsck                           >>$seqres.full
1643         echo "*** end fsck.$FSTYP output"       >>$seqres.full
1644
1645         ok=0
1646     fi
1647     rm -f $tmp.fsck
1648
1649     if [ $ok -eq 0 ]
1650     then
1651         echo "*** mount output ***"             >>$seqres.full
1652         _mount                                  >>$seqres.full
1653         echo "*** end mount output"             >>$seqres.full
1654     elif [ "$type" = "$FSTYP" ]
1655     then
1656         # was mounted ...
1657         _mount_or_remount_rw "$MOUNT_OPTIONS" $device $mountpoint
1658         ok=$?
1659     fi
1660
1661     if [ $ok -eq 0 ]; then
1662         status=1
1663         exit 1
1664     fi
1665
1666     return 0
1667 }
1668
1669 # run xfs_check and friends on a FS.
1670
1671 _check_xfs_filesystem()
1672 {
1673     if [ $# -ne 3 ]
1674     then
1675         echo "Usage: _check_xfs_filesystem device <logdev>|none <rtdev>|none" 1>&2
1676         exit 1
1677     fi
1678
1679     extra_mount_options=""
1680     device=$1
1681     if [ "$2" != "none" ]; then
1682         extra_log_options="-l$2"
1683         extra_mount_options="-ologdev=$2"
1684     fi
1685
1686     if [ "$3" != "none" ]; then
1687         extra_rt_options="-r$3"
1688         extra_mount_options=$extra_mount_options" -ortdev=$3"
1689     fi
1690     extra_mount_options=$extra_mount_options" $MOUNT_OPTIONS"
1691
1692     [ "$FSTYP" != xfs ] && return 0
1693
1694     type=`_fs_type $device`
1695     ok=1
1696
1697     if [ "$type" = "xfs" ]
1698     then
1699         # mounted ...
1700         mountpoint=`_umount_or_remount_ro $device`
1701     fi
1702
1703     $XFS_LOGPRINT_PROG -t $extra_log_options $device 2>&1 \
1704                 | tee $tmp.logprint | grep -q "<CLEAN>"
1705     if [ $? -ne 0 -a "$HOSTOS" = "Linux" ]
1706     then
1707         echo "_check_xfs_filesystem: filesystem on $device has dirty log (see $seqres.full)"
1708
1709         echo "_check_xfs_filesystem: filesystem on $device has dirty log"   >>$seqres.full
1710         echo "*** xfs_logprint -t output ***"   >>$seqres.full
1711         cat $tmp.logprint                       >>$seqres.full
1712         echo "*** end xfs_logprint output"      >>$seqres.full
1713
1714         ok=0
1715     fi
1716
1717     # xfs_check runs out of memory on large files, so even providing the test
1718     # option (-t) to avoid indexing the free space trees doesn't make it pass on
1719     # large filesystems. Avoid it.
1720     if [ "$LARGE_SCRATCH_DEV" != yes ]; then
1721             _xfs_check $extra_log_options $device 2>&1 |\
1722                  _fix_malloc >$tmp.fs_check
1723     fi
1724     if [ -s $tmp.fs_check ]
1725     then
1726         echo "_check_xfs_filesystem: filesystem on $device is inconsistent (c) (see $seqres.full)"
1727
1728         echo "_check_xfs_filesystem: filesystem on $device is inconsistent" >>$seqres.full
1729         echo "*** xfs_check output ***"         >>$seqres.full
1730         cat $tmp.fs_check                       >>$seqres.full
1731         echo "*** end xfs_check output"         >>$seqres.full
1732
1733         ok=0
1734     fi
1735
1736     $XFS_REPAIR_PROG -n $extra_log_options $extra_rt_options $device >$tmp.repair 2>&1
1737     if [ $? -ne 0 ]
1738     then
1739         echo "_check_xfs_filesystem: filesystem on $device is inconsistent (r) (see $seqres.full)"
1740
1741         echo "_check_xfs_filesystem: filesystem on $device is inconsistent" >>$seqres.full
1742         echo "*** xfs_repair -n output ***"     >>$seqres.full
1743         cat $tmp.repair | _fix_malloc           >>$seqres.full
1744         echo "*** end xfs_repair output"        >>$seqres.full
1745
1746         ok=0
1747     fi
1748     rm -f $tmp.fs_check $tmp.logprint $tmp.repair
1749
1750     if [ $ok -eq 0 ]
1751     then
1752         echo "*** mount output ***"             >>$seqres.full
1753         _mount                                  >>$seqres.full
1754         echo "*** end mount output"             >>$seqres.full
1755     elif [ "$type" = "xfs" ]
1756     then
1757         _mount_or_remount_rw "$extra_mount_options" $device $mountpoint
1758     fi
1759
1760     if [ $ok -eq 0 ]; then
1761         status=1
1762         if [ "$iam" != "check" ]; then
1763                 exit 1
1764         fi
1765     fi
1766
1767     return 0
1768 }
1769
1770 # Filter the knowen errors the UDF Verifier reports.
1771 _udf_test_known_error_filter()
1772 {
1773         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."
1774
1775 }
1776
1777 _check_udf_filesystem()
1778 {
1779     [ "$DISABLE_UDF_TEST" == "1" ] && return
1780
1781     if [ $# -ne 1 -a $# -ne 2 ]
1782     then
1783         echo "Usage: _check_udf_filesystem device [last_block]" 1>&2
1784         exit 1
1785     fi
1786
1787     if [ ! -x $here/src/udf_test ]
1788     then
1789         echo "udf_test not installed, please download and build the Philips"
1790         echo "UDF Verification Software from http://www.extra.research.philips.com/udf/."
1791         echo "Then copy the udf_test binary to $here/src/."
1792         echo "If you do not wish to run udf_test then set environment variable DISABLE_UDF_TEST"
1793         echo "to 1."
1794         return
1795     fi
1796
1797     device=$1
1798     if [ $# -eq 2 ];
1799     then
1800         LAST_BLOCK=`expr \( $2 - 1 \)`
1801         OPT_ARG="-lastvalidblock $LAST_BLOCK"
1802     fi
1803
1804     rm -f $seqres.checkfs
1805     sleep 1 # Due to a problem with time stamps in udf_test
1806     $here/src/udf_test $OPT_ARG $device | tee $seqres.checkfs | egrep "Error|Warning" | \
1807         _udf_test_known_error_filter | \
1808         egrep -iv "Error count:.*[0-9]+.*total occurrences:.*[0-9]+|Warning count:.*[0-9]+.*total occurrences:.*[0-9]+" && \
1809         echo "Warning UDF Verifier reported errors see $seqres.checkfs."
1810 }
1811
1812 _check_xfs_test_fs()
1813 {
1814     TEST_LOG="none"
1815     TEST_RT="none"
1816     [ "$USE_EXTERNAL" = yes -a ! -z "$TEST_LOGDEV" ] && \
1817         TEST_LOG="$TEST_LOGDEV"
1818
1819     [ "$USE_EXTERNAL" = yes -a ! -z "$TEST_RTDEV" ] && \
1820         TEST_RT="$TEST_RTDEV"
1821
1822     _check_xfs_filesystem $TEST_DEV $TEST_LOG $TEST_RT
1823
1824     # check for ipath consistency
1825     if $XFS_GROWFS_PROG -n $TEST_DIR | grep -q 'inode-paths=1'; then
1826         # errors go to stderr
1827         xfs_check_ipaths $TEST_DIR >/dev/null
1828         xfs_repair_ipaths -n $TEST_DIR >/dev/null
1829     fi
1830 }
1831
1832 _check_btrfs_filesystem()
1833 {
1834     device=$1
1835
1836     # If type is set, we're mounted
1837     type=`_fs_type $device`
1838     ok=1
1839
1840     if [ "$type" = "$FSTYP" ]
1841     then
1842         # mounted ...
1843         mountpoint=`_umount_or_remount_ro $device`
1844     fi
1845
1846     btrfsck $device >$tmp.fsck 2>&1
1847     if [ $? -ne 0 ]
1848     then
1849         echo "_check_btrfs_filesystem: filesystem on $device is inconsistent (see $seqres.full)"
1850
1851         echo "_check_btrfs_filesystem: filesystem on $device is inconsistent" >>$seqres.full
1852         echo "*** fsck.$FSTYP output ***"       >>$seqres.full
1853         cat $tmp.fsck                           >>$seqres.full
1854         echo "*** end fsck.$FSTYP output"       >>$seqres.full
1855
1856         ok=0
1857     fi
1858     rm -f $tmp.fsck
1859
1860     if [ $ok -eq 0 ]
1861     then
1862         echo "*** mount output ***"             >>$seqres.full
1863         _mount                                  >>$seqres.full
1864         echo "*** end mount output"             >>$seqres.full
1865     elif [ "$type" = "$FSTYP" ]
1866     then
1867         # was mounted ...
1868         _mount_or_remount_rw "$MOUNT_OPTIONS" $device $mountpoint
1869         ok=$?
1870     fi
1871
1872     if [ $ok -eq 0 ]; then
1873         status=1
1874         exit 1
1875     fi
1876
1877     return 0
1878 }
1879
1880 _check_test_fs()
1881 {
1882     case $FSTYP in
1883     xfs)
1884         _check_xfs_test_fs
1885         ;;
1886     nfs)
1887         # no way to check consistency for nfs
1888         ;;
1889     cifs)
1890         # no way to check consistency for cifs
1891         ;;
1892     udf)
1893         # do nothing for now
1894         ;;
1895     btrfs)
1896         _check_btrfs_filesystem $TEST_DEV
1897         ;;
1898     tmpfs)
1899         # no way to check consistency for tmpfs
1900         ;;
1901     *)
1902         _check_generic_filesystem $TEST_DEV
1903         ;;
1904     esac
1905 }
1906
1907 _check_scratch_fs()
1908 {
1909     device=$SCRATCH_DEV
1910     [ $# -eq 1 ] && device=$1
1911
1912     case $FSTYP in
1913     xfs)
1914         SCRATCH_LOG="none"
1915         SCRATCH_RT="none"
1916         [ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_LOGDEV" ] && \
1917             SCRATCH_LOG="$SCRATCH_LOGDEV"
1918
1919         [ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_RTDEV" ] && \
1920             SCRATCH_RT="$SCRATCH_RTDEV"
1921
1922         _check_xfs_filesystem $device $SCRATCH_LOG $SCRATCH_RT
1923         ;;
1924     udf)
1925         _check_udf_filesystem $device $udf_fsize
1926         ;;
1927     nfs*)
1928         # Don't know how to check an NFS filesystem, yet.
1929         ;;
1930     cifs)
1931         # Don't know how to check a CIFS filesystem, yet.
1932         ;;
1933     btrfs)
1934         _check_btrfs_filesystem $device
1935         ;;
1936     tmpfs)
1937         # no way to check consistency for tmpfs
1938         ;;
1939     *)
1940         _check_generic_filesystem $device
1941         ;;
1942     esac
1943 }
1944
1945 _full_fstyp_details()
1946 {
1947      [ -z "$FSTYP" ] && FSTYP=xfs
1948      if [ $FSTYP = xfs ]; then
1949         if [ -d /proc/fs/xfs ]; then
1950             if grep -q 'debug 0' /proc/fs/xfs/stat; then
1951                 FSTYP="$FSTYP (non-debug)"
1952             elif grep -q 'debug 1' /proc/fs/xfs/stat; then
1953                 FSTYP="$FSTYP (debug)"
1954             fi
1955         else
1956             if uname -a | grep -qi 'debug'; then
1957                 FSTYP="$FSTYP (debug)"
1958             else
1959                 FSTYP="$FSTYP (non-debug)"
1960             fi
1961         fi
1962      fi
1963      echo $FSTYP
1964 }
1965
1966 _full_platform_details()
1967 {
1968      os=`uname -s`
1969      host=`hostname -s`
1970      kernel=`uname -r`
1971      platform=`uname -m`
1972      echo "$os/$platform $host $kernel"
1973 }
1974
1975 _link_out_file()
1976 {
1977         if [ -z "$1" -o -z "$2" ]; then
1978                 echo Error must pass src and dst.
1979                 exit
1980         fi
1981         rm -f $2
1982         if [ "`uname`" == "IRIX64" ] || [ "`uname`" == "IRIX" ]; then
1983                 ln -s $1.irix $2
1984         elif [ "`uname`" == "Linux" ]; then
1985                 ln -s $1.linux $2
1986         else
1987                 echo Error test $seq does not run on the operating system: `uname`
1988                 exit
1989         fi
1990 }
1991
1992 _die()
1993 {
1994         echo $@
1995         exit 1
1996 }
1997
1998 #takes files, randomdata
1999 _nfiles()
2000 {
2001         f=0
2002         while [ $f -lt $1 ]
2003         do
2004                 file=f$f
2005                 echo > $file
2006                 if [ $size -gt 0 ]; then
2007                     if [ "$2" == "false" ]; then
2008                         dd if=/dev/zero of=$file bs=1024 count=$size 2>&1 | _filter_dd
2009                     else
2010                         dd if=/dev/urandom of=$file bs=1024 count=$size 2>&1 | _filter_dd
2011                     fi
2012                 fi
2013                 let f=$f+1
2014         done
2015 }
2016
2017 # takes dirname, depth, randomdata
2018 _descend()
2019 {
2020         dirname=$1; depth=$2; randomdata=$3
2021         mkdir $dirname  || die "mkdir $dirname failed"
2022         cd $dirname
2023
2024         _nfiles $files $randomdata          # files for this dir and data type
2025
2026         [ $depth -eq 0 ] && return
2027         let deep=$depth-1 # go 1 down
2028
2029         [ $verbose = true ] && echo "descending, depth from leaves = $deep"
2030
2031         d=0
2032         while [ $d -lt $dirs ]
2033         do
2034                 _descend d$d $deep &
2035                 let d=$d+1
2036                 wait
2037         done
2038 }
2039
2040 # Populate a filesystem with inodes for performance experiments
2041 #
2042 # usage: populate [-v] [-n ndirs] [-f nfiles] [-d depth] [-r root] [-s size] [-x]
2043 #
2044 _populate_fs()
2045 {
2046     here=`pwd`
2047     dirs=5          # ndirs in each subdir till leaves
2048     size=0          # sizeof files in K
2049     files=100       # num files in _each_ subdir
2050     depth=2         # depth of tree from root to leaves
2051     verbose=false
2052     root=root       # path of initial root of directory tree
2053     randomdata=false # -x data type urandom or zero
2054
2055     OPTIND=1
2056     while getopts "d:f:n:r:s:v:x" c
2057     do
2058         case $c in
2059         d)      depth=$OPTARG;;
2060         n)      dirs=$OPTARG;;
2061         f)      files=$OPTARG;;
2062         s)      size=$OPTARG;;
2063         v)      verbose=true;;
2064         r)      root=$OPTARG;;
2065         x)      randomdata=true;;
2066         esac
2067     done
2068
2069     _descend $root $depth $randomdata
2070     wait
2071
2072     cd $here
2073
2074     [ $verbose = true ] && echo done
2075 }
2076
2077 # query whether the given file has the given inode flag set
2078 #
2079 _test_inode_flag()
2080 {
2081     flag=$1
2082     file=$2
2083
2084     if which $XFS_IO_PROG >/dev/null; then
2085         if $XFS_IO_PROG -r -c 'lsattr -v' "$file" | grep -q "$flag" ; then
2086             return 0
2087         fi
2088     fi
2089     return 1
2090 }
2091
2092 # query the given files extsize allocator hint in bytes (if any)
2093 #
2094 _test_inode_extsz()
2095 {
2096     file=$1
2097     blocks=""
2098
2099     if which $XFS_IO_PROG >/dev/null; then
2100         blocks=`$XFS_IO_PROG -r -c 'stat' "$file" | \
2101                 awk '/^xattr.extsize =/ { print $3 }'`
2102     fi
2103     [ -z "$blocks" ] && blocks="0"
2104     echo $blocks
2105 }
2106
2107 # scratch_dev_pool should contain the disks pool for the btrfs raid
2108 _require_scratch_dev_pool()
2109 {
2110         local i
2111         local ndevs
2112
2113         if [ -z "$SCRATCH_DEV_POOL" ]; then
2114                 _notrun "this test requires a valid \$SCRATCH_DEV_POOL"
2115         fi
2116
2117         if [ -z "$1" ]; then
2118                 ndevs=2
2119         else
2120                 ndevs=$1
2121         fi
2122
2123         # btrfs test case needs ndevs or more scratch_dev_pool; other FS not sure
2124         # so fail it
2125         case $FSTYP in
2126         btrfs)
2127                 if [ "`echo $SCRATCH_DEV_POOL|wc -w`" -lt $ndevs ]; then
2128                         _notrun "btrfs and this test needs $ndevs or more disks in SCRATCH_DEV_POOL"
2129                 fi
2130         ;;
2131         *)
2132                 _notrun "dev_pool is not supported by fstype \"$FSTYP\""
2133         ;;
2134         esac
2135
2136         for i in $SCRATCH_DEV_POOL; do
2137                 if [ "`_is_block_dev $i`" = "" ]; then
2138                         _notrun "this test requires valid block disk $i"
2139                 fi
2140                 if [ "`_is_block_dev $i`" = "`_is_block_dev $TEST_DEV`" ]; then
2141                         _notrun "$i is part of TEST_DEV, this test requires unique disks"
2142                 fi
2143                 if _mount | grep -q $i; then
2144                         if ! $UMOUNT_PROG $i; then
2145                             echo "failed to unmount $i - aborting"
2146                             exit 1
2147                         fi
2148                 fi
2149                 # to help better debug when something fails, we remove
2150                 # traces of previous btrfs FS on the dev.
2151                 dd if=/dev/zero of=$i bs=4096 count=100 > /dev/null 2>&1
2152         done
2153 }
2154
2155 # We will check if the device is deletable
2156 _require_deletable_scratch_dev_pool()
2157 {
2158         local i
2159         local x
2160         for i in $SCRATCH_DEV_POOL; do
2161                 x=`echo $i | cut -d"/" -f 3`
2162                 if [ ! -f /sys/class/block/${x}/device/delete ]; then
2163                         _notrun "$i is a device which is not deletable"
2164                 fi
2165         done
2166 }
2167
2168 # We check for btrfs and (optionally) features of the btrfs command
2169 _require_btrfs()
2170 {
2171         cmd=$1
2172         _require_command $BTRFS_UTIL_PROG btrfs
2173         if [ -z "$1" ]; then
2174                 return 1;
2175         fi
2176         $BTRFS_UTIL_PROG $cmd --help >/dev/null 2>&1
2177         [ $? -eq 0 ] || _notrun "$BTRFS_UTIL_PROG too old (must support $cmd)"
2178 }
2179
2180 # Check that fio is present, and it is able to execute given jobfile
2181 _require_fio()
2182 {
2183         job=$1
2184
2185         _require_command $FIO_PROG
2186         if [ -z "$1" ]; then
2187                 return 1;
2188         fi
2189
2190         $FIO_PROG --warnings-fatal --showcmd $job >> $seqres.full 2>&1
2191         [ $? -eq 0 ] || _notrun "$FIO_PROG too old, see $seqres.full"
2192 }
2193
2194 # Does freeze work on this fs?
2195 _require_freeze()
2196 {
2197         xfs_freeze -f "$TEST_DIR" >/dev/null 2>&1
2198         result=$? 
2199         xfs_freeze -u "$TEST_DIR" >/dev/null 2>&1
2200         [ $result -eq 0 ] || _notrun "$FSTYP does not support freezing"
2201 }
2202
2203 # arg 1 is dev to remove and is output of the below eg.
2204 # ls -l /sys/class/block/sdd | rev | cut -d "/" -f 3 | rev
2205 _devmgt_remove()
2206 {
2207         local lun=$1
2208         local disk=$2
2209
2210         echo 1 > /sys/class/scsi_device/${lun}/device/delete || _fail "Remove disk failed"
2211
2212         stat $disk > /dev/null 2>&1
2213         while [ $? -eq 0 ]; do
2214                 sleep 1
2215                 stat $disk > /dev/null 2>&1
2216         done
2217 }
2218
2219 # arg 1 is dev to add and is output of the below eg.
2220 # ls -l /sys/class/block/sdd | rev | cut -d "/" -f 3 | rev
2221 _devmgt_add()
2222 {
2223         local h
2224         local tdl
2225         # arg 1 will be in h:t:d:l format now in the h and "t d l" format
2226         h=`echo ${1} | cut -d":" -f 1`
2227         tdl=`echo ${1} | cut -d":" -f 2-|sed 's/:/ /g'`
2228
2229         echo ${tdl} >  /sys/class/scsi_host/host${h}/scan || _fail "Add disk failed"
2230
2231         # ensure the device comes online
2232         dev_back_oneline=0
2233         for i in `seq 1 10`; do
2234                 if [ -d /sys/class/scsi_device/${1}/device/block ]; then
2235                         dev=`ls /sys/class/scsi_device/${1}/device/block`
2236                         for j in `seq 1 10`;
2237                         do
2238                                 stat /dev/$dev > /dev/null 2>&1
2239                                 if [ $? -eq 0 ]; then
2240                                         dev_back_oneline=1
2241                                         break
2242                                 fi
2243                                 sleep 1
2244                         done
2245                         break
2246                 else
2247                         sleep 1
2248                 fi
2249         done
2250         if [ $dev_back_oneline -eq 0 ]; then
2251                 echo "/dev/$dev online failed" >> $seqres.full
2252         else
2253                 echo "/dev/$dev is back online" >> $seqres.full
2254         fi
2255 }
2256
2257 _require_fstrim()
2258 {
2259         if [ -z "$FSTRIM_PROG" ]; then
2260                 _notrun "This test requires fstrim utility."
2261         fi
2262 }
2263
2264 _test_batched_discard()
2265 {
2266         if [ $# -ne 1 ]; then
2267                 echo "Usage: _test_batched_discard mnt_point" 1>&2
2268                 exit 1
2269         fi
2270         _require_fstrim
2271         $FSTRIM_PROG ${1} &>/dev/null
2272 }
2273
2274 _require_dumpe2fs()
2275 {
2276         if [ -z "$DUMPE2FS_PROG" ]; then
2277                 _notrun "This test requires dumpe2fs utility."
2278         fi
2279 }
2280
2281 _require_ugid_map()
2282 {
2283         if [ ! -e /proc/self/uid_map ]; then
2284                 _notrun "This test requires procfs uid_map support."
2285         fi
2286         if [ ! -e /proc/self/gid_map ]; then
2287                 _notrun "This test requires procfs gid_map support."
2288         fi
2289 }
2290
2291 _require_cp_reflink()
2292 {
2293        cp --help | grep -q reflink || \
2294                _notrun "This test requires a cp with --reflink support."
2295 }
2296
2297 _require_fssum()
2298 {
2299         FSSUM_PROG=$here/src/fssum
2300         [ -x $FSSUM_PROG ] || _notrun "fssum not built"
2301 }
2302
2303 _require_btrfs_cloner()
2304 {
2305         CLONER_PROG=$here/src/cloner
2306         [ -x $CLONER_PROG ] || \
2307                 _notrun "cloner binary not present at $CLONER_PROG"
2308 }
2309
2310 # Given 2 files, verify that they have the same mapping but different
2311 # inodes - i.e. an undisturbed reflink
2312 # Silent if so, make noise if not
2313 _verify_reflink()
2314 {
2315        # not a hard link or symlink?
2316        cmp -s  <(stat -c '%i' $1) <(stat -c '%i' $2) \
2317                && echo "$1 and $2 are not reflinks: same inode number"
2318
2319        # same mapping?
2320        diff -u <($XFS_IO_PROG -c "fiemap" $1 | grep -v $1) \
2321                <($XFS_IO_PROG -c "fiemap" $2 | grep -v $2) \
2322                || echo "$1 and $2 are not reflinks: different extents"
2323 }
2324
2325 _require_relatime()
2326 {
2327         _scratch_mkfs > /dev/null 2>&1
2328         _mount -t $FSTYP -o relatime $SCRATCH_DEV $SCRATCH_MNT || \
2329                 _notrun "relatime not supported by the current kernel"
2330         _scratch_unmount
2331 }
2332
2333 _require_userns()
2334 {
2335         [ -x src/nsexec ] || _notrun "src/nsexec executable not found"
2336         src/nsexec -U true 2>/dev/null || _notrun "userns not supported by this kernel"
2337 }
2338
2339 _create_loop_device()
2340 {
2341         file=$1
2342         dev=`losetup -f --show $file` || _fail "Cannot assign $file to a loop device"
2343         echo $dev
2344 }
2345
2346 _destroy_loop_device()
2347 {
2348         dev=$1
2349         losetup -d $dev || _fail "Cannot destroy loop device $dev"
2350 }
2351
2352 _scale_fsstress_args()
2353 {
2354     args=""
2355     while [ $# -gt 0 ]; do
2356         case "$1" in
2357             -n) args="$args $1 $(($2 * $TIME_FACTOR))"; shift ;;
2358             -p) args="$args $1 $(($2 * $LOAD_FACTOR))"; shift ;;
2359             *) args="$args $1" ;;
2360         esac
2361         shift
2362     done
2363     echo $args
2364 }
2365
2366 #
2367 # Return the logical block size if running on a block device,
2368 # else substitute the page size.
2369 #
2370 _min_dio_alignment()
2371 {
2372     dev=$1
2373
2374     if [ -b "$dev" ]; then
2375         blockdev --getss $dev
2376     else
2377         $here/src/feature -s
2378     fi
2379 }
2380
2381 run_check()
2382 {
2383         echo "# $@" >> $seqres.full 2>&1
2384         "$@" >> $seqres.full 2>&1 || _fail "failed: '$@'"
2385 }
2386
2387 _run_btrfs_util_prog()
2388 {
2389         run_check $BTRFS_UTIL_PROG $*
2390 }
2391
2392 _require_btrfs_send_stream_version()
2393 {
2394         $BTRFS_UTIL_PROG send 2>&1 | \
2395                 grep '^[ \t]*\-\-stream\-version <version>' > /dev/null 2>&1
2396         if [ $? -ne 0 ]; then
2397                 _notrun "Missing btrfs-progs send --stream-version command line option, skipped this test"
2398         fi
2399
2400         # test if btrfs kernel supports send stream version 2
2401         if [ ! -f /sys/fs/btrfs/send/stream_version ]; then
2402                 _notrun "Missing btrfs kernel patch for send stream version 2, skipped this test"
2403         fi
2404 }
2405
2406 _require_btrfs_mkfs_feature()
2407 {
2408         if [ -z $1 ]; then
2409                 echo "Missing feature name argument for _require_btrfs_mkfs_feature"
2410                 exit 1
2411         fi
2412         feat=$1
2413         $MKFS_BTRFS_PROG -O list-all 2>&1 | \
2414                 grep '^[ \t]*'"$feat"'\b' > /dev/null 2>&1
2415         [ $? -eq 0 ] || \
2416                 _notrun "Feature $feat not supported in the available version of mkfs.btrfs"
2417 }
2418
2419 _require_btrfs_fs_feature()
2420 {
2421         if [ -z $1 ]; then
2422                 echo "Missing feature name argument for _require_btrfs_fs_feature"
2423                 exit 1
2424         fi
2425         feat=$1
2426         modprobe btrfs > /dev/null 2>&1
2427         [ -e /sys/fs/btrfs/features/$feat ] || \
2428                 _notrun "Feature $feat not supported by the available btrfs version"
2429 }
2430
2431 _get_total_inode()
2432 {
2433         if [ -z "$1" ]; then
2434                 echo "Usage: _get_total_inode <mnt>"
2435                 exit 1
2436         fi
2437         local nr_inode;
2438         nr_inode=`$DF_PROG -i $1 | tail -1 | awk '{print $3}'`
2439         echo $nr_inode
2440 }
2441
2442 _get_used_inode()
2443 {
2444         if [ -z "$1" ]; then
2445                 echo "Usage: _get_used_inode <mnt>"
2446                 exit 1
2447         fi
2448         local nr_inode;
2449         nr_inode=`$DF_PROG -i $1 | tail -1 | awk '{print $4}'`
2450         echo $nr_inode
2451 }
2452
2453 _get_free_inode()
2454 {
2455         if [ -z "$1" ]; then
2456                 echo "Usage: _get_free_inode <mnt>"
2457                 exit 1
2458         fi
2459         local nr_inode;
2460         nr_inode=`$DF_PROG -i $1 | tail -1 | awk '{print $5}'`
2461         echo $nr_inode
2462 }
2463
2464 init_rc()
2465 {
2466         if [ "$iam" == new ]
2467         then
2468                 return
2469         fi
2470         # make some further configuration checks here
2471         if [ "$TEST_DEV" = ""  ]
2472         then
2473                 echo "common/rc: Error: \$TEST_DEV is not set"
2474                 exit 1
2475         fi
2476
2477         # if $TEST_DEV is not mounted, mount it now as XFS
2478         if [ -z "`_fs_type $TEST_DEV`" ]
2479         then
2480                 # $TEST_DEV is not mounted
2481                 if ! _test_mount
2482                 then
2483                         echo "common/rc: retrying test device mount with external set"
2484                         [ "$USE_EXTERNAL" != "yes" ] && export USE_EXTERNAL=yes
2485                         if ! _test_mount
2486                         then
2487                                 echo "common/rc: could not mount $TEST_DEV on $TEST_DIR"
2488                                 exit 1
2489                         fi
2490                 fi
2491         fi
2492
2493         if [ "`_fs_type $TEST_DEV`" != "$FSTYP" ]
2494         then
2495                 echo "common/rc: Error: \$TEST_DEV ($TEST_DEV) is not a MOUNTED $FSTYP filesystem"
2496                 $DF_PROG $TEST_DEV
2497                 exit 1
2498         fi
2499         # Figure out if we need to add -F ("foreign", deprecated) option to xfs_io
2500         xfs_io -c stat $TEST_DIR 2>&1 | grep -q "is not on an XFS filesystem" && \
2501         export XFS_IO_PROG="$XFS_IO_PROG -F"
2502 }
2503
2504 # get real device path name by following link
2505 _real_dev()
2506 {
2507         local _dev=$1
2508         if [ -b "$_dev" ] && [ -L "$_dev" ]; then
2509                 _dev=`readlink -f "$_dev"`
2510         fi
2511         echo $_dev
2512 }
2513
2514 # basename of a device
2515 _short_dev()
2516 {
2517         echo `basename $(_real_dev $1)`
2518 }
2519
2520 init_rc
2521
2522 ################################################################################
2523 # make sure this script returns success
2524 /bin/true