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