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