2 # SPDX-License-Identifier: GPL-2.0
3 # Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved.
7 # Checks that given_value is in range of correct_value +/- tolerance.
8 # Tolerance can be an absolute value or a percentage of the correct value
9 # (see examples with tolerances below).
10 # Outputs suitable message to stdout if it's not in range.
12 # A verbose option, -v, may be used as the LAST argument
15 # foo: 0.0298 = 0.03 +/- 5%
16 # _within_tolerance "foo" 0.0298 0.03 5%
18 # foo: 0.0298 = 0.03 +/- 0.01
19 # _within_tolerance "foo" 0.0298 0.03 0.01
21 # foo: 0.0298 = 0.03 -0.01 +0.002
22 # _within_tolerance "foo" 0.0298 0.03 0.01 0.002
24 # foo: verbose output of 0.0298 = 0.03 +/- 5%
25 # _within_tolerance "foo" 0.0298 0.03 5% -v
36 # maxtol arg is optional
37 # verbose arg is optional
49 [ "$6" = "-v" ] && _verbose=1
52 # find min with or without %
53 _mintolerance=`echo $_mintol | sed -e 's/%//'`
54 if [ $_mintol = $_mintolerance ]
56 _min=`echo "scale=5; $_correct_val-$_mintolerance" | bc`
58 _min=`echo "scale=5; $_correct_val-$_mintolerance*0.01*$_correct_val" | bc`
61 # find max with or without %
62 _maxtolerance=`echo $_maxtol | sed -e 's/%//'`
63 if [ $_maxtol = $_maxtolerance ]
65 _max=`echo "scale=5; $_correct_val+$_maxtolerance" | bc`
67 _max=`echo "scale=5; $_correct_val+$_maxtolerance*0.01*$_correct_val" | bc`
70 $_debug && echo "min = $_min"
71 $_debug && echo "max = $_max"
75 if ($_min <= $_given_val) 1;
76 if ($_min > $_given_val) 0;
81 if ($_given_val <= $_max) 1;
82 if ($_given_val > $_max) 0;
85 _above_min=`bc <$tmp.bc.1`
86 _below_max=`bc <$tmp.bc.2`
90 _in_range=`expr $_above_min \& $_below_max`
92 # fix up min, max precision for output
93 # can vary for 5.3, 6.2
95 # remove any trailing zeroes from min, max if they have fractional parts
96 _min=`echo $_min | sed -e '/\./s/0*$//' -e 's/\.$//'`
97 _max=`echo $_max | sed -e '/\./s/0*$//' -e 's/\.$//'`
99 if [ $_in_range -eq 1 ]
101 [ $_verbose -eq 1 ] && echo $_name is in range
104 [ $_verbose -eq 1 ] && echo $_name has value of $_given_val
105 [ $_verbose -eq 1 ] && echo $_name is NOT in range $_min .. $_max
115 -e 's/[A-Z][a-z][a-z] [A-z][a-z][a-z] *[0-9][0-9]* [0-9][0-9]:[0-9][0-9]:[0-9][0-9] [0-9][0-9][0-9][0-9]$/DATE/'
118 # prints filtered output on stdout, values (use eval) on stderr
119 # Non XFS filesystems always return a 4k block size and a 256 byte inode.
124 _xfs_filter_mkfs "$@"
128 perl -e 'print STDERR "dbsize=4096\nisize=256\n"'
133 # prints the bits we care about in growfs
138 if (/^data\s+=\s+bsize=(\d+)\s+blocks=(\d+), imaxpct=(\d+)/) {
139 print "xfs_growfs --BlockSize=$1 --Blocks=$2\n";
149 /records in/ { next }
150 /records out/ { next }
151 /No space left on device/ { print " !!! disk full (expected)"
159 perl -ne 'if (/.*:(.*)/) {
160 if ( "$last_line" ne "$1" ) { print "$_"; $first_match=1; }
161 elsif ( $first_match==1 ) { print "*\n"; $first_match=0; }
165 print $_; $last_line=$_;
171 # Apart from standard numeric values, we also filter out 'inf', 'nan', and
172 # '-nan' which can result from division in some cases
173 sed -e "s/[0-9/.]* [GMKiBbytes]*, [0-9]* ops\; [0-9/:. sec]* ([infa0-9/.-]* [EPGMKiBbytes]*\/sec and [infa0-9/.-]* ops\/sec)/XXX Bytes, X ops\; XX:XX:XX.X (XXX YYY\/sec and XXX ops\/sec)/"
176 # Also filter out the offset part of xfs_io output
177 # Some test cases may be affected by underlaying extent/chunk layout change,
178 # so wipe out this part to avoid golden output difference
179 _filter_xfs_io_offset()
181 # filter out " at offset XXX" and offset of "pread -v"
182 _filter_xfs_io | sed -e "s/ at offset [0-9]*$//" -e "s/^[0-9a-f]\+:/XXXXXXXX:/"
185 # stderr filter for xfs_io to handle change of error output format (e.g.
186 # pwrite64 -> pwrite).
187 _filter_xfs_io_error()
189 sed -e "s/^\(.*\)64\(: .*$\)/\1\2/"
192 _filter_xfs_io_unique()
194 common_line_filter | _filter_xfs_io
197 _filter_xfs_io_units_modified()
202 $AWK_PROG -v unit="$UNIT" -v unit_size=$UNIT_SIZE '
204 split($2, bytes, "/")
206 bytes_written = strtonum(bytes[1])
208 offset = strtonum($NF)
210 unit_start = offset / unit_size
211 unit_start = int(unit_start)
212 unit_end = (offset + bytes_written - 1) / unit_size
213 unit_end = int(unit_end)
215 printf("%ss modified: [%d - %d]\n", unit, unit_start, unit_end)
222 _filter_xfs_io_blocks_modified()
224 BLOCK_SIZE=$(_get_block_size $SCRATCH_MNT)
226 _filter_xfs_io_units_modified "Block" $BLOCK_SIZE
229 _filter_xfs_io_pages_modified()
231 PAGE_SIZE=$(get_page_size)
233 _filter_xfs_io_units_modified "Page" $PAGE_SIZE
236 _filter_xfs_io_numbers()
238 _filter_xfs_io | sed -E 's/[0-9]+/XXXX/g'
243 # TEST_DEV may be a prefix of TEST_DIR (e.g. /mnt, /mnt/ovl-mnt)
244 # so substitute TEST_DIR first
245 sed -e "s,\B$TEST_DIR,TEST_DIR,g" \
246 -e "s,\B$TEST_DEV,TEST_DEV,g"
251 # SCRATCH_DEV may be a prefix of SCRATCH_MNT (e.g. /mnt, /mnt/ovl-mnt)
252 # so substitute SCRATCH_MNT first
253 sed -e "s,\B$SCRATCH_MNT,SCRATCH_MNT,g" \
254 -e "s,\B$SCRATCH_DEV,SCRATCH_DEV,g" \
258 _filter_testdir_and_scratch()
260 # filter both $TEST_DIR and $SCRATCH_MNT, but always filter the longer
261 # string first if the other string is a substring of the first one
262 if echo "$TEST_DIR" | grep -q "$SCRATCH_MNT"; then
263 _filter_test_dir | _filter_scratch
265 _filter_scratch | _filter_test_dir
269 # Turn any device in the scratch pool into SCRATCH_DEV
270 _filter_scratch_pool()
272 FILTER_STRINGS=`echo $SCRATCH_DEV_POOL | sed -e 's/\s\+/\\\|/g'`
273 sed -e "s,$FILTER_STRINGS,SCRATCH_DEV,g"
283 # Long dev name might be split onto its own line; last
284 # seds remove that newline if present
285 _filter_testdir_and_scratch | _filter_spaces | \
286 sed -e 'N;s/SCRATCH_DEV\n/SCRATCH_DEV/g' | \
287 sed -e 'N;s/TEST_DEV\n/TEST_DEV/g'
290 _filter_project_quota()
292 # Project ID 0 is always present on disk but was not reported
293 # until the GETNEXTQUOTA ioctl came into use. Filter it out.
294 # But if you specify a name for ID 0, that means you want to
295 # deal with it by yourself, this function won't filter it out.
296 _filter_quota | grep -v "^\#0 \|^(null) "
299 # Account for different "ln" failure messages
302 sed -e "s,\(creating symbolic link .*\) to .*: ,\1: ," \
303 -e "s,failed to create,creating,"
306 # If given an arg, filter *that* UUID string
307 # Otherwise look for something that looks like a generic UUID
312 sed -e "s/\(uuid[ :=]\+\) $UUID/\1 <EXACTUUID>/i"
314 sed -e "s/\(uuid[ :=]\+\) [0-9a-f-][0-9a-f-]*/\1 <UUID>/ig"
318 # In mixed group the added disks may have zero used size
321 sed -e "s/0\.00/<SIZE>/g"
324 # Filter out sizes like 6.14MB etc
327 sed -e "s/[0-9\.]\+\s\?[b|k|m|g|t][i]\?[b]\?/<SIZE>/ig"
330 # Convert string read from stdin like 128K to bytes and print it to stdout
331 _filter_size_to_bytes()
334 suffix=${size:${#size}-1}
338 m|M) mul=$((1024*1024)) ;;
339 g|G) mul=$((1024*1024*1024)) ;;
340 t|T) mul=$((1024*1024*1024*1024)) ;;
342 echo $((${size:0:${#size}-1}*$mul))
345 # Print trimmed bytes of fstrim
346 # Starting from util-linux v2.23 fstrim usees human readable sizes in
350 egrep -o "[0-9]+ bytes" | $AWK_PROG '{print $1}'
353 # Remove the ending dot appended to mount error message, util-linux 2.30
360 # Older mount output referred to "block device" when mounting RO devices. It's
361 # gone in newer versions. v2.30 changed the output again. This filter is to
362 # unify all read-only mount messages across all util-linux versions.
364 # for a successful ro mount:
365 # ancient: mount: block device <device> is write-protected, mounting read-only
366 # prior to v2.30: mount: <device> is write-protected, mounting read-only
367 # v2.30 and later: mount: <mountpoint>: WARNING: device write-protected, mounted read-only.
370 # ancient (two-line message):
371 # mount: block device <device> is write-protected, mounting read-only
372 # mount: cannot mount block device <device> read-only
373 # prior to v2.30 (two-line message):
374 # mount: <device> is write-protected, mounting read-only
375 # mount: cannot mount <device> read-only
376 # v2.30 and later (single-line message):
377 # mount: <mountpoint>: cannot mount <device> read-only.
379 # a failed rw remount:
380 # ancient: mount: cannot remount block device <device> read-write, is write-protected
381 # prior to v2.30: mount: cannot remount <device> read-write, is write-protected
382 # v2.30 and later: mount: <mountpoint>: cannot remount <device> read-write, is write-protected.
384 # dmesg(1) may have more information after failed mount mount system call
386 # Now use _filter_ro_mount to unify all these differences across old & new
387 # util-linux versions. So the filtered format would be:
389 # successful ro mount:
390 # mount: device write-protected, mounting read-only
393 # mount: device write-protected, mounting read-only
394 # mount: cannot mount device read-only
397 # mount: cannot remount device read-write, is write-protected
400 if (/write-protected, mount.*read-only/) {
401 # filter successful ro mount, and first line of prior to v2.30
402 # format failed ro mount
403 print "mount: device write-protected, mounting read-only\n";
404 } elsif (/mount: .*: cannot mount.*read-only/) {
405 # filter v2.30 format failed ro mount, convert single-line
406 # message to two-line message
407 print "mount: device write-protected, mounting read-only\n";
408 print "mount: cannot mount device read-only\n";
409 } elsif (/^mount: cannot mount .* read-only$/) {
410 # filter prior to v2.30 format failed ro mount
411 print "mount: cannot mount device read-only\n";
412 } elsif (/mount:.* cannot remount .* read-write.*/) {
413 # filter failed rw remount
414 print "mount: cannot remount device read-write, is write-protected\n";
417 }' | grep -v "dmesg(1) may have more information after failed mount" | \
421 # Filter a failed mount output due to EUCLEAN and USTALE, util-linux changed
422 # the message several times.
425 # mount: Structure needs cleaning
427 # mount: mount <device> on <mountpoint> failed: Structure needs cleaning
429 # mount: <mountpoint>: mount(2) system call failed: Structure needs cleaning.
431 # dmesg(1) may have more information after failed mount mount system call
433 # This is also true for ESTALE error. So let's remove all the changing parts
434 # and keep the 'prior to v2.21' format:
435 # mount: Structure needs cleaning
436 # mount: Stale file handle
437 _filter_error_mount()
439 grep -v "dmesg(1) may have more information after failed mount" | \
440 sed -e "s/mount:\(.*failed:\)/mount:/" | _filter_ending_dot
443 # Similar to _filter_error_mount, filter a busy mount output.
444 # Turn both old (prior to util-linux v2.30) and new (v2.30 and later) format to
446 # old: mount: <device> is already mounted or <mountpoint> busy
447 # new: mount: <mountpoint>: <device> already mounted or mount point busy.
448 # filtered: mount: device already mounted or mount point busy
449 # v2.38 and later, filter out:
450 # dmesg(1) may have more information after failed mount mount system call
453 grep -v "dmesg(1) may have more information after failed mount" | \
454 sed -e "s/.*: .* already mounted or .* busy/mount: device already mounted or mount point busy/" | \
460 BLOCK_SIZE=$(_get_block_size $SCRATCH_MNT)
461 $AWK_PROG -v block_size=$BLOCK_SIZE '
463 offset = strtonum("0"$1);
464 $1 = sprintf("%o", offset / block_size);
471 # Remove quotes from failed mknod calls. Starting with Coreutils v8.25,
472 # mknod errors print unquoted filenames
475 sed -e "s/mknod: [\`']\(.*\)': File exists/mknod: \1: File exists/"
478 # Remove leading "rename" in "mv -v" output
481 sed -e "s/^renamed //"
484 # New stat(1) uses statx(2)
487 sed -e "s/\<cannot stat\>/cannot statx/"
490 # touch v9.0+ modified part of the message printed on error. Filter the
491 # generic part out, but preserve the strerror() part, which is
492 # actually useful for debugging and usually stable.
495 sed -e "s/.* '\(.*\)':\(.*\)/touch: '\1':\2/"
500 sed -e '/^lost+found$/d'
505 sed -e "s,$OVL_LOWER,OVL_LOWER,g" \
506 -e "s,$OVL_UPPER,OVL_UPPER,g" \
507 -e "s,$OVL_WORK,OVL_WORK,g"
510 # interpret filefrag output,
511 # eg. "physical 1234, length 10, logical 5678" -> "1234#10#5678"
515 if (/blocks? of (\d+) bytes/) {
519 ($ext, $logical, $physical, $length) =
520 (/^\s*(\d+):\s+(\d+)..\s+\d+:\s+(\d+)..\s+\d+:\s+(\d+):/)
522 ($flags) = /.*:\s*(\S*)$/;
523 print $physical * $blocksize, "#",
524 $length * $blocksize, "#",
525 $logical * $blocksize, "#",
529 # Clean up the extents list output of 'xfs_io -c fiemap', e.g.
532 # 0: [0..79]: 628365312..628365391
534 # 2: [160..319]: 628365472..628365631
536 # 0 79 628365312 628365391
537 # 160 319 628365472 628365631
541 # first_logical_block last_logical_block first_physical_block last_physical_block
543 # Blocks are 512 bytes, and holes are omitted.
545 _filter_xfs_io_fiemap()
547 grep -E '^[[:space:]]+[0-9]+:' \
548 | grep -v '\<hole\>' \
549 | sed -E 's/^[[:space:]]+[0-9]+://' \
553 # We generate WARNINGs on purpose when applications mix buffered/mmap IO with
554 # direct IO on the same file. This is a helper for _check_dmesg() to filter out
556 _filter_aiodio_dmesg()
558 local warn1="WARNING:.*fs/xfs/xfs_file\.c:.*xfs_file_dio_aio_write.*"
559 local warn2="WARNING:.*fs/xfs/xfs_file\.c:.*xfs_file_dio_aio_read.*"
560 local warn3="WARNING:.*fs/xfs/xfs_file\.c:.*xfs_file_read_iter.*"
561 local warn4="WARNING:.*fs/xfs/xfs_file\.c:.*xfs_file_aio_read.*"
562 local warn5="WARNING:.*fs/iomap\.c:.*iomap_dio_rw.*"
563 local warn6="WARNING:.*fs/xfs/xfs_aops\.c:.*__xfs_get_blocks.*"
564 local warn7="WARNING:.*fs/iomap\.c:.*iomap_dio_actor.*"
565 local warn8="WARNING:.*fs/iomap\.c:.*iomap_dio_complete.*"
566 local warn9="WARNING:.*fs/direct-io\.c:.*dio_complete.*"
567 local warn10="WARNING:.*fs/iomap/direct-io\.c:.*iomap_dio_actor.*"
568 sed -e "s#$warn1#Intentional warnings in xfs_file_dio_aio_write#" \
569 -e "s#$warn2#Intentional warnings in xfs_file_dio_aio_read#" \
570 -e "s#$warn3#Intentional warnings in xfs_file_read_iter#" \
571 -e "s#$warn4#Intentional warnings in xfs_file_aio_read#" \
572 -e "s#$warn5#Intentional warnings in iomap_dio_rw#" \
573 -e "s#$warn6#Intentional warnings in __xfs_get_blocks#" \
574 -e "s#$warn7#Intentional warnings in iomap_dio_actor#" \
575 -e "s#$warn8#Intentional warnings in iomap_dio_complete#" \
576 -e "s#$warn9#Intentional warnings in dio_complete#" \
577 -e "s#$warn10#Intentional warnings in iomap_dio_actor#"
580 # We generate assert related WARNINGs on purpose and make sure test doesn't fail
581 # because of these warnings. This is a helper for _check_dmesg() to filter out
583 _filter_assert_dmesg()
585 local warn1="WARNING:.*fs/xfs/xfs_message\.c:.*asswarn.*"
586 local warn2="WARNING:.*fs/xfs/xfs_message\.c:.*assfail.*"
587 sed -e "s#$warn1#Intentional warnings in asswarn#" \
588 -e "s#$warn2#Intentional warnings in assfail#"
591 # With version 2.41 of libcap, the output format of getcap changed.
592 # More specifically such change was added by the following commit:
594 # commit 177cd418031b1acfcf73fe3b1af9f3279828681c
595 # Author: Andrew G. Morgan <morgan@kernel.org>
596 # Date: Tue Jul 21 22:58:05 2020 -0700
598 # A more compact form for the text representation of capabilities.
600 # While this does not change anything about the supported range of
601 # equivalent text specifications for capabilities, as accepted by
602 # cap_from_text(), this does alter the preferred output format of
603 # cap_to_text() to be two characters shorter in most cases. That is,
604 # what used to be summarized as:
608 # is now converted to the equivalent text:
612 # which is also more intuitive.
616 sed -e "s/= //" -e "s/\+/=/g"
619 # Filter user/group/project id numbers out of quota reports, and standardize
620 # the block counts to use filesystem block size. Callers must set the id and
621 # bsize variables before calling this function.
622 _filter_quota_report()
624 test -n "$id" || echo "id must be set"
625 test -n "$bsize" || echo "block size must be set"
627 tr -s '[:space:]' | \
629 s/^\#'$id' /[NAME] /g;
630 s/^\#0 \d+ /[ROOT] 0 /g;
634 if ($ENV{'LARGE_SCRATCH_DEV'}) {
635 $val = $ENV{'NUM_SPACE_FILES'};
637 s/(^\[ROOT\] \S+ \S+ \S+ \S+ \[--------\] )(\S+)/$1@{[$2 - $val]}/g' |
638 sed -e 's/ 65535 \[--------\]/ 00 \[--------\]/g' |
640 s|^(.*?) (\d+) (\d+) (\d+)|$1 @{[$2 * 1024 /'$bsize']} @{[$3 * 1024 /'$bsize']} @{[$4 * 1024 /'$bsize']}|'
644 # Bash 5.1+ adds "line 1: " when reporting an error when running a
645 # command via the -c option. For example, "bash -c 'echo foo > /'"
646 # will result in the error "bash: line 1: /: Is a directory" when
647 # earlier versions of bash would omit the "line 1: " annotation.
651 sed -e "s/^bash: line 1: /bash: /"
655 # blkzone report added zone capacity to be printed from v2.37.
656 # This filter will add an extra column 'cap' with the same value of
657 # 'len'(zone size) for blkzone version < 2.37
659 # Before: start: 0x000100000, len 0x040000, wptr 0x000000 ..
660 # After: start: 0x000100000, len 0x040000, cap 0x040000, wptr 0x000000 ..
661 _filter_blkzone_report()
663 $AWK_PROG -F "," 'BEGIN{OFS=",";} $3 !~ /cap/ {$2=$2","$2;} {print;}' |\
667 # make sure this script returns success