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