common/rc: fix check for disabled kmemleak
[xfstests-dev.git] / common / rc
index 99d2ebbdbfd71436e7b9f4ce77f0f5240739db1d..d5bb1feee2c3f83093f7eec3540b4466a8c5b502 100644 (file)
--- a/common/rc
+++ b/common/rc
@@ -1,37 +1,10 @@
 ##/bin/bash
-#-----------------------------------------------------------------------
-#  Copyright (c) 2000-2006 Silicon Graphics, Inc.  All Rights Reserved.
-#  This program is free software; you can redistribute it and/or modify
-#  it under the terms of the GNU General Public License as published by
-#  the Free Software Foundation; either version 2 of the License, or
-#  (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software
-#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
-#  USA
-#
-#  Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
-#  Mountain View, CA 94043, USA, or: http://www.sgi.com
-#-----------------------------------------------------------------------
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright (c) 2000-2006 Silicon Graphics, Inc.  All Rights Reserved.
 
-BC=$(which bc 2> /dev/null) || BC=
+. common/config
 
-# Valid test names start with 3 digits "NNN":
-#  "[0-9]\{3\}"
-# followed by an optional "-":
-#  "-\?"
-# followed by an optional combination of alphanumeric and "-" chars:
-#  "[[:alnum:]-]*"
-# e.g. 999-the-mark-of-fstests
-#
-VALID_TEST_ID="[0-9]\{3\}"
-VALID_TEST_NAME="$VALID_TEST_ID-\?[[:alnum:]-]*"
+BC=$(which bc 2> /dev/null) || BC=
 
 # Some tests are not relevant or functional when testing XFS realtime
 # subvolumes along with the rtinherit=1 mkfs option.  In these cases,
@@ -110,32 +83,28 @@ _ls_l()
        ls -l $* | sed "s/\(^[-rwxdlbcpsStT]*\)\. /\1 /" | grep -v 'lost+found'
 }
 
-# we need common/config
-if [ "$iam" != "check" ]
-then
-    if ! . ./common/config
-        then
-        echo "$iam: failed to source common/config"
-        exit 1
-    fi
-fi
-
 _dump_err()
 {
-    err_msg="$*"
-    echo "$err_msg"
+    _err_msg="$*"
+    echo "$_err_msg"
+}
+
+_dump_err_cont()
+{
+    _err_msg="$*"
+    echo -n "$_err_msg"
 }
 
 _dump_err2()
 {
-    err_msg="$*"
-    >2& echo "$err_msg"
+    _err_msg="$*"
+    >2& echo "$_err_msg"
 }
 
 _log_err()
 {
-    err_msg="$*"
-    echo "$err_msg" | tee -a $seqres.full
+    _err_msg="$*"
+    echo "$_err_msg" | tee -a $seqres.full
     echo "(see $seqres.full for details)"
 }
 
@@ -149,6 +118,7 @@ case "$FSTYP" in
         [ "$XFS_REPAIR_PROG" = "" ] && _fatal "xfs_repair not found"
         [ "$XFS_DB_PROG" = "" ] && _fatal "xfs_db not found"
         [ "$MKFS_XFS_PROG" = "" ] && _fatal "mkfs_xfs not found"
+        [ "$XFS_INFO_PROG" = "" ] && _fatal "xfs_info not found"
 
         . ./common/xfs
         ;;
@@ -333,7 +303,7 @@ _supports_filetype()
        local fstyp=`$DF_PROG $dir | tail -1 | $AWK_PROG '{print $2}'`
        case "$fstyp" in
        xfs)
-               xfs_info $dir | grep -q "ftype=1"
+               $XFS_INFO_PROG $dir | grep -q "ftype=1"
                ;;
        ext2|ext3|ext4)
                local dev=`$DF_PROG $dir | tail -1 | $AWK_PROG '{print $1}'`
@@ -999,7 +969,7 @@ _scratch_mkfs_sized()
        ;;
     btrfs)
        local mixed_opt=
-       (( fssize <= 100 * 1024 * 1024 )) && mixed_opt='--mixed'
+       (( fssize <= 1024 * 1024 * 1024 )) && mixed_opt='--mixed'
        $MKFS_BTRFS_PROG $MKFS_OPTIONS $mixed_opt -b $fssize $SCRATCH_DEV
        ;;
     jfs)
@@ -1169,27 +1139,6 @@ _get_pids_by_name()
        -e "/[0-9]:[0-9][0-9]  *$1 /s/ .*//p"
 }
 
-# fix malloc libs output
-#
-_fix_malloc()
-{
-    # filter out the Electric Fence notice
-    $PERL_PROG -e '
-        while (<>) {
-            if (defined $o && /^\s+Electric Fence/) {
-                chomp($o);
-                print "$o";
-                undef $o;
-                next;
-            }
-            print $o if (defined $o);
-
-            $o=$_;
-        }
-        print $o if (defined $o);
-    '
-}
-
 #
 # _df_device : get an IRIX style df line for a given device
 #
@@ -1317,13 +1266,13 @@ _is_block_dev()
        exit 1
     fi
 
-    local _dev=$1
-    if [ -L "${_dev}" ]; then
-        _dev=`readlink -f "${_dev}"`
+    local dev=$1
+    if [ -L "$dev" ]; then
+        dev=`readlink -f "$dev"`
     fi
 
-    if [ -b "${_dev}" ]; then
-        src/lstat64 "${_dev}" | $AWK_PROG '/Device type:/ { print $9 }'
+    if [ -b "$dev" ]; then
+        src/lstat64 "$dev" | $AWK_PROG '/Device type:/ { print $9 }'
     fi
 }
 
@@ -1336,13 +1285,13 @@ _is_char_dev()
                exit 1
        fi
 
-       local _dev=$1
-       if [ -L "${_dev}" ]; then
-               _dev=`readlink -f "${_dev}"`
+       local dev=$1
+       if [ -L "$dev" ]; then
+               dev=`readlink -f "$dev"`
        fi
 
-       if [ -c "${_dev}" ]; then
-               src/lstat64 "${_dev}" | $AWK_PROG '/Device type:/ { print $9 }'
+       if [ -c "$dev" ]; then
+               src/lstat64 "$dev" | $AWK_PROG '/Device type:/ { print $9 }'
        fi
 }
 
@@ -1359,20 +1308,20 @@ _is_char_dev()
 _do()
 {
     if [ $# -eq 1 ]; then
-       local _cmd=$1
+       local cmd=$1
     elif [ $# -eq 2 ]; then
-       local _note=$1
-       local _cmd=$2
-       echo -n "$_note... "
+       local note=$1
+       local cmd=$2
+       echo -n "$note... "
     else
        echo "Usage: _do [note] cmd" 1>&2
        status=1; exit
     fi
 
-    (eval "echo '---' \"$_cmd\"") >>$seqres.full
-    (eval "$_cmd") >$tmp._out 2>&1
+    (eval "echo '---' \"$cmd\"") >>$seqres.full
+    (eval "$cmd") >$tmp._out 2>&1
     local ret=$?
-    cat $tmp._out | _fix_malloc >>$seqres.full
+    cat $tmp._out >>$seqres.full
     rm -f $tmp._out
     if [ $# -eq 2 ]; then
        if [ $ret -eq 0 ]; then
@@ -1386,7 +1335,7 @@ _do()
            -o \( $# -eq 2 -a "$_do_die_on_error" = "message_only" \) ]
     then
        [ $# -ne 2 ] && echo
-       eval "echo \"$_cmd\" failed \(returned $ret\): see $seqres.full"
+       eval "echo \"$cmd\" failed \(returned $ret\): see $seqres.full"
        status=1; exit
     fi
 
@@ -1600,6 +1549,16 @@ _require_scratch()
        touch ${RESULT_DIR}/require_scratch
 }
 
+# require a scratch dev of a minimum size (in kb)
+_require_scratch_size()
+{
+       [ $# -eq 1 ] || _fail "_require_scratch_size: expected size param"
+
+       _require_scratch
+       local devsize=`_get_device_size $SCRATCH_DEV`
+       [ $devsize -lt $1 ] && _notrun "scratch dev too small"
+}
+
 
 # this test needs a test partition - check we're ok & mount it
 #
@@ -1805,16 +1764,16 @@ _require_no_realtime()
 _require_command()
 {
        if [ $# -eq 2 ]; then
-               local _name="$2"
+               local name="$2"
        elif [ $# -eq 1 ]; then
-               local _name="$1"
+               local name="$1"
        else
                _fail "usage: _require_command <command> [<name>]"
        fi
 
-       local _command=`echo "$1" | awk '{ print $1 }'`
-       if [ ! -x "$_command" ]; then
-               _notrun "$_name utility required, skipped this test"
+       local command=`echo "$1" | awk '{ print $1 }'`
+       if [ ! -x "$command" ]; then
+               _notrun "$name utility required, skipped this test"
        fi
 }
 
@@ -1862,7 +1821,7 @@ _require_sane_bdev_flush()
 # this test requires a specific device mapper target
 _require_dm_target()
 {
-       local _target=$1
+       local target=$1
 
        # require SCRATCH_DEV to be a valid block device with sane BLKFLSBUF
        # behaviour
@@ -1870,11 +1829,11 @@ _require_dm_target()
        _require_sane_bdev_flush $SCRATCH_DEV
        _require_command "$DMSETUP_PROG" dmsetup
 
-       modprobe dm-$_target >/dev/null 2>&1
+       modprobe dm-$target >/dev/null 2>&1
 
-       $DMSETUP_PROG targets 2>&1 | grep -q ^$_target
+       $DMSETUP_PROG targets 2>&1 | grep -q ^$target
        if [ $? -ne 0 ]; then
-               _notrun "This test requires dm $_target support"
+               _notrun "This test requires dm $target support"
        fi
 }
 
@@ -2137,17 +2096,27 @@ _require_xfs_io_command()
                        -c "fiemap -v $param" $testfile 2>&1`
                param_checked=1
                ;;
-       "flink" )
-               testio=`$XFS_IO_PROG -T -F -c "flink $testfile" \
-                       $TEST_DIR 2>&1`
+       "flink")
+               local testlink=$TEST_DIR/$$.link.xfs_io
+               testio=`$XFS_IO_PROG -F -f -c "flink $testlink" $testfile 2>&1`
+               rm -f $testlink > /dev/null 2>&1
+               ;;
+       "-T")
+               # Check O_TMPFILE support in xfs_io, kernel and fs
+               testio=`$XFS_IO_PROG -T -c quit $TEST_DIR 2>&1`
                echo $testio | egrep -q "invalid option|Is a directory" && \
                        _notrun "xfs_io $command support is missing"
+               echo $testio | grep -q "Operation not supported" && \
+                       _notrun "O_TMPFILE is not supported"
                ;;
-       "fsmap" )
+       "fsmap")
                testio=`$XFS_IO_PROG -f -c "fsmap" $testfile 2>&1`
                echo $testio | grep -q "Inappropriate ioctl" && \
                        _notrun "xfs_io $command support is missing"
                ;;
+       "label")
+               testio=`$XFS_IO_PROG -c "label" $TEST_DIR 2>&1`
+               ;;
        "open")
                # -c "open $f" is broken in xfs_io <= 4.8. Along with the fix,
                # a new -C flag was introduced to execute one shot commands.
@@ -2168,7 +2137,7 @@ _require_xfs_io_command()
                param_checked=1
                ;;
        "scrub"|"repair")
-               testio=`$XFS_IO_PROG -x -c "$command probe 0" $TEST_DIR 2>&1`
+               testio=`$XFS_IO_PROG -x -c "$command probe" $TEST_DIR 2>&1`
                echo $testio | grep -q "Inappropriate ioctl" && \
                        _notrun "xfs_io $command support is missing"
                ;;
@@ -2186,7 +2155,7 @@ _require_xfs_io_command()
        rm -f $testfile 2>&1 > /dev/null
        echo $testio | grep -q "not found" && \
                _notrun "xfs_io $command support is missing"
-       echo $testio | grep -q "Operation not supported" && \
+       echo $testio | grep -q "Operation not supported\|Inappropriate ioctl" && \
                _notrun "xfs_io $command failed (old kernel/wrong fs?)"
        echo $testio | grep -q "Invalid" && \
                _notrun "xfs_io $command failed (old kernel/wrong fs/bad args?)"
@@ -2226,6 +2195,19 @@ _require_odirect()
        rm -f $testfile 2>&1 > /dev/null
 }
 
+_format_swapfile() {
+       local fname="$1"
+       local sz="$2"
+
+       rm -f "$fname"
+       touch "$fname"
+       chmod 0600 "$fname"
+       # Swap files must be nocow on Btrfs.
+       $CHATTR_PROG +C "$fname" > /dev/null 2>&1
+       _pwrite_byte 0x61 0 "$sz" "$fname" >> $seqres.full
+       mkswap "$fname" >> $seqres.full
+}
+
 # Check that the filesystem supports swapfiles
 _require_scratch_swapfile()
 {
@@ -2235,10 +2217,8 @@ _require_scratch_swapfile()
        _scratch_mount
 
        # Minimum size for mkswap is 10 pages
-       local size=$(($(get_page_size) * 10))
+       _format_swapfile "$SCRATCH_MNT/swap" $(($(get_page_size) * 10))
 
-       _pwrite_byte 0x61 0 "$size" "$SCRATCH_MNT/swap" >/dev/null 2>&1
-       mkswap "$SCRATCH_MNT/swap" >/dev/null 2>&1
        if ! swapon "$SCRATCH_MNT/swap" >/dev/null 2>&1; then
                _scratch_unmount
                _notrun "swapfiles are not supported"
@@ -2949,15 +2929,15 @@ _require_scratch_dev_pool()
 # must be called after _require_scratch_dev_pool
 _require_scratch_dev_pool_equal_size()
 {
-       local _size
-       local _newsize
-       local _dev
+       local size
+       local newsize
+       local dev
 
        # SCRATCH_DEV has been set to the first device in SCRATCH_DEV_POOL
-       _size=`_get_device_size $SCRATCH_DEV`
-       for _dev in $SCRATCH_DEV_POOL; do
-               _newsize=`_get_device_size $_dev`
-               if [ $_size -ne $_newsize ]; then
+       size=`_get_device_size $SCRATCH_DEV`
+       for dev in $SCRATCH_DEV_POOL; do
+               newsize=`_get_device_size $dev`
+               if [ $size -ne $newsize ]; then
                        _notrun "This test requires devices in SCRATCH_DEV_POOL have the same size"
                fi
        done
@@ -3246,9 +3226,12 @@ _exclude_scratch_mount_option()
 _require_atime()
 {
        _exclude_scratch_mount_option "noatime"
-       if [ "$FSTYP" == "nfs" ]; then
-               _notrun "atime related mount options have no effect on NFS"
-       fi
+       case $FSTYP in
+       nfs|cifs)
+               _notrun "atime related mount options have no effect on $FSTYP"
+               ;;
+       esac
+
 }
 
 _require_relatime()
@@ -3477,7 +3460,7 @@ _check_dmesg()
        _dmesg_since_test_start | $filter >$seqres.dmesg
        egrep -q -e "kernel BUG at" \
             -e "WARNING:" \
-            -e "BUG:" \
+            -e "\bBUG:" \
             -e "Oops:" \
             -e "possible recursive locking detected" \
             -e "Internal error" \
@@ -3499,59 +3482,68 @@ _check_dmesg()
 # capture the kmemleak report
 _capture_kmemleak()
 {
-       local _kern_knob="${DEBUGFS_MNT}/kmemleak"
-       local _leak_file="$1"
+       local kern_knob="${DEBUGFS_MNT}/kmemleak"
+       local leak_file="$1"
 
        # Tell the kernel to scan for memory leaks.  Apparently the write
        # returns before the scan is complete, so do it twice in the hopes
        # that twice is enough to capture all the leaks.
-       echo "scan" > "${_kern_knob}"
-       cat "${_kern_knob}" > /dev/null
-       echo "scan" > "${_kern_knob}"
-       cat "${_kern_knob}" > "${_leak_file}.tmp"
-       if [ -s "${_leak_file}.tmp" ]; then
-               cat > "${_leak_file}" << ENDL
+       echo "scan" > "$kern_knob"
+       cat "$kern_knob" > /dev/null
+       echo "scan" > "$kern_knob"
+       cat "$kern_knob" > "$leak_file.tmp"
+       if [ -s "$leak_file.tmp" ]; then
+               cat > "$leak_file" << ENDL
 EXPERIMENTAL kmemleak reported some memory leaks!  Due to the way kmemleak
 works, the leak might be from an earlier test, or something totally unrelated.
 ENDL
-               cat "${_leak_file}.tmp" >> "${_leak_file}"
-               rm -rf "${_leak_file}.tmp"
+               cat "$leak_file.tmp" >> "$leak_file"
        fi
-       echo "clear" > "${_kern_knob}"
+       rm -rf "$leak_file.tmp"
+       echo "clear" > "$kern_knob"
 }
 
 # set up kmemleak
 _init_kmemleak()
 {
-       local _kern_knob="${DEBUGFS_MNT}/kmemleak"
+       local kern_knob="${DEBUGFS_MNT}/kmemleak"
+
+       # Since kernel v4.19-rc3, the kmemleak knob exists even if kmemleak is
+       # disabled, but returns EBUSY on write. So instead of relying on
+       # existance of writable knob file, we use a test file to indicate that
+       # _check_kmemleak() is enabled only if we actually managed to write to
+       # the knob file.
+       rm -f ${RESULT_BASE}/check_kmemleak
 
-       if [ ! -w "${_kern_knob}" ]; then
+       if [ ! -w "$kern_knob" ]; then
                return 0
        fi
 
        # Disable the automatic scan so that we can control it completely,
        # then dump all the leaks recorded so far.
-       echo "scan=off" > "${_kern_knob}"
-       _capture_kmemleak /dev/null
+       if echo "scan=off" > "$kern_knob" 2>/dev/null; then
+               _capture_kmemleak /dev/null
+               touch ${RESULT_BASE}/check_kmemleak
+       fi
 }
 
 # check kmemleak log
 _check_kmemleak()
 {
-       local _kern_knob="${DEBUGFS_MNT}/kmemleak"
-       local _leak_file="${seqres}.kmemleak"
+       local kern_knob="${DEBUGFS_MNT}/kmemleak"
+       local leak_file="${seqres}.kmemleak"
 
-       if [ ! -w "${_kern_knob}" ]; then
+       if [ ! -f ${RESULT_BASE}/check_kmemleak ]; then
                return 0
        fi
 
        # Capture and report any leaks
-       _capture_kmemleak "${_leak_file}"
-       if [ -s "${_leak_file}" ]; then
-               _dump_err "_check_kmemleak: something found in kmemleak (see ${_leak_file})"
+       _capture_kmemleak "$leak_file"
+       if [ -s "$leak_file" ]; then
+               _dump_err "_check_kmemleak: something found in kmemleak (see $leak_file)"
                return 1
        else
-               rm -f "${_leak_file}"
+               rm -f "$leak_file"
                return 0
        fi
 }
@@ -3564,10 +3556,6 @@ _disable_dmesg_check()
 
 init_rc()
 {
-       if [ "$iam" == new ]
-       then
-               return
-       fi
        # make some further configuration checks here
        if [ "$TEST_DEV" = ""  ]
        then
@@ -3632,11 +3620,11 @@ init_rc()
 # get real device path name by following link
 _real_dev()
 {
-       local _dev=$1
-       if [ -b "$_dev" ] && [ -L "$_dev" ]; then
-               _dev=`readlink -f "$_dev"`
+       local dev=$1
+       if [ -b "$dev" ] && [ -L "$dev" ]; then
+               dev=`readlink -f "$dev"`
        fi
-       echo $_dev
+       echo $dev
 }
 
 # basename of a device
@@ -3647,12 +3635,12 @@ _short_dev()
 
 _sysfs_dev()
 {
-       local _dev=`_real_dev $1`
-       local _maj=$(stat -c%t $_dev | tr [:lower:] [:upper:])
-       local _min=$(stat -c%T $_dev | tr [:lower:] [:upper:])
-       _maj=$(echo "ibase=16; $_maj" | bc)
-       _min=$(echo "ibase=16; $_min" | bc)
-       echo /sys/dev/block/$_maj:$_min
+       local dev=`_real_dev $1`
+       local maj=$(stat -c%t $dev | tr [:lower:] [:upper:])
+       local min=$(stat -c%T $dev | tr [:lower:] [:upper:])
+       maj=$(echo "ibase=16; $maj" | bc)
+       min=$(echo "ibase=16; $min" | bc)
+       echo /sys/dev/block/$maj:$min
 }
 
 # Get the minimum block size of a file.  Usually this is the
@@ -3792,6 +3780,43 @@ _require_scratch_feature()
        esac
 }
 
+# The maximum filesystem label length, /not/ including terminating NULL
+_label_get_max()
+{
+       case $FSTYP in
+       xfs)
+               echo 12
+               ;;
+       btrfs)
+               echo 255
+               ;;
+       *)
+               _notrun "$FSTYP does not define maximum label length"
+               ;;
+       esac
+}
+
+# Helper to check above early in a script
+_require_label_get_max()
+{
+       # Just call _label_get_max which will notrun if appropriate
+       dummy=$(_label_get_max)
+}
+
+_dmsetup_remove()
+{
+       $UDEV_SETTLE_PROG >/dev/null 2>&1
+       $DMSETUP_PROG remove "$@" >>$seqres.full 2>&1
+       $DMSETUP_PROG mknodes >/dev/null 2>&1
+}
+
+_dmsetup_create()
+{
+       $DMSETUP_PROG create "$@" >>$seqres.full 2>&1 || return 1
+       $DMSETUP_PROG mknodes >/dev/null 2>&1
+       $UDEV_SETTLE_PROG >/dev/null 2>&1
+}
+
 init_rc
 
 ################################################################################