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