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