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