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