1#!/bin/ksh -p
2
3#
4# CDDL HEADER START
5#
6# This file and its contents are supplied under the terms of the
7# Common Development and Distribution License ("CDDL"), version 1.0.
8# You may only use this file in accordance with the terms of version
9# 1.0 of the CDDL.
10#
11# A full copy of the text of the CDDL should have accompanied this
12# source.  A copy of the CDDL is also available via the Internet at
13# http://www.illumos.org/license/CDDL.
14#
15# CDDL HEADER END
16#
17
18#
19# Copyright (c) 2020, Datto Inc. All rights reserved.
20#
21
22. $STF_SUITE/include/libtest.shlib
23. $STF_SUITE/tests/functional/resilver/resilver.cfg
24
25SYSEVENT=$STF_SUITE/tests/functional/resilver/sysevent
26
27#
28# DESCRIPTION:
29# Testing resilver completes when scan errors are encountered, but relevant
30# DTL's have not been lost.
31#
32# STRATEGY:
33# 1. Create a pool (1k recordsize)
34# 2. Create a 32m file (32k records)
35# 3. Inject an error halfway through the file
36# 4. Start a resilver, ensure the error is triggered and that the resilver
37#    does not restart after finishing
38#
39# NB: use legacy scanning to ensure scan of specific block causes error
40#
41
42function cleanup
43{
44	log_must zinject -c all
45	destroy_pool $TESTPOOL
46	rm -f ${VDEV_FILES[@]} $SPARE_VDEV_FILE
47	log_must set_tunable32 zfs_scan_legacy $ORIG_SCAN_LEGACY
48	[[ -n "$EVTPID" ]] && kill "$EVTPID"
49	[[ -n "$EVTFILE" ]] && rm -f "$EVTFILE"
50}
51
52log_assert "Check for resilver restarts caused by scan errors"
53
54ORIG_SCAN_LEGACY=$(get_tunable zfs_scan_legacy)
55
56log_onexit cleanup
57
58# use legacy scan to ensure injected error will be triggered
59log_must set_tunable32 zfs_scan_legacy 1
60
61 # create the pool and a 32M file (32k blocks)
62log_must truncate -s $VDEV_FILE_SIZE ${VDEV_FILES[0]} $SPARE_VDEV_FILE
63log_must zpool create -f -O recordsize=1k $TESTPOOL ${VDEV_FILES[0]}
64log_must dd if=/dev/urandom of=/$TESTPOOL/file bs=1M count=32 > /dev/null 2>&1
65
66# determine objset/object
67objset=$(zdb -d $TESTPOOL/ | sed -ne 's/.*ID \([0-9]*\).*/\1/p')
68object=$(ls -i /$TESTPOOL/file | awk '{print $1}')
69
70# inject event to cause error during resilver
71log_must zinject -b `printf "%x:%x:0:3fff" $objset $object` $TESTPOOL
72
73
74EVTFILE=$(mktemp /tmp/resilver_events.XXXXXX)
75EVTPID=$($SYSEVENT -o $EVTFILE ESC_ZFS_resilver_start ESC_ZFS_resilver_finish)
76log_must test -n "$EVTPID"
77
78# start resilver
79log_must zpool attach $TESTPOOL ${VDEV_FILES[0]} $SPARE_VDEV_FILE
80
81log_note "waiting for read errors to start showing up"
82for iter in {0..59}
83do
84	zpool sync $TESTPOOL
85	err=$(zpool status $TESTPOOL | grep ${VDEV_FILES[0]} | awk '{print $3}')
86	(( $err > 0 )) && break
87	sleep 1
88done
89
90(( $err == 0 )) && log_fail "Unable to induce errors in resilver"
91
92log_note "waiting for resilver to finish"
93for iter in {0..59}
94do
95	finish=$(grep "ESC_ZFS_resilver_finish" $EVTFILE | wc -l)
96	(( $finish > 0 )) && break
97	sleep 1
98done
99
100(( $finish == 0 )) && log_fail "resilver took too long to finish"
101
102# wait a few syncs to ensure that zfs does not restart the resilver
103log_must zpool sync $TESTPOOL
104log_must zpool sync $TESTPOOL
105
106# check if resilver was restarted
107start=$(grep "ESC_ZFS_resilver_start" $EVTFILE | wc -l)
108(( $start != 1 )) && log_fail "resilver restarted unnecessarily"
109
110log_pass "Resilver did not restart unnecessarily from scan errors"
111