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