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