]> git.proxmox.com Git - mirror_zfs.git/blobdiff - tests/zfs-tests/include/libtest.shlib
Do not iterate through filesystems unnecessarily
[mirror_zfs.git] / tests / zfs-tests / include / libtest.shlib
index 8918dd885c2fa5c823c5e23d95046a166ef27b68..ea9448353b68fc0732b9542015ae70310fa63386 100644 (file)
@@ -1,4 +1,3 @@
-#!/bin/ksh -p
 #
 # CDDL HEADER START
 #
 #
 # Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
-# Copyright (c) 2012, 2016 by Delphix. All rights reserved.
-# Copyright 2016 Nexenta Systems, Inc.
+# Copyright (c) 2012, 2017 by Delphix. All rights reserved.
+# Copyright (c) 2017 by Tim Chase. All rights reserved.
+# Copyright (c) 2017 by Nexenta Systems, Inc. All rights reserved.
 # Copyright (c) 2017 Lawrence Livermore National Security, LLC.
 # Copyright (c) 2017 Datto Inc.
 # Copyright (c) 2017 Open-E, Inc. All Rights Reserved.
+# Use is subject to license terms.
 #
 
 . ${STF_TOOLS}/include/logapi.shlib
@@ -42,6 +43,20 @@ if [ -n "$STF_PATH" ]; then
        PATH="$STF_PATH"
 fi
 
+#
+# Generic dot version comparison function
+#
+# Returns success when version $1 is greater than or equal to $2.
+#
+function compare_version_gte
+{
+       if [[ "$(printf "$1\n$2" | sort -V | tail -n1)" == "$1" ]]; then
+               return 0
+       else
+               return 1
+       fi
+}
+
 # Linux kernel version comparison function
 #
 # $1 Linux version ("4.10", "2.6.32") or blank for installed Linux version
@@ -590,6 +605,8 @@ function default_cleanup_noexit
        if is_mpath_device $disk1; then
                delete_partitions
        fi
+
+       rm -f $TEST_BASE_DIR/{err,out}
 }
 
 
@@ -627,7 +644,7 @@ function destroy_snapshot
        typeset snap=${1:-$TESTPOOL/$TESTFS@$TESTSNAP}
 
        if ! snapexists $snap; then
-               log_fail "'$snap' does not existed."
+               log_fail "'$snap' does not exist."
        fi
 
        #
@@ -806,7 +823,11 @@ function zero_partitions #<whole_disk_name>
        typeset i
 
        if is_linux; then
-               log_must parted $DEV_DSKDIR/$diskname -s -- mklabel gpt
+               DSK=$DEV_DSKDIR/$diskname
+               DSK=$(echo $DSK | sed -e "s|//|/|g")
+               log_must parted $DSK -s -- mklabel gpt
+               blockdev --rereadpt $DSK 2>/dev/null
+               block_device_wait
        else
                for i in 0 1 3 4 5 6 7
                do
@@ -834,10 +855,11 @@ function set_partition #<slice_num> <slice_start> <size_plus_units>  <whole_disk
        typeset start=$2
        typeset size=$3
        typeset disk=$4
-       [[ -z $slicenum || -z $size || -z $disk ]] && \
-           log_fail "The slice, size or disk name is unspecified."
 
        if is_linux; then
+               if [[ -z $size || -z $disk ]]; then
+                       log_fail "The size or disk name is unspecified."
+               fi
                typeset size_mb=${size%%[mMgG]}
 
                size_mb=${size_mb%%[mMgG][bB]}
@@ -880,6 +902,10 @@ function set_partition #<slice_num> <slice_start> <size_plus_units>  <whole_disk
                blockdev --rereadpt $DEV_DSKDIR/$disk 2>/dev/null
                block_device_wait
        else
+               if [[ -z $slicenum || -z $size || -z $disk ]]; then
+                       log_fail "The slice, size or disk name is unspecified."
+               fi
+
                typeset format_file=/var/tmp/format_in.$$
 
                echo "partition" >$format_file
@@ -1005,7 +1031,7 @@ function get_endslice #<disk> <slice>
 
                ((endcyl = (endcyl + 1) / ratio))
        fi
