summaryrefslogtreecommitdiff
path: root/usr/src/test/zfs-tests
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/test/zfs-tests')
-rw-r--r--usr/src/test/zfs-tests/cmd/dir_rd_update/dir_rd_update.c5
-rw-r--r--usr/src/test/zfs-tests/runfiles/delphix.run4
-rw-r--r--usr/src/test/zfs-tests/runfiles/omnios.run8
-rw-r--r--usr/src/test/zfs-tests/runfiles/openindiana.run8
-rw-r--r--usr/src/test/zfs-tests/runfiles/smartos.run8
-rw-r--r--usr/src/test/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_features_004_neg.ksh2
-rwxr-xr-xusr/src/test/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_features_005_pos.ksh93
-rw-r--r--usr/src/test/zfs-tests/tests/functional/mdb/mdb_001_pos.ksh38
-rw-r--r--usr/src/test/zfs-tests/tests/functional/resilver/Makefile74
-rwxr-xr-xusr/src/test/zfs-tests/tests/functional/resilver/cleanup.ksh31
-rw-r--r--usr/src/test/zfs-tests/tests/functional/resilver/resilver.cfg32
-rwxr-xr-xusr/src/test/zfs-tests/tests/functional/resilver/resilver_restart_001.ksh196
-rw-r--r--usr/src/test/zfs-tests/tests/functional/resilver/resilver_restart_002.ksh110
-rwxr-xr-xusr/src/test/zfs-tests/tests/functional/resilver/setup.ksh31
-rw-r--r--usr/src/test/zfs-tests/tests/functional/resilver/sysevent.c163
15 files changed, 767 insertions, 36 deletions
diff --git a/usr/src/test/zfs-tests/cmd/dir_rd_update/dir_rd_update.c b/usr/src/test/zfs-tests/cmd/dir_rd_update/dir_rd_update.c
index bca365c524..0283bc9644 100644
--- a/usr/src/test/zfs-tests/cmd/dir_rd_update/dir_rd_update.c
+++ b/usr/src/test/zfs-tests/cmd/dir_rd_update/dir_rd_update.c
@@ -63,6 +63,11 @@ main(int argc, char **argv)
}
cp1 = argv[1];
+ if (strlen(cp1) >= (sizeof (dirpath) - strlen("TMP_DIR"))) {
+ (void) printf("The string length of mount point is "
+ "too large\n");
+ exit(-1);
+ }
(void) strcpy(&dirpath[0], (const char *)cp1);
(void) strcat(&dirpath[strlen(dirpath)], "TMP_DIR");
diff --git a/usr/src/test/zfs-tests/runfiles/delphix.run b/usr/src/test/zfs-tests/runfiles/delphix.run
index 01705fb5f4..f7dc35928e 100644
--- a/usr/src/test/zfs-tests/runfiles/delphix.run
+++ b/usr/src/test/zfs-tests/runfiles/delphix.run
@@ -370,6 +370,10 @@ tests = ['zpool_replace_001_neg', 'zpool_replace_002_neg', 'replace-o_ashift',
tests = ['zpool_resilver_bad_args', 'zpool_resilver_restart']
tags = ['functional', 'cli_root', 'zpool_resilver']
+[/opt/zfs-tests/tests/functional/resilver]
+tests = ['resilver_restart_001']
+tags = ['functional', 'resilver']
+
[/opt/zfs-tests/tests/functional/cli_root/zpool_scrub]
tests = ['zpool_scrub_001_neg', 'zpool_scrub_002_pos', 'zpool_scrub_003_pos',
'zpool_scrub_004_pos', 'zpool_scrub_005_pos', 'zpool_scrub_print_repairing',
diff --git a/usr/src/test/zfs-tests/runfiles/omnios.run b/usr/src/test/zfs-tests/runfiles/omnios.run
index 17107c6efc..4dbfde3fb0 100644
--- a/usr/src/test/zfs-tests/runfiles/omnios.run
+++ b/usr/src/test/zfs-tests/runfiles/omnios.run
@@ -12,7 +12,7 @@
#
# Copyright (c) 2013, 2017 by Delphix. All rights reserved.
# Copyright 2016, OmniTI Computer Consulting, Inc. All rights reserved.
-# Copyright 2019 Joyent, Inc.
+# Copyright 2020 Joyent, Inc.
# Copyright 2019 RackTop Systems.
#
@@ -205,6 +205,10 @@ tests = ['zfs_rename_001_pos', 'zfs_rename_002_pos', 'zfs_rename_003_pos',
[/opt/zfs-tests/tests/functional/cli_root/zfs_reservation]
tests = ['zfs_reservation_001_pos', 'zfs_reservation_002_pos']
+[/opt/zfs-tests/tests/functional/resilver]
+tests = ['resilver_restart_001', 'resilver_restart_002']
+tags = ['functional', 'resilver']
+
[/opt/zfs-tests/tests/functional/cli_root/zfs_rollback]
tests = ['zfs_rollback_001_pos', 'zfs_rollback_002_pos',
'zfs_rollback_003_neg', 'zfs_rollback_004_neg']
@@ -286,7 +290,7 @@ tests = ['zpool_create_001_pos', 'zpool_create_002_pos',
'zpool_create_encrypted', 'zpool_create_crypt_combos',
'zpool_create_features_001_pos', 'zpool_create_features_002_pos',
'zpool_create_features_003_pos', 'zpool_create_features_004_neg',
- 'zpool_create_tempname', 'create-o_ashift']
+ 'zpool_create_features_005_pos', 'zpool_create_tempname', 'create-o_ashift']
[/opt/zfs-tests/tests/functional/cli_root/zpool_destroy]
tests = ['zpool_destroy_001_pos', 'zpool_destroy_002_pos',
diff --git a/usr/src/test/zfs-tests/runfiles/openindiana.run b/usr/src/test/zfs-tests/runfiles/openindiana.run
index 2f12f5de58..21473782c2 100644
--- a/usr/src/test/zfs-tests/runfiles/openindiana.run
+++ b/usr/src/test/zfs-tests/runfiles/openindiana.run
@@ -12,7 +12,7 @@
#
# Copyright (c) 2012, 2017 by Delphix. All rights reserved.
# Copyright 2016, OmniTI Computer Consulting, Inc. All rights reserved.
-# Copyright 2019 Joyent, Inc.
+# Copyright 2020 Joyent, Inc.
# Copyright 2019 RackTop Systems.
#
@@ -205,6 +205,10 @@ tests = ['zfs_rename_001_pos', 'zfs_rename_002_pos', 'zfs_rename_003_pos',
[/opt/zfs-tests/tests/functional/cli_root/zfs_reservation]
tests = ['zfs_reservation_001_pos', 'zfs_reservation_002_pos']
+[/opt/zfs-tests/tests/functional/resilver]
+tests = ['resilver_restart_001', 'resilver_restart_002']
+tags = ['functional', 'resilver']
+
[/opt/zfs-tests/tests/functional/cli_root/zfs_rollback]
tests = ['zfs_rollback_001_pos', 'zfs_rollback_002_pos',
'zfs_rollback_003_neg', 'zfs_rollback_004_neg']
@@ -286,7 +290,7 @@ tests = ['zpool_create_001_pos', 'zpool_create_002_pos',
'zpool_create_encrypted', 'zpool_create_crypt_combos',
'zpool_create_features_001_pos', 'zpool_create_features_002_pos',
'zpool_create_features_003_pos', 'zpool_create_features_004_neg',
- 'zpool_create_tempname', 'create-o_ashift']
+ 'zpool_create_features_005_pos', 'zpool_create_tempname', 'create-o_ashift']
[/opt/zfs-tests/tests/functional/cli_root/zpool_destroy]
tests = ['zpool_destroy_001_pos', 'zpool_destroy_002_pos',
diff --git a/usr/src/test/zfs-tests/runfiles/smartos.run b/usr/src/test/zfs-tests/runfiles/smartos.run
index f8c81e5865..c8d6dc4783 100644
--- a/usr/src/test/zfs-tests/runfiles/smartos.run
+++ b/usr/src/test/zfs-tests/runfiles/smartos.run
@@ -10,7 +10,7 @@
#
#
-# Copyright 2019 Joyent, Inc.
+# Copyright 2020 Joyent, Inc.
#
[DEFAULT]
@@ -164,6 +164,10 @@ tests = ['zfs_rename_001_pos', 'zfs_rename_002_pos', 'zfs_rename_003_pos',
[/opt/zfs-tests/tests/functional/cli_root/zfs_reservation]
tests = ['zfs_reservation_001_pos', 'zfs_reservation_002_pos']
+[/opt/zfs-tests/tests/functional/resilver]
+tests = ['resilver_restart_001', 'resilver_restart_002']
+tags = ['functional', 'resilver']
+
[/opt/zfs-tests/tests/functional/cli_root/zfs_rollback]
tests = ['zfs_rollback_001_pos', 'zfs_rollback_002_pos',
'zfs_rollback_003_neg', 'zfs_rollback_004_neg']
@@ -242,7 +246,7 @@ tests = ['zpool_create_001_pos', 'zpool_create_002_pos',
'zpool_create_encrypted', 'zpool_create_crypt_combos',
'zpool_create_features_001_pos', 'zpool_create_features_002_pos',
'zpool_create_features_003_pos', 'zpool_create_features_004_neg',
- 'zpool_create_tempname', 'create-o_ashift']
+ 'zpool_create_features_005_pos', 'zpool_create_tempname', 'create-o_ashift']
[/opt/zfs-tests/tests/functional/cli_root/zpool_destroy]
tests = ['zpool_destroy_001_pos', 'zpool_destroy_002_pos',
diff --git a/usr/src/test/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_features_004_neg.ksh b/usr/src/test/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_features_004_neg.ksh
index 83886533c4..84af87d613 100644
--- a/usr/src/test/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_features_004_neg.ksh
+++ b/usr/src/test/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_features_004_neg.ksh
@@ -38,7 +38,7 @@
verify_runnable "global"
properties="\
-feature@async_destroy=disabled \
+feature@async_destroy=disable \
feature@async_destroy=active \
feature@xxx_fake_xxx=enabled \
unsupported@some_feature=inactive \
diff --git a/usr/src/test/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_features_005_pos.ksh b/usr/src/test/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_features_005_pos.ksh
new file mode 100755
index 0000000000..a8ed95109f
--- /dev/null
+++ b/usr/src/test/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_features_005_pos.ksh
@@ -0,0 +1,93 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_create/zpool_create.shlib
+
+################################################################################
+#
+# Specifically disabling a feature, all other features should be enabled.
+#
+# 1. Loop through all existing features:
+# a. Create a new pool with '-o feature@XXX=disabled'.
+# b. Verify that every other feature is 'enabled' or 'active'.
+#
+################################################################################
+
+verify_runnable "global"
+
+function cleanup
+{
+ datasetexists $TESTPOOL && log_must zpool destroy $TESTPOOL
+}
+
+function check_features
+{
+ typeset feature="${1}"
+
+ zpool get all ${TESTPOOL} | grep feature@ | while read line; do
+ set -- $(echo "${line}")
+
+ if [[ "feature@${feature}" == "${2}" ]]; then
+ # Failure passed feature must be disabled.
+ if [[ "${3}" != "disabled" ]]; then
+ return 1;
+ fi
+ else
+ # Failure other features must be enabled or active.
+ if [[ "${3}" != "enabled" && "${3}" != "active" ]]; then
+ return 2;
+ fi
+ fi
+ done
+
+ # All features enabled or active except the expected one.
+ return 0
+}
+
+log_onexit cleanup
+
+# Several representative features are tested to keep the test time short.
+# The features 'extensible_dataset' and 'enabled_txg' are intentionally
+# excluded because other features depend on them.
+set -A features \
+ "hole_birth" \
+ "large_blocks" \
+ "large_dnode" \
+ "userobj_accounting"
+
+typeset -i i=0
+while (( $i < ${#features[*]} )); do
+ log_assert "'zpool create' creates pools with ${features[i]} disabled"
+
+ log_must zpool create -f -o "feature@${features[i]}=disabled" \
+ $TESTPOOL $DISKS
+ log_must check_features "${features[i]}"
+ log_must zpool destroy -f $TESTPOOL
+ (( i = i+1 ))
+done
+
+log_pass "'zpool create -o feature@feature=disabled' disables features"
diff --git a/usr/src/test/zfs-tests/tests/functional/mdb/mdb_001_pos.ksh b/usr/src/test/zfs-tests/tests/functional/mdb/mdb_001_pos.ksh
index 7f6faf690e..39180c2a39 100644
--- a/usr/src/test/zfs-tests/tests/functional/mdb/mdb_001_pos.ksh
+++ b/usr/src/test/zfs-tests/tests/functional/mdb/mdb_001_pos.ksh
@@ -26,7 +26,8 @@
#
#
-# Copyright (c) 2013, 2016 by Delphix. All rights reserved.
+# Copyright (c) 2013, 2017 by Delphix. All rights reserved.
+# Copyright 2020 Joyent, Inc.
#
. $STF_SUITE/include/libtest.shlib
@@ -43,7 +44,7 @@
function cleanup
{
- rm -f $OUTFILE
+ rm -f $tmpfile
}
verify_runnable "global"
@@ -60,6 +61,7 @@ typeset bp=$(mdb -ke "$spa + $off_ub + $off_rbp =J")
# dcmds and walkers skipped due to being DEBUG only or difficult to run:
# ::zfs_params
# ::refcount
+# ::walk zms_freelist
set -A dcmds "::abuf_find 1 2" \
"::arc" \
@@ -84,47 +86,25 @@ set -A dcmds "::abuf_find 1 2" \
"$spa ::print -a spa_t spa_uberblock.ub_rootbp | ::blkptr" \
"$spa ::walk metaslab" \
"$spa ::walk metaslab | ::head -1 | ::metaslab_weight" \
- "$spa ::walk metaslab | ::head -1 | ::metaslab_trace" \
+ "*metaslab_alloc_trace_cache::walk kmem | ::metaslab_trace" \
"$spa ::walk zio_root | ::zio -c" \
"$spa ::walk zio_root | ::zio -r" \
- "$spa ::walk zms_freelist"
"$spa ::zfs_blkstats -v" \
"::dbufs" \
"::dbufs -n mos -o mdn -l 0 -b 0" \
"::dbufs | ::dbuf" \
"::dbuf_stats" \
- "dbuf_cache ::walk multilist"
+ "dbuf_caches::print dbuf_cache_t cache | ::walk multilist"
#
# The commands above were supplied by the ZFS development team. The idea is to
# do as much checking as possible without the need to hardcode addresses.
#
-log_assert "Verify that the ZFS mdb dcmds and walkers are working as expected."
+for cmd in ${cmds[@]}; do
+ log_must eval "mdb -ke \"${cmd}\" >$tmpfile 2>&1"
-typeset -i RET=0
-
-i=0
-while (( $i < ${#dcmds[*]} )); do
- log_note "Verifying: '${dcmds[i]}'"
- echo "${dcmds[i]}" | mdb -k > $OUTFILE 2>&1
- RET=$?
- if (( $RET != 0 )); then
- log_fail "mdb '${dcmds[i]}' returned error $RET"
- fi
-
- #
# mdb prefixes all errors with "mdb: " so we check the output.
- #
- grep "mdb:" $OUTFILE > /dev/null 2>&1
- RET=$?
- if (( $RET == 0 )); then
- echo "mdb '${dcmds[i]}' contained 'mdb:'"
- # Using tail limits the number of lines in the log
- tail -100 $OUTFILE
- log_fail "mdb walker or dcmd failed"
- fi
-
- ((i = i + 1))
+ log_mustnot grep -q "mdb:" $tmpfile
done
log_pass "The ZFS mdb dcmds and walkers are working as expected."
diff --git a/usr/src/test/zfs-tests/tests/functional/resilver/Makefile b/usr/src/test/zfs-tests/tests/functional/resilver/Makefile
new file mode 100644
index 0000000000..dd564d19c2
--- /dev/null
+++ b/usr/src/test/zfs-tests/tests/functional/resilver/Makefile
@@ -0,0 +1,74 @@
+#
+# 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 2020 Joyent, Inc.
+#
+
+include $(SRC)/Makefile.master
+
+PROG = sysevent
+
+SCRIPTS = cleanup \
+ resilver_restart_001 \
+ resilver_restart_002 \
+ setup
+
+include $(SRC)/cmd/Makefile.cmd
+include $(SRC)/test/Makefile.com
+
+ROOTOPTPKG = $(ROOT)/opt/zfs-tests
+TARGETDIR = $(ROOTOPTPKG)/tests/functional/resilver
+
+OBJS = $(PROG:%=%.o)
+SRCS = $(OBJS:%.o=%.c)
+SRCFILES = resilver.cfg
+
+CMDS = $(PROG:%=$(TARGETDIR)/%) $(SCRIPTS:%=$(TARGETDIR)/%)
+$(CMDS) := FILEMODE = 0555
+
+FILES = $(SRCFILES:%=$(TARGETDIR)/%)
+$(FILES) := FILEMODE = 0444
+
+CPPFLAGS += -D__EXTENSIONS__
+LDLIBS += -lsysevent
+
+CSTD = $(CSTD_GNU99)
+
+all: $(PROG)
+
+$(PROG): $(OBJS)
+ $(LINK.c) $(OBJS) -o $@ $(LDFLAGS) $(LDLIBS)
+ $(POST_PROCESS)
+
+%.o: %.c
+ $(COMPILE.c) $<
+
+install: all $(CMDS) $(FILES)
+
+clobber: clean
+ -$(RM) $(PROG)
+
+clean:
+ -$(RM) $(OBJS)
+
+$(CMDS): $(TARGETDIR) $(PROG)
+
+$(FILES): $(SRCFILES)
+
+$(TARGETDIR):
+ $(INS.dir)
+
+$(TARGETDIR)/%: %
+ $(INS.file)
+
+$(TARGETDIR)/%: %.ksh
+ $(INS.rename)
diff --git a/usr/src/test/zfs-tests/tests/functional/resilver/cleanup.ksh b/usr/src/test/zfs-tests/tests/functional/resilver/cleanup.ksh
new file mode 100755
index 0000000000..4dfa814245
--- /dev/null
+++ b/usr/src/test/zfs-tests/tests/functional/resilver/cleanup.ksh
@@ -0,0 +1,31 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+
+#
+# Copyright (c) 2019, Datto Inc. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/resilver/resilver.cfg
+
+verify_runnable "global"
+
+log_pass
diff --git a/usr/src/test/zfs-tests/tests/functional/resilver/resilver.cfg b/usr/src/test/zfs-tests/tests/functional/resilver/resilver.cfg
new file mode 100644
index 0000000000..88dfd24aed
--- /dev/null
+++ b/usr/src/test/zfs-tests/tests/functional/resilver/resilver.cfg
@@ -0,0 +1,32 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+
+#
+# Copyright (c) 2019, Datto Inc. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "global"
+
+set -A VDEV_FILES $TEST_BASE_DIR/file-{1..4}
+SPARE_VDEV_FILE=$TEST_BASE_DIR/spare-1
+
+VDEV_FILE_SIZE=$(( $SPA_MINDEVSIZE * 2 ))
diff --git a/usr/src/test/zfs-tests/tests/functional/resilver/resilver_restart_001.ksh b/usr/src/test/zfs-tests/tests/functional/resilver/resilver_restart_001.ksh
new file mode 100755
index 0000000000..6333f4197a
--- /dev/null
+++ b/usr/src/test/zfs-tests/tests/functional/resilver/resilver_restart_001.ksh
@@ -0,0 +1,196 @@
+#!/bin/ksh -p
+
+#
+# CDDL HEADER START
+#
+# 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.
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2019, Datto Inc. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/resilver/resilver.cfg
+
+SYSEVENT=$STF_SUITE/tests/functional/resilver/sysevent
+
+#
+# DESCRIPTION:
+# Testing resilver restart logic both with and without the deferred resilver
+# feature enabled, verifying that resilver is not restarted when it is
+# unecessary.
+#
+# STRATEGY:
+# 1. Create a pool
+# 2. Create four filesystems with the primary cache disable to force reads
+# 3. Write four files simultaneously, one to each filesystem
+# 4. Do with and without deferred resilvers enabled
+# a. Replace a vdev with a spare & suspend resilver immediately
+# b. Verify resilver starts properly
+# c. Offline / online another vdev to introduce a new DTL range
+# d. Verify resilver restart restart or defer
+# e. Inject read errors on vdev that was offlined / onlned
+# f. Verify that resilver did not restart
+# g. Unsuspend resilver and wait for it to finish
+# h. Verify that there are two resilvers and nothing is deferred
+#
+
+function cleanup
+{
+ log_must set_tunable32 zfs_resilver_min_time_ms $ORIG_RESILVER_MIN_TIME
+ log_must set_tunable32 zfs_scan_suspend_progress \
+ $ORIG_SCAN_SUSPEND_PROGRESS
+ log_must zinject -c all
+ destroy_pool $TESTPOOL
+ rm -f ${VDEV_FILES[@]} $SPARE_VDEV_FILE
+ [[ -n "$EVTFILE" ]] && rm -f "$EVTFILE"
+ [[ -n "$EVTPID" ]] && kill "$EVTPID"
+}
+
+# count resilver events in zpool and number of deferred rsilvers on vdevs
+function verify_restarts # <msg> <cnt> <defer>
+{
+ msg=$1
+ cnt=$2
+ defer=$3
+
+ # check the number of resilver start in events log
+ RESILVERS=$(wc -l $EVTFILE | awk '{ print $1 }')
+ log_note "expected $cnt resilver start(s)$msg, found $RESILVERS"
+ [[ "$RESILVERS" -ne "$cnt" ]] &&
+ log_fail "expected $cnt resilver start(s)$msg, found $RESILVERS"
+
+ [[ -z "$defer" ]] && return
+
+ # use zdb to find which vdevs have the resilver defer flag
+ VDEV_DEFERS=$(zdb -C $TESTPOOL | awk '
+ /children/ { gsub(/[^0-9]/, ""); child = $0 }
+ /com\.datto:resilver_defer$/ { print child }
+ ')
+
+ if [[ "$defer" == "-" ]]
+ then
+ [[ -n $VDEV_DEFERS ]] &&
+ log_fail "didn't expect any vdevs to have resilver deferred"
+ return
+ fi
+
+ [[ $VDEV_DEFERS -eq $defer ]] ||
+ log_fail "resilver deferred set on unexpected vdev: $VDEV_DEFERS"
+}
+
+log_assert "Check for unnecessary resilver restarts"
+
+ORIG_RESILVER_MIN_TIME=$(get_tunable zfs_resilver_min_time_ms)
+ORIG_SCAN_SUSPEND_PROGRESS=$(get_tunable zfs_scan_suspend_progress)
+
+set -A RESTARTS -- '1' '2' '2' '2'
+set -A VDEVS -- '' '' '' ''
+set -A DEFER_RESTARTS -- '1' '1' '1' '2'
+set -A DEFER_VDEVS -- '-' '2' '2' '-'
+
+VDEV_REPLACE="${VDEV_FILES[1]} $SPARE_VDEV_FILE"
+
+log_onexit cleanup
+
+# Monitor for resilver start events and log them to $EVTFILE as they occur
+EVTFILE=$(mktemp /tmp/resilver_events.XXXXXX)
+EVTPID=$($SYSEVENT -o $EVTFILE ESC_ZFS_resilver_start)
+log_must test -n "$EVTPID"
+
+log_must truncate -s $VDEV_FILE_SIZE ${VDEV_FILES[@]} $SPARE_VDEV_FILE
+
+log_must zpool create -f -o feature@resilver_defer=disabled $TESTPOOL \
+ raidz ${VDEV_FILES[@]}
+
+# create 4 filesystems
+for fs in fs{0..3}
+do
+ log_must zfs create -o primarycache=none -o recordsize=1k $TESTPOOL/$fs
+done
+
+# simultaneously write 16M to each of them
+set -A DATAPATHS /$TESTPOOL/fs{0..3}/dat.0
+log_note "Writing data files"
+for path in ${DATAPATHS[@]}
+do
+ dd if=/dev/urandom of=$path bs=1M count=16 > /dev/null 2>&1 &
+done
+wait
+
+# test without and with deferred resilve feature enabled
+for test in "without" "with"
+do
+ log_note "Testing $test deferred resilvers"
+
+ if [[ $test == "with" ]]
+ then
+ log_must zpool set feature@resilver_defer=enabled $TESTPOOL
+ RESTARTS=( "${DEFER_RESTARTS[@]}" )
+ VDEVS=( "${DEFER_VDEVS[@]}" )
+ VDEV_REPLACE="$SPARE_VDEV_FILE ${VDEV_FILES[1]}"
+ fi
+
+ # clear the events
+ cp /dev/null $EVTFILE
+
+ # limit scanning time
+ log_must set_tunable32 zfs_resilver_min_time_ms 50
+
+ # initiate a resilver and suspend the scan as soon as possible
+ log_must zpool replace $TESTPOOL $VDEV_REPLACE
+ log_must set_tunable32 zfs_scan_suspend_progress 1
+
+ # there should only be 1 resilver start
+ verify_restarts '' "${RESTARTS[0]}" "${VDEVS[0]}"
+
+ # offline then online a vdev to introduce a new DTL range after current
+ # scan, which should restart (or defer) the resilver
+ log_must zpool offline $TESTPOOL ${VDEV_FILES[2]}
+ log_must zpool sync $TESTPOOL
+ log_must zpool online $TESTPOOL ${VDEV_FILES[2]}
+ log_must zpool sync $TESTPOOL
+
+ # there should now be 2 resilver starts w/o defer, 1 with defer
+ verify_restarts ' after offline/online' "${RESTARTS[1]}" "${VDEVS[1]}"
+
+ # inject read io errors on vdev and verify resilver does not restart
+ log_must zinject -a -d ${VDEV_FILES[2]} -e io -T read -f 0.25 $TESTPOOL
+ log_must cat ${DATAPATHS[1]} > /dev/null
+ log_must zinject -c all
+
+ # there should still be 2 resilver starts w/o defer, 1 with defer
+ verify_restarts ' after zinject' "${RESTARTS[2]}" "${VDEVS[2]}"
+
+ # unsuspend resilver
+ log_must set_tunable32 zfs_scan_suspend_progress 0
+ log_must set_tunable32 zfs_resilver_min_time_ms 3000
+
+ # wait for resilver to finish
+ for iter in {0..59}
+ do
+ is_pool_resilvered $TESTPOOL && break
+ sleep 1
+ done
+ is_pool_resilvered $TESTPOOL ||
+ log_fail "resilver timed out"
+
+ # wait for a few txg's to see if a resilver happens
+ log_must zpool sync $TESTPOOL
+ log_must zpool sync $TESTPOOL
+
+ # there should now be 2 resilver starts
+ verify_restarts ' after resilver' "${RESTARTS[3]}" "${VDEVS[3]}"
+done
+
+log_pass "Resilver did not restart unnecessarily"
diff --git a/usr/src/test/zfs-tests/tests/functional/resilver/resilver_restart_002.ksh b/usr/src/test/zfs-tests/tests/functional/resilver/resilver_restart_002.ksh
new file mode 100644
index 0000000000..da111da9fd
--- /dev/null
+++ b/usr/src/test/zfs-tests/tests/functional/resilver/resilver_restart_002.ksh
@@ -0,0 +1,110 @@
+#!/bin/ksh -p
+
+#
+# CDDL HEADER START
+#
+# 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.
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2020, Datto Inc. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/resilver/resilver.cfg
+
+SYSEVENT=$STF_SUITE/tests/functional/resilver/sysevent
+
+#
+# DESCRIPTION:
+# Testing resilver completes when scan errors are encountered, but relevant
+# DTL's have not been lost.
+#
+# STRATEGY:
+# 1. Create a pool (1k recordsize)
+# 2. Create a 32m file (32k records)
+# 3. Inject an error halfway through the file
+# 4. Start a resilver, ensure the error is triggered and that the resilver
+# does not restart after finishing
+#
+# NB: use legacy scanning to ensure scan of specific block causes error
+#
+
+function cleanup
+{
+ log_must zinject -c all
+ destroy_pool $TESTPOOL
+ rm -f ${VDEV_FILES[@]} $SPARE_VDEV_FILE
+ log_must set_tunable32 zfs_scan_legacy $ORIG_SCAN_LEGACY
+ [[ -n "$EVTPID" ]] && kill "$EVTPID"
+ [[ -n "$EVTFILE" ]] && rm -f "$EVTFILE"
+}
+
+log_assert "Check for resilver restarts caused by scan errors"
+
+ORIG_SCAN_LEGACY=$(get_tunable zfs_scan_legacy)
+
+log_onexit cleanup
+
+# use legacy scan to ensure injected error will be triggered
+log_must set_tunable32 zfs_scan_legacy 1
+
+ # create the pool and a 32M file (32k blocks)
+log_must truncate -s $VDEV_FILE_SIZE ${VDEV_FILES[0]} $SPARE_VDEV_FILE
+log_must zpool create -f -O recordsize=1k $TESTPOOL ${VDEV_FILES[0]}
+log_must dd if=/dev/urandom of=/$TESTPOOL/file bs=1M count=32 > /dev/null 2>&1
+
+# determine objset/object
+objset=$(zdb -d $TESTPOOL/ | sed -ne 's/.*ID \([0-9]*\).*/\1/p')
+object=$(ls -i /$TESTPOOL/file | awk '{print $1}')
+
+# inject event to cause error during resilver
+log_must zinject -b `printf "%x:%x:0:3fff" $objset $object` $TESTPOOL
+
+
+EVTFILE=$(mktemp /tmp/resilver_events.XXXXXX)
+EVTPID=$($SYSEVENT -o $EVTFILE ESC_ZFS_resilver_start ESC_ZFS_resilver_finish)
+log_must test -n "$EVTPID"
+
+# start resilver
+log_must zpool attach $TESTPOOL ${VDEV_FILES[0]} $SPARE_VDEV_FILE
+
+log_note "waiting for read errors to start showing up"
+for iter in {0..59}
+do
+ zpool sync $TESTPOOL
+ err=$(zpool status $TESTPOOL | grep ${VDEV_FILES[0]} | awk '{print $3}')
+ (( $err > 0 )) && break
+ sleep 1
+done
+
+(( $err == 0 )) && log_fail "Unable to induce errors in resilver"
+
+log_note "waiting for resilver to finish"
+for iter in {0..59}
+do
+ finish=$(grep "ESC_ZFS_resilver_finish" $EVTFILE | wc -l)
+ (( $finish > 0 )) && break
+ sleep 1
+done
+
+(( $finish == 0 )) && log_fail "resilver took too long to finish"
+
+# wait a few syncs to ensure that zfs does not restart the resilver
+log_must zpool sync $TESTPOOL
+log_must zpool sync $TESTPOOL
+
+# check if resilver was restarted
+start=$(grep "ESC_ZFS_resilver_start" $EVTFILE | wc -l)
+(( $start != 1 )) && log_fail "resilver restarted unnecessarily"
+
+log_pass "Resilver did not restart unnecessarily from scan errors"
diff --git a/usr/src/test/zfs-tests/tests/functional/resilver/setup.ksh b/usr/src/test/zfs-tests/tests/functional/resilver/setup.ksh
new file mode 100755
index 0000000000..4dfa814245
--- /dev/null
+++ b/usr/src/test/zfs-tests/tests/functional/resilver/setup.ksh
@@ -0,0 +1,31 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+
+#
+# Copyright (c) 2019, Datto Inc. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/resilver/resilver.cfg
+
+verify_runnable "global"
+
+log_pass
diff --git a/usr/src/test/zfs-tests/tests/functional/resilver/sysevent.c b/usr/src/test/zfs-tests/tests/functional/resilver/sysevent.c
new file mode 100644
index 0000000000..62a8b2faa2
--- /dev/null
+++ b/usr/src/test/zfs-tests/tests/functional/resilver/sysevent.c
@@ -0,0 +1,163 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at http://smartos.org/CDDL
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file.
+ *
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * Copyright 2020 Joyent, Inc.
+ *
+ */
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/debug.h>
+#include <sys/sysmacros.h>
+#include <sys/types.h>
+#include <libsysevent.h>
+#include <sys/sysevent/eventdefs.h>
+
+FILE *out;
+
+static void
+process_event(sysevent_t *ev)
+{
+ char *class = NULL;
+ char *subclass = NULL;
+
+ /* get sysevent metadata and add to the nvlist */
+ class = sysevent_get_class_name(ev);
+ subclass = sysevent_get_subclass_name(ev);
+
+ if (class == NULL || subclass == NULL)
+ errx(EXIT_FAILURE, "failed to retrieve sysevent metadata");
+
+ VERIFY0(strcmp(class, EC_ZFS));
+
+ flockfile(out);
+ (void) fprintf(out, "Received %s.%s event\n", class, subclass);
+ (void) fflush(out);
+ funlockfile(out);
+}
+
+static void
+child_fatal(int fd, const char *msg, ...)
+{
+ va_list ap;
+ int fail = EXIT_FAILURE;
+
+ va_start(ap, msg);
+ (void) vfprintf(stderr, msg, ap);
+ va_end(ap);
+ (void) fputc('\n', stderr);
+
+ (void) write(fd, &fail, sizeof (fail));
+ (void) close(fd);
+ exit(EXIT_FAILURE);
+}
+
+static void
+do_child(int fd, char * const subclasses[], size_t n)
+{
+ sysevent_handle_t *handle;
+ int ret = 0;
+
+ if ((handle = sysevent_bind_handle(process_event)) == NULL) {
+ child_fatal(fd, "sysevent_bind_handle() failed: %s",
+ strerror(errno));
+ }
+
+ if (sysevent_subscribe_event(handle, EC_ZFS,
+ (const char **)subclasses, n) != 0) {
+ child_fatal(fd, "failed to subscribe to sysevents: %s",
+ strerror(errno));
+ }
+
+ (void) write(fd, &ret, sizeof (ret));
+ (void) close(fd);
+
+ /* leave stderr open so any errors get captured by test harness */
+ (void) fclose(stdin);
+ (void) fclose(stdout);
+
+ for (;;)
+ (void) pause();
+}
+
+static void
+usage(const char *name)
+{
+ (void) fprintf(stderr, "Usage: %s [-o outfile] zfs_event...\n", name);
+ exit(2);
+}
+
+int
+main(int argc, char * const argv[])
+{
+ const char *outfile = NULL;
+ pid_t child;
+ int fds[2];
+ int ret = 0;
+ int c;
+
+ while ((c = getopt(argc, argv, "o:")) != -1) {
+ switch (c) {
+ case 'o':
+ outfile = optarg;
+ break;
+ case '?':
+ (void) fprintf(stderr, "Invalid option -%c\n", optopt);
+ usage(argv[0]);
+ }
+ }
+
+ if (outfile != NULL) {
+ if ((out = fopen(optarg, "w")) == NULL)
+ err(EXIT_FAILURE, "unable to open %s", optarg);
+ } else {
+ out = stdout;
+ }
+
+ VERIFY0(pipe(fds));
+
+ switch (child = fork()) {
+ case -1:
+ err(EXIT_FAILURE, "unable to fork");
+ case 0:
+ do_child(fds[1], argv + optind, (size_t)(argc - optind));
+ break;
+ default:
+ break;
+ }
+
+ (void) close(fds[1]);
+
+ if (read(fds[0], &ret, sizeof (ret)) < 0)
+ err(EXIT_FAILURE, "failure waiting on child");
+
+ if (ret != 0)
+ return (ret);
+
+ (void) close(fds[0]);
+ (void) printf("%d\n", child);
+ return (0);
+}