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