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