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