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