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