diff options
Diffstat (limited to 'usr/src/test/zfs-tests')
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); +} |