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