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