--- /dev/null	Mon Aug  5 17:25:37 2019
+++ new/usr/src/test/zfs-tests/tests/functional/wbc/wbc.kshlib	Mon Aug  5 17:25:37 2019
@@ -0,0 +1,591 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2016 Nexenta Systems, Inc. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+function cleanup
+{
+	if poolexists $TESTPOOL ; then
+		destroy_pool $TESTPOOL
+	fi
+
+	if poolexists $TESTPOOL2 ; then
+		destroy_pool $TESTPOOL2
+	fi
+}
+
+function disk_vendor
+{
+	typeset disk=$1
+
+	if $(is_physical_device $disk) ; then
+		echo inquiry | format $disk | nawk  '/Vendor:/{print $NF}'
+	else
+		echo UNKNOWN
+	fi
+}
+
+function disk_model
+{
+	typeset disk=$1
+
+	if $(is_physical_device $disk) ; then
+		echo inquiry | format $disk | nawk  '/Product:/{print $NF}'
+	else
+		echo UNKNOWN
+	fi
+}
+
+function disk_info
+{
+	typeset disk=$1
+	typeset vendor=$(disk_vendor $disk)
+	typeset model=$(disk_model $disk)
+
+	echo "$vendor-$model"
+}
+
+function disk_is_ssd
+{
+	typeset disk=$1
+
+	if $(is_physical_device $disk) ; then
+		if disk_info $disk | egrep -i "$SSD_MODELS" >/dev/null 2>&1 ; then
+			return 0
+		fi
+	fi
+
+	return 1
+}
+
+function set_disks
+{
+	MIN_DSK_COUNT=$(( $MIN_SSD_COUNT + $MIN_HDD_COUNT ))
+	SSD_COUNT=0
+	HDD_COUNT=0
+
+	typeset disk
+	for disk in $DISKS ; do
+		if $(disk_is_ssd $disk) ; then
+			(( SSD_COUNT = SSD_COUNT + 1 ))
+			eval "SSD_DISK$SSD_COUNT=$disk"
+		else
+			(( HDD_COUNT = HDD_COUNT + 1 ))
+			eval "HDD_DISK$HDD_COUNT=$disk"
+		fi
+	done
+
+	# HDD only setup
+	if [[ $SSD_COUNT -lt $MIN_SSD_COUNT && $HDD_COUNT -ge $MIN_DSK_COUNT ]] ; then
+		for SSD_COUNT in {1..$MIN_SSD_COUNT} ; do
+			eval "SSD_DISK$SSD_COUNT=\$HDD_DISK$HDD_COUNT"
+			unset HDD_DISK$HDD_COUNT
+			(( HDD_COUNT = HDD_COUNT - 1 ))
+		done
+	fi
+
+	# SSD only setup
+	if [[ $HDD_COUNT -lt $MIN_HDD_COUNT && $SSD_COUNT -ge $MIN_DSK_COUNT ]] ; then
+		for HDD_COUNT in {1..$MIN_HDD_COUNT} ; do
+			eval "HDD_DISK$HDD_COUNT=\$SSD_DISK$SSD_COUNT"
+			unset SSD_DISK$SSD_COUNT
+			(( SSD_COUNT = SSD_COUNT - 1 ))
+		done
+	fi
+
+	# diskless setup
+	if [[ $HDD_COUNT -lt $MIN_HDD_COUNT || $SSD_COUNT -lt $MIN_SSD_COUNT ]] ; then
+		mkdir -p $VDEV_DIR
+
+		for HDD_COUNT in {1..$MIN_HDD_COUNT} ; do
+			eval "HDD_DISK$HDD_COUNT=\"$VDEV_DIR/hdd$HDD_COUNT\""
+		done
+
+		for SSD_COUNT in {1..$MIN_SSD_COUNT} ; do
+			eval "SSD_DISK$SSD_COUNT=\"$VDEV_DIR/ssd$SSD_COUNT\""
+		done
+	fi
+
+	typeset -i item=0
+
+	for item in {1..$HDD_COUNT} ; do
+		eval "HDD_DISKS=\"$HDD_DISKS \$HDD_DISK$item\""
+		export HDD_DISK$item
+	done
+
+	export HDD_COUNT HDD_DISKS
+
+	for item in {1..$SSD_COUNT} ; do
+		eval "SSD_DISKS=\"$SSD_DISKS \$SSD_DISK$item\""
+		export SSD_DISK$item
+	done
+
+	export SSD_COUNT SSD_DISKS
+}
+
+function test_disks
+{
+	echo "SSD_COUNT=$SSD_COUNT"
+	echo "HDD_COUNT=$HDD_COUNT"
+
+	echo "SSD_DISKS = $SSD_DISKS"
+	echo "HDD_DISKS = $HDD_DISKS"
+}
+
+function create_disks
+{
+	typeset -i ret=0
+	test -d "$VDEV_DIR" || return $ret
+
+	typeset -i item
+	typeset disk
+
+	for item in {1..$HDD_COUNT} ; do
+		eval "disk=\$HDD_DISK$item"
+		echo mkfile $VDEV_SIZE $disk
+		mkfile $VDEV_SIZE $disk
+		((ret |= $?))
+	done
+
+	for item in {1..$SSD_COUNT} ; do
+		eval "disk=\$SSD_DISK$item"
+		echo mkfile $VDEV_SIZE $disk
+		mkfile $VDEV_SIZE $disk
+		((ret |= $?))
+	done
+
+	return $ret
+}
+
+#
+# Enable krrp debug
+#
+function enable_krrp_debug
+{
+	echo krrp_debug/W 1 | mdb -kw
+}
+
+#
+# Disable krrp debug
+#
+function disable_krrp_debug
+{
+	echo krrp_debug/W 0 | mdb -kw
+}
+
+#
+# Try zpool status/iostat for given pool
+#
+# $1 pool
+#
+function display_status
+{
+	typeset pool=$1
+	typeset -i ret=0
+
+	zpool status -xv $pool >/dev/null 2>&1
+	ret=$?
+
+	zpool iostat >/dev/null 2>&1
+	((ret |= $?))
+
+	typeset mntpnt=$(get_prop mountpoint $pool)
+	dd if=/dev/urandom of=$mntpnt/testfile.$$ &
+	typeset pid=$!
+
+	zpool iostat -v 1 60 > /dev/null
+	((ret |= $?))
+
+	kill -9 $pid
+
+	return $ret
+}
+
+function create_dataset # <dataset> [size]
+{
+	typeset dataset_name=$1
+	typeset size=${2:+-V $2}
+
+	if [[ -z $dataset_name ]] ; then
+		log_note "Missing dataset name."
+		return 1
+	fi
+
+	if [[ -d /$dataset_name ]] ; then
+		rm -rf /$dataset_name
+	fi
+
+	zfs create -p $dataset_name $size
+
+	return $?
+}
+
+# Return 0 if create successfully or the pool exists; $? otherwise
+# Note: In local zones, this function should return 0 silently.
+#
+# $1 - pool name:    required
+# $2 - pool_type:    optional
+# $3 - recordsize:   optional
+# $4 - compression:  optional
+
+function create_pool #pool_name
+{
+	typeset pool_name=${1%%/*}
+	typeset pool_type=$2
+	typeset recordsize=$3
+	typeset compression=$4
+
+	if [[ -z $pool_name ]]; then
+		log_note "Missing pool name."
+		return 1
+	fi
+
+	is_global_zone || return 0
+
+	if poolexists $pool_name ; then
+		destroy_pool $pool_name
+	fi
+
+	if [[ -d /$pool_name ]] ; then
+		rm -rf /$pool_name
+	fi
+
+	if [[ -z $pool_type ]] ; then
+		pool_type=$(get_random_pool_type)
+	fi
+
+	if [[ -z $recordsize ]] ; then
+		recordsize=$(get_random_recordsize)
+	fi
+
+	if [[ -z $compression ]] ; then
+		compression=$(get_random_compression)
+	fi
+
+	if [[ $pool_type == "stripe" ]] ; then
+		pool_type=""
+	fi
+
+	zpool create -f \
+		-O compression=$compression \
+		-O recordsize=$recordsize \
+		-o cachefile=none \
+		$pool_name \
+		$pool_type $HDD_DISKS
+
+	return $?
+}
+
+# Return 0 if create successfully or the pool exists; $? otherwise
+# Note: In local zones, this function should return 0 silently.
+#
+# $1 - pool name:    required
+# $2 - wbc_mode:     optional
+# $3 - pool_type:    optional
+# $4 - special_type: optional
+# $5 - recordsize:   optional
+# $6 - compression:  optional
+
+function create_pool_special #pool_name
+{
+	typeset pool_name=${1%%/*}
+	typeset wbc_mode=$2
+	typeset pool_type=$3
+	typeset special_type=$4
+	typeset recordsize=$5
+	typeset compression=$6
+
+	if [[ -z $pool_name ]]; then
+		log_note "Missing pool name."
+		return 1
+	fi
+
+	is_global_zone || return 0
+
+	if poolexists $pool_name ; then
+		destroy_pool $pool_name
+	fi
+
+	if [[ -d /$pool_name ]] ; then
+		rm -rf /$pool_name
+	fi
+
+	if [[ -z $pool_type ]] ; then
+		pool_type=$(get_random_pool_type)
+	fi
+
+	if [[ -z $special_type ]] ; then
+		special_type=$(get_random_special_type)
+	fi
+
+	if [[ -z $recordsize ]] ; then
+		recordsize=$(get_random_recordsize)
+	fi
+
+	if [[ -z $compression ]] ; then
+		compression=$(get_random_compression)
+	fi
+
+	if [[ $wbc_mode == "none" ]] ; then
+		wbc_mode=""
+	fi
+
+	if [[ -n $wbc_mode ]] ; then
+		wbc_mode="-O wbc_mode=$wbc_mode"
+	fi
+
+	if [[ $pool_type == "stripe" ]] ; then
+		pool_type=""
+	fi
+
+	if [[ $special_type == "stripe" ]] ; then
+		special_type=""
+	fi
+
+	zpool create -f \
+		-O compression=$compression \
+		-O recordsize=$recordsize \
+		-o cachefile=none \
+		$wbc_mode \
+		$pool_name \
+		$pool_type $HDD_DISKS \
+		special $special_type $SSD_DISKS
+
+	return $?
+}
+
+function get_random_recordsize
+{
+	random_get "4k" "8k" "16k" "32k" "64k" "128k"
+}
+
+function get_random_compression
+{
+	random_get "off" "on" "lzjb" "gzip" "zle" "lz4"
+}
+
+function get_random_pool_type
+{
+	random_get "stripe" "mirror" "raidz" "raidz2" "raidz3"
+}
+
+function get_random_special_type
+{
+	random_get "stripe" "mirror"
+}
+
+function get_wbc_mode # <dataset>
+{
+	typeset dataset=$1
+
+	if [[ -z $dataset ]] ; then
+		log_note "Missing dataset name."
+		return 1
+	fi
+
+	zfs get -H -o value wbc_mode $dataset
+
+	return $?
+}
+
+function set_wbc_mode # <dataset> <mode>
+{
+	typeset dataset=$1
+	typeset mode=$2
+
+	if [[ -z $dataset ]] ; then
+		log_note "Missing dataset name."
+		return 1
+	fi
+
+	if [[ -z $mode ]] ; then
+		log_note "Missing wbc mode."
+		return 1
+	fi
+
+	zfs set wbc_mode=$mode $dataset
+	value=$(get_wbc_mode $dataset)
+
+	if [[ "$mode" != "$value" ]] ; then
+		return 1
+	fi
+
+	return 0
+}
+
+function enable_wbc # <dataset>
+{
+	typeset dataset=$1
+
+	if [[ -z $dataset ]] ; then
+		log_note "Missing dataset name."
+		return 1
+	fi
+
+	set_wbc_mode $dataset on
+
+	return $?
+}
+
+function disable_wbc # <dataset>
+{
+	typeset dataset=$1
+
+	if [[ -z $dataset ]] ; then
+		log_note "Missing dataset name."
+		return 1
+	fi
+
+	set_wbc_mode $dataset off
+
+	return $?
+}
+
+function check_pool_errors # <pool> [<vdev>]
+{
+	typeset pool=$1
+	shift
+
+	if [[ $# -gt 0 ]] ; then
+		typeset checkvdev=$1
+	else
+		typeset checkvdev=""
+	fi
+
+	typeset -i errnum=0
+	typeset c_read=0
+	typeset c_write=0
+	typeset c_cksum=0
+	typeset tmpfile=/var/tmp/file.$$
+	typeset healthstr="pool '$pool' is healthy"
+	typeset output=$(zpool status -x $pool)
+
+	if [[ "$output" == "$healthstr" ]] ; then
+		return $errnum
+	fi
+
+	zpool status -x $pool | egrep -v "^$" | \
+		egrep -v "special|pool:|state:|config:|errors:" >$tmpfile
+
+	typeset line
+	typeset -i fetchbegin=1
+
+	while read line; do
+		if [[ $fetchbegin -ne 0 ]] ; then
+			echo $line | grep "NAME" >/dev/null 2>&1
+			if [[ $? -eq 0 ]] ; then
+				fetchbegin=0
+				continue
+			fi
+		fi
+
+		if [[ -n $checkvdev ]] ; then
+			echo $line | grep $checkvdev >/dev/null 2>&1
+			if [[ $? -ne 0 ]] ; then
+				continue
+			fi
+
+			c_read=`echo $line | awk '{print $3}'`
+			c_write=`echo $line | awk '{print $4}'`
+			c_cksum=`echo $line | awk '{print $5}'`
+
+			if [[ $c_read != 0 || $c_write != 0 || $c_cksum != 0 ]] ; then
+				(( errnum = errnum + 1 ))
+			fi
+
+			break
+		fi
+
+		c_read=`echo $line | awk '{print $3}'`
+		c_write=`echo $line | awk '{print $4}'`
+		c_cksum=`echo $line | awk '{print $5}'`
+
+		if [[ $c_read != 0 || $c_write != 0 || $c_cksum != 0 ]] ; then
+			(( errnum = errnum + 1 ))
+		fi
+
+	done <$tmpfile
+
+	rm -f $tmpfile
+
+	return $errnum
+}
+
+function get_pool_prop # <property> <pool>
+{
+	typeset property=$1
+	typeset pool=$2
+	typeset value
+
+	if [[ -z $property ]]; then
+		log_fail "The property name is not defined."
+	fi
+
+	if [[ -z $pool ]]; then
+		log_fail "The pool name is not defined."
+	fi
+
+	if ! poolexists $pool; then
+		log_fail "Pool '$pool' does not exist."
+	fi
+
+	value=$(zpool get -H -o value $property $pool)
+
+	if [[ $? != 0 ]]; then
+		log_fail "Unable to get property '$property' for pool '$pool'."
+	fi
+
+	echo $value
+
+	return 0
+}
+
+function set_pool_prop # <property> <value> <pool>
+{
+	typeset property=$1
+	typeset value=$2
+	typeset pool=$3
+	typeset check
+
+	if [[ -z $property ]]; then
+		log_fail "The property name is not defined."
+	fi
+
+	if [[ -z $value ]]; then
+		log_fail "The '$property' property value is not defined."
+	fi
+
+	if [[ -z $pool ]]; then
+		log_fail "The pool name is not defined."
+	fi
+
+	zpool set $property=$value $pool
+
+	if [[ $? != 0 ]]; then
+		log_note "Unable to set '$property' property to" \
+			"'$value' for pool '$pool'."
+		return 1
+	fi
+
+	check=$(get_pool_prop $property $pool)
+
+	if [[ "$check" != "$value" ]]; then
+		log_note "Unexpected '$property' property value:" \
+			"'$check' (expected '$value')."
+		return 1
+	fi
+
+	return 0
+}