-       
+
        echo $endcyl
 }
 
@@ -1068,14 +1094,14 @@ function fill_fs # destdir dirnum filenum bytes num_writes data
        typeset -i filenum=${3:-50}
        typeset -i bytes=${4:-8192}
        typeset -i num_writes=${5:-10240}
-       typeset -i data=${6:-0}
+       typeset data=${6:-0}
 
        typeset -i odirnum=1
        typeset -i idirnum=0
        typeset -i fn=0
        typeset -i retval=0
 
-       log_must mkdir -p $destdir/$idirnum
+       mkdir -p $destdir/$idirnum
        while (($odirnum > 0)); do
                if ((dirnum >= 0 && idirnum >= dirnum)); then
                        odirnum=0
@@ -1091,7 +1117,7 @@ function fill_fs # destdir dirnum filenum bytes num_writes data
                if (($fn >= $filenum)); then
                        fn=0
                        ((idirnum = idirnum + 1))
-                       log_must mkdir -p $destdir/$idirnum
+                       mkdir -p $destdir/$idirnum
                else
                        ((fn = fn + 1))
                fi
@@ -1206,30 +1232,11 @@ function datasetnonexists
        return 0
 }
 
-#
-# Given a mountpoint, or a dataset name, determine if it is shared via NFS.
-#
-# Returns 0 if shared, 1 otherwise.
-#
-function is_shared
+function is_shared_impl
 {
        typeset fs=$1
        typeset mtpt
 
-       if [[ $fs != "/"* ]] ; then
-               if datasetnonexists "$fs" ; then
-                       return 1
-               else
-                       mtpt=$(get_prop mountpoint "$fs")
-                       case $mtpt in
-                               none|legacy|-) return 1
-                                       ;;
-                               *)      fs=$mtpt
-                                       ;;
-                       esac
-               fi
-       fi
-
        if is_linux; then
                for mtpt in `share | awk '{print $1}'` ; do
                        if [[ $mtpt == $fs ]] ; then
@@ -1253,6 +1260,33 @@ function is_shared
        return 1
 }
 
+#
+# Given a mountpoint, or a dataset name, determine if it is shared via NFS.
+#
+# Returns 0 if shared, 1 otherwise.
+#
+function is_shared
+{
+       typeset fs=$1
+       typeset mtpt
+
+       if [[ $fs != "/"* ]] ; then
+               if datasetnonexists "$fs" ; then
+                       return 1
+               else
+                       mtpt=$(get_prop mountpoint "$fs")
+                       case $mtpt in
+                               none|legacy|-) return 1
+                                       ;;
+                               *)      fs=$mtpt
+                                       ;;
+                       esac
+               fi
+       fi
+
+       is_shared_impl "$fs"
+}
+
 #
 # Given a dataset name determine if it is shared via SMB.
 #
@@ -1591,6 +1625,31 @@ function destroy_pool #pool
        return 0
 }
 
+# Return 0 if created successfully; $? otherwise
+#
+# $1 - dataset name
+# $2-n - dataset options
+
+function create_dataset #dataset dataset_options
+{
+       typeset dataset=$1
+
+       shift
+
+       if [[ -z $dataset ]]; then
+               log_note "Missing dataset name."
+               return 1
+       fi
+
+       if datasetexists $dataset ; then
+               destroy_dataset $dataset
+       fi
+
+       log_must zfs create $@ $dataset
+
+       return 0
+}
+
 # Return 0 if destroy successfully or the dataset exists; $? otherwise
 # Note: In local zones, this function should return 0 silently.
 #
@@ -1874,6 +1933,23 @@ function verify_filesys # pool filesystem dir
        log_must rm -rf $zdbout
 }
 
+#
+# Given a pool issue a scrub and verify that no checksum errors are reported.
+#
+function verify_pool
+{
+       typeset pool=${1:-$TESTPOOL}
+
+       log_must zpool scrub $pool
+       log_must wait_scrubbed $pool
+
+       cksum=$(zpool status $pool | awk 'L{print $NF;L=0} /CKSUM$/{L=1}')
+       if [[ $cksum != 0 ]]; then
+               log_must zpool status -v
+               log_fail "Unexpected CKSUM errors found on $pool ($cksum)"
+       fi
+}
+
 #
 # Given a pool, and this function list all disks in the pool
 #
@@ -1883,7 +1959,7 @@ function get_disklist # pool
 
        disklist=$(zpool iostat -v $1 | nawk '(NR >4) {print $1}' | \
            grep -v "\-\-\-\-\-" | \
-           egrep -v -e "^(mirror|raidz1|raidz2|spare|log|cache)$")
+           egrep -v -e "^(mirror|raidz[1-3]|spare|log|cache|special|dedup)$")
 
        echo $disklist
 }
@@ -1957,7 +2033,7 @@ function check_hotspare_state # pool disk state{inuse,avail}
 function wait_hotspare_state # pool disk state timeout
 {
        typeset pool=$1
-       typeset disk=${2#$/DEV_DSKDIR/}
+       typeset disk=${2#*$DEV_DSKDIR/}
        typeset state=$3
        typeset timeout=${4:-60}
        typeset -i i=0
@@ -2001,7 +2077,7 @@ function check_slog_state # pool disk state{online,offline,unavail}
 function check_vdev_state # pool disk state{online,offline,unavail}
 {
        typeset pool=$1
-       typeset disk=${2#$/DEV_DSKDIR/}
+       typeset disk=${2#*$DEV_DSKDIR/}
        typeset state=$3
 
        cur_state=$(get_device_state $pool $disk)
@@ -2020,7 +2096,7 @@ function check_vdev_state # pool disk state{online,offline,unavail}
 function wait_vdev_state # pool disk state timeout
 {
        typeset pool=$1
-       typeset disk=${2#$/DEV_DSKDIR/}
+       typeset disk=${2#*$DEV_DSKDIR/}
        typeset state=$3
        typeset timeout=${4:-60}
        typeset -i i=0
@@ -2068,6 +2144,8 @@ function check_pool_status # pool token keyword <verbose>
 #      is_pool_scrubbed - to check if the pool is scrub completed
 #      is_pool_scrub_stopped - to check if the pool is scrub stopped
 #      is_pool_scrub_paused - to check if the pool has scrub paused
+#      is_pool_removing - to check if the pool is removing a vdev
+#      is_pool_removed - to check if the pool is remove completed
 #
 function is_pool_resilvering #pool <verbose>
 {
@@ -2105,6 +2183,37 @@ function is_pool_scrub_paused #pool <verbose>
        return $?
 }
 
+function is_pool_removing #pool
+{
+       check_pool_status "$1" "remove" "in progress since "
+       return $?
+}
+
+function is_pool_removed #pool
+{
+       check_pool_status "$1" "remove" "completed on"
+       return $?
+}
+
+function wait_for_degraded
+{
+       typeset pool=$1
+       typeset timeout=${2:-30}
+       typeset t0=$SECONDS
+
+       while :; do
+               [[ $(get_pool_prop health $pool) == "DEGRADED" ]] && break
+               log_note "$pool is not yet degraded."
+               sleep 1
+               if ((SECONDS - t0 > $timeout)); then
+                       log_note "$pool not degraded after $timeout seconds."
+                       return 1
+               fi
+       done
+
+       return 0
+}
+
 #
 # Use create_pool()/destroy_pool() to clean up the information in
 # in the given disk to avoid slice overlapping.
@@ -2485,7 +2594,6 @@ function verify_opt_p_ops
                                        "when ops is $ops."
                        fi
                        log_must datasetexists $dataset
-                       log_mustnot snapexists $dataset
                        ;;
                *)
                        log_fail "$ops is not supported."
@@ -2910,7 +3018,7 @@ function user_run
        shift
 
        log_note "user:$user $@"
-       eval su - \$user -c \"$@\" > /tmp/out 2>/tmp/err
+       eval su - \$user -c \"$@\" > $TEST_BASE_DIR/out 2>$TEST_BASE_DIR/err
        return $?
 }
 
@@ -2935,8 +3043,11 @@ function vdevs_in_pool
 
        shift
 
+       # We could use 'zpool list' to only get the vdevs of the pool but we
+       # can't reference a mirror/raidz vdev using its ID (i.e mirror-0),
+       # therefore we use the 'zpool status' output.
        typeset tmpfile=$(mktemp)
-       zpool list -Hv "$pool" >$tmpfile
+       zpool status -v "$pool" | grep -A 1000 "config:" >$tmpfile
        for vdev in $@; do
                grep -w ${vdev##*/} $tmpfile >/dev/null 2>&1
                [[ $? -ne 0 ]] && return 1
@@ -3099,14 +3210,25 @@ function wait_replacing #pool
 function wait_scrubbed
 {
        typeset pool=${1:-$TESTPOOL}
-       typeset iter=${2:-10}
-       for i in {1..$iter} ; do
-               if is_pool_scrubbed $pool ; then
-                       return 0
-               fi
-               sleep 1
+       while true ; do
+               is_pool_scrubbed $pool && break
+               log_must sleep 1
        done
-       return 1
+}
+
+# Backup the zed.rc in our test directory so that we can edit it for our test.
+#
+# Returns: Backup file name.  You will need to pass this to zed_rc_restore().
+function zed_rc_backup
+{
+       zedrc_backup="$(mktemp)"
+       cp $ZEDLET_DIR/zed.rc $zedrc_backup
+       echo $zedrc_backup
+}
+
+function zed_rc_restore
+{
+       mv $1 $ZEDLET_DIR/zed.rc
 }
 
 #
@@ -3226,7 +3348,7 @@ function zed_stop
 
        log_note "Stopping ZED"
        if [[ -f ${ZEDLET_DIR}/zed.pid ]]; then
-               zedpid=$(cat ${ZEDLET_DIR}/zed.pid)
+               zedpid=$(<${ZEDLET_DIR}/zed.pid)
                kill $zedpid
                while ps -p $zedpid > /dev/null; do
                        sleep 1
@@ -3247,6 +3369,23 @@ function zed_events_drain
        done
 }
 
+# Set a variable in zed.rc to something, un-commenting it in the process.
+#
+# $1 variable
+# $2 value
+function zed_rc_set
+{
+       var="$1"
+       val="$2"
+       # Remove the line
+       cmd="'/$var/d'"
+       eval sed -i $cmd $ZEDLET_DIR/zed.rc
+
+       # Add it at the end
+       echo "$var=$val" >> $ZEDLET_DIR/zed.rc
+}
+
+
 #
 # Check is provided device is being active used as a swap device.
 #
@@ -3382,3 +3521,64 @@ function get_tunable_impl
 
        return 1
 }
+
+#
+# Prints the current time in seconds since UNIX Epoch.
+#
+function current_epoch
+{
+       printf '%(%s)T'
+}
+
+#
+# Get decimal value of global uint32_t variable using mdb.
+#
+function mdb_get_uint32
+{
+       typeset variable=$1
+       typeset value
+
+       value=$(mdb -k -e "$variable/X | ::eval .=U")
+       if [[ $? -ne 0 ]]; then
+               log_fail "Failed to get value of '$variable' from mdb."
+               return 1
+       fi
+
+       echo $value
+       return 0
+}
+
+#
+# Set global uint32_t variable to a decimal value using mdb.
+#
+function mdb_set_uint32
+{
+       typeset variable=$1
+       typeset value=$2
+
+       mdb -kw -e "$variable/W 0t$value" > /dev/null
+       if [[ $? -ne 0 ]]; then
+               echo "Failed to set '$variable' to '$value' in mdb."
+               return 1
+       fi
+
+       return 0
+}
+
+#
+# Set global scalar integer variable to a hex value using mdb.
+# Note: Target should have CTF data loaded.
+#
+function mdb_ctf_set_int
+{
+       typeset variable=$1
+       typeset value=$2
+
+       mdb -kw -e "$variable/z $value" > /dev/null
+       if [[ $? -ne 0 ]]; then
+               echo "Failed to set '$variable' to '$value' in mdb."
+               return 1
+       fi
+
+       return 0
+}