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