1094e47eGeorge Wilson/*
2094e47eGeorge Wilson * CDDL HEADER START
3094e47eGeorge Wilson *
4094e47eGeorge Wilson * The contents of this file are subject to the terms of the
5094e47eGeorge Wilson * Common Development and Distribution License (the "License").
6094e47eGeorge Wilson * You may not use this file except in compliance with the License.
7094e47eGeorge Wilson *
8094e47eGeorge Wilson * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9094e47eGeorge Wilson * or http://www.opensolaris.org/os/licensing.
10094e47eGeorge Wilson * See the License for the specific language governing permissions
11094e47eGeorge Wilson * and limitations under the License.
12094e47eGeorge Wilson *
13094e47eGeorge Wilson * When distributing Covered Code, include this CDDL HEADER in each
14094e47eGeorge Wilson * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15094e47eGeorge Wilson * If applicable, add the following below this CDDL HEADER, with the
16094e47eGeorge Wilson * fields enclosed by brackets "[]" replaced with your own identifying
17094e47eGeorge Wilson * information: Portions Copyright [yyyy] [name of copyright owner]
18094e47eGeorge Wilson *
19094e47eGeorge Wilson * CDDL HEADER END
20094e47eGeorge Wilson */
21094e47eGeorge Wilson
22094e47eGeorge Wilson/*
23af1d63aPaul Dagnelie * Copyright (c) 2016, 2019 by Delphix. All rights reserved.
24094e47eGeorge Wilson */
25094e47eGeorge Wilson
26094e47eGeorge Wilson#include <sys/spa.h>
27094e47eGeorge Wilson#include <sys/spa_impl.h>
28094e47eGeorge Wilson#include <sys/txg.h>
29094e47eGeorge Wilson#include <sys/vdev_impl.h>
30094e47eGeorge Wilson#include <sys/refcount.h>
31094e47eGeorge Wilson#include <sys/metaslab_impl.h>
32094e47eGeorge Wilson#include <sys/dsl_synctask.h>
33094e47eGeorge Wilson#include <sys/zap.h>
34094e47eGeorge Wilson#include <sys/dmu_tx.h>
35094e47eGeorge Wilson
36094e47eGeorge Wilson/*
37094e47eGeorge Wilson * Value that is written to disk during initialization.
38094e47eGeorge Wilson */
39094e47eGeorge Wilsonuint64_t zfs_initialize_value = 0xdeadbeefdeadbeefULL;
40094e47eGeorge Wilson
41094e47eGeorge Wilson/* maximum number of I/Os outstanding per leaf vdev */
42094e47eGeorge Wilsonint zfs_initialize_limit = 1;
43094e47eGeorge Wilson
44094e47eGeorge Wilson/* size of initializing writes; default 1MiB, see zfs_remove_max_segment */
45094e47eGeorge Wilsonuint64_t zfs_initialize_chunk_size = 1024 * 1024;
46094e47eGeorge Wilson
47094e47eGeorge Wilsonstatic boolean_t
48094e47eGeorge Wilsonvdev_initialize_should_stop(vdev_t *vd)
49094e47eGeorge Wilson{
50094e47eGeorge Wilson	return (vd->vdev_initialize_exit_wanted || !vdev_writeable(vd) ||
51094e47eGeorge Wilson	    vd->vdev_detached || vd->vdev_top->vdev_removing);
52094e47eGeorge Wilson}
53094e47eGeorge Wilson
54094e47eGeorge Wilsonstatic void
55094e47eGeorge Wilsonvdev_initialize_zap_update_sync(void *arg, dmu_tx_t *tx)
56094e47eGeorge Wilson{
57094e47eGeorge Wilson	/*
58094e47eGeorge Wilson	 * We pass in the guid instead of the vdev_t since the vdev may
59094e47eGeorge Wilson	 * have been freed prior to the sync task being processed. This
60094e47eGeorge Wilson	 * happens when a vdev is detached as we call spa_config_vdev_exit(),
61084fd14Brian Behlendorf	 * stop the initializing thread, schedule the sync task, and free
62094e47eGeorge Wilson	 * the vdev. Later when the scheduled sync task is invoked, it would
63094e47eGeorge Wilson	 * find that the vdev has been freed.
64094e47eGeorge Wilson	 */
65094e47eGeorge Wilson	uint64_t guid = *(uint64_t *)arg;
66094e47eGeorge Wilson	uint64_t txg = dmu_tx_get_txg(tx);
67094e47eGeorge Wilson	kmem_free(arg, sizeof (uint64_t));
68094e47eGeorge Wilson
69094e47eGeorge Wilson	vdev_t *vd = spa_lookup_by_guid(tx->tx_pool->dp_spa, guid, B_FALSE);
70094e47eGeorge Wilson	if (vd == NULL || vd->vdev_top->vdev_removing || !vdev_is_concrete(vd))
71094e47eGeorge Wilson		return;
72094e47eGeorge Wilson
73094e47eGeorge Wilson	uint64_t last_offset = vd->vdev_initialize_offset[txg & TXG_MASK];
74094e47eGeorge Wilson	vd->vdev_initialize_offset[txg & TXG_MASK] = 0;
75094e47eGeorge Wilson
76094e47eGeorge Wilson	VERIFY(vd->vdev_leaf_zap != 0);
77094e47eGeorge Wilson
78094e47eGeorge Wilson	objset_t *mos = vd->vdev_spa->spa_meta_objset;
79094e47eGeorge Wilson
80094e47eGeorge Wilson	if (last_offset > 0) {
81094e47eGeorge Wilson		vd->vdev_initialize_last_offset = last_offset;
82094e47eGeorge Wilson		VERIFY0(zap_update(mos, vd->vdev_leaf_zap,
84094e47eGeorge Wilson		    sizeof (last_offset), 1, &last_offset, tx));
85094e47eGeorge Wilson	}
86094e47eGeorge Wilson	if (vd->vdev_initialize_action_time > 0) {
87094e47eGeorge Wilson		uint64_t val = (uint64_t)vd->vdev_initialize_action_time;
88094e47eGeorge Wilson		VERIFY0(zap_update(mos, vd->vdev_leaf_zap,
89094e47eGeorge Wilson		    VDEV_LEAF_ZAP_INITIALIZE_ACTION_TIME, sizeof (val),
90094e47eGeorge Wilson		    1, &val, tx));
91094e47eGeorge Wilson	}
92094e47eGeorge Wilson
93094e47eGeorge Wilson	uint64_t initialize_state = vd->vdev_initialize_state;
94094e47eGeorge Wilson	VERIFY0(zap_update(mos, vd->vdev_leaf_zap,
95094e47eGeorge Wilson	    VDEV_LEAF_ZAP_INITIALIZE_STATE, sizeof (initialize_state), 1,
96094e47eGeorge Wilson	    &initialize_state, tx));
97094e47eGeorge Wilson}
98094e47eGeorge Wilson
99094e47eGeorge Wilsonstatic void
100094e47eGeorge Wilsonvdev_initialize_change_state(vdev_t *vd, vdev_initializing_state_t new_state)
101094e47eGeorge Wilson{
102094e47eGeorge Wilson	ASSERT(MUTEX_HELD(&vd->vdev_initialize_lock));
103094e47eGeorge Wilson	spa_t *spa = vd->vdev_spa;
104094e47eGeorge Wilson
105094e47eGeorge Wilson	if (new_state == vd->vdev_initialize_state)
106094e47eGeorge Wilson		return;
107094e47eGeorge Wilson
108094e47eGeorge Wilson	/*
109094e47eGeorge Wilson	 * Copy the vd's guid, this will be freed by the sync task.
110094e47eGeorge Wilson	 */
111094e47eGeorge Wilson	uint64_t *guid = kmem_zalloc(sizeof (uint64_t), KM_SLEEP);
112094e47eGeorge Wilson	*guid = vd->vdev_guid;
113094e47eGeorge Wilson
114094e47eGeorge Wilson	/*
115094e47eGeorge Wilson	 * If we're suspending, then preserving the original start time.
116094e47eGeorge Wilson	 */
117094e47eGeorge Wilson	if (vd->vdev_initialize_state != VDEV_INITIALIZE_SUSPENDED) {
118094e47eGeorge Wilson		vd->vdev_initialize_action_time = gethrestime_sec();
119094e47eGeorge Wilson	}
120094e47eGeorge Wilson	vd->vdev_initialize_state = new_state;
121094e47eGeorge Wilson
122094e47eGeorge Wilson	dmu_tx_t *tx = dmu_tx_create_dd(spa_get_dsl(spa)->dp_mos_dir);
123094e47eGeorge Wilson	VERIFY0(dmu_tx_assign(tx, TXG_WAIT));
124094e47eGeorge Wilson	dsl_sync_task_nowait(spa_get_dsl(spa), vdev_initialize_zap_update_sync,
125084fd14Brian Behlendorf	    guid, 2, ZFS_SPACE_CHECK_NONE, tx);
126094e47eGeorge Wilson
127094e47eGeorge Wilson	switch (new_state) {
128094e47eGeorge Wilson	case VDEV_INITIALIZE_ACTIVE:
129094e47eGeorge Wilson		spa_history_log_internal(spa, "initialize", tx,
130094e47eGeorge Wilson		    "vdev=%s activated", vd->vdev_path);
131094e47eGeorge Wilson		break;
132094e47eGeorge Wilson	case VDEV_INITIALIZE_SUSPENDED:
133094e47eGeorge Wilson		spa_history_log_internal(spa, "initialize", tx,
134094e47eGeorge Wilson		    "vdev=%s suspended", vd->vdev_path);
135094e47eGeorge Wilson		break;
136094e47eGeorge Wilson	case VDEV_INITIALIZE_CANCELED:
137094e47eGeorge Wilson		spa_history_log_internal(spa, "initialize", tx,
138094e47eGeorge Wilson		    "vdev=%s canceled", vd->vdev_path);
139094e47eGeorge Wilson		break;
140094e47eGeorge Wilson	case VDEV_INITIALIZE_COMPLETE:
141094e47eGeorge Wilson		spa_history_log_internal(spa, "initialize", tx,
142094e47eGeorge Wilson		    "vdev=%s complete", vd->vdev_path);
143094e47eGeorge Wilson		break;
144094e47eGeorge Wilson	default:
145094e47eGeorge Wilson		panic("invalid state %llu", (unsigned long long)new_state);
146094e47eGeorge Wilson	}
147094e47eGeorge Wilson
148094e47eGeorge Wilson	dmu_tx_commit(tx);
149094e47eGeorge Wilson}
150094e47eGeorge Wilson
151094e47eGeorge Wilsonstatic void
152094e47eGeorge Wilsonvdev_initialize_cb(zio_t *zio)
153094e47eGeorge Wilson{
154094e47eGeorge Wilson	vdev_t *vd = zio->io_vd;
155094e47eGeorge Wilson	mutex_enter(&vd->vdev_initialize_io_lock);
156094e47eGeorge Wilson	if (zio->io_error == ENXIO && !vdev_writeable(vd)) {
157094e47eGeorge Wilson		/*
158094e47eGeorge Wilson		 * The I/O failed because the vdev was unavailable; roll the
159094e47eGeorge Wilson		 * last offset back. (This works because spa_sync waits on
160094e47eGeorge Wilson		 * spa_txg_zio before it runs sync tasks.)
161094e47eGeorge Wilson		 */
162094e47eGeorge Wilson		uint64_t *off =
163094e47eGeorge Wilson		    &vd->vdev_initialize_offset[zio->io_txg & TXG_MASK];
164094e47eGeorge Wilson		*off = MIN(*off, zio->io_offset);
165094e47eGeorge Wilson	} else {
166094e47eGeorge Wilson		/*
167094e47eGeorge Wilson		 * Since initializing is best-effort, we ignore I/O errors and
168094e47eGeorge Wilson		 * rely on vdev_probe to determine if the errors are more
169094e47eGeorge Wilson		 * critical.
170094e47eGeorge Wilson		 */
171094e47eGeorge Wilson		if (zio->io_error != 0)
172094e47eGeorge Wilson			vd->vdev_stat.vs_initialize_errors++;
173094e47eGeorge Wilson
174094e47eGeorge Wilson		vd->vdev_initialize_bytes_done += zio->io_orig_size;
175094e47eGeorge Wilson	}
176094e47eGeorge Wilson	ASSERT3U(vd->vdev_initialize_inflight, >, 0);
177094e47eGeorge Wilson	vd->vdev_initialize_inflight--;
178094e47eGeorge Wilson	cv_broadcast(&vd->vdev_initialize_io_cv);
179094e47eGeorge Wilson	mutex_exit(&vd->vdev_initialize_io_lock);
180094e47eGeorge Wilson
181094e47eGeorge Wilson	spa_config_exit(vd->vdev_spa, SCL_STATE_ALL, vd);
182094e47eGeorge Wilson}
183094e47eGeorge Wilson
184094e47eGeorge Wilson/* Takes care of physical writing and limiting # of concurrent ZIOs. */
185094e47eGeorge Wilsonstatic int
186094e47eGeorge Wilsonvdev_initialize_write(vdev_t *vd, uint64_t start, uint64_t size, abd_t *data)
187094e47eGeorge Wilson{
188094e47eGeorge Wilson	spa_t *spa = vd->vdev_spa;
189094e47eGeorge Wilson
190094e47eGeorge Wilson	/* Limit inflight initializing I/Os */
191094e47eGeorge Wilson	mutex_enter(&vd->vdev_initialize_io_lock);
192094e47eGeorge Wilson	while (vd->vdev_initialize_inflight >= zfs_initialize_limit) {
193094e47eGeorge Wilson		cv_wait(&vd->vdev_initialize_io_cv,
194094e47eGeorge Wilson		    &vd->vdev_initialize_io_lock);
195094e47eGeorge Wilson	}
196094e47eGeorge Wilson	vd->vdev_initialize_inflight++;
197094e47eGeorge Wilson	mutex_exit(&vd->vdev_initialize_io_lock);
198094e47eGeorge Wilson
199094e47eGeorge Wilson	dmu_tx_t *tx = dmu_tx_create_dd(spa_get_dsl(spa)->dp_mos_dir);
200094e47eGeorge Wilson	VERIFY0(dmu_tx_assign(tx, TXG_WAIT));
201094e47eGeorge Wilson	uint64_t txg = dmu_tx_get_txg(tx);
202094e47eGeorge Wilson
203094e47eGeorge Wilson	spa_config_enter(spa, SCL_STATE_ALL, vd, RW_READER);
204094e47eGeorge Wilson	mutex_enter(&vd->vdev_initialize_lock);
205094e47eGeorge Wilson
206094e47eGeorge Wilson	if (vd->vdev_initialize_offset[txg & TXG_MASK] == 0) {
207094e47eGeorge Wilson		uint64_t *guid = kmem_zalloc(sizeof (uint64_t), KM_SLEEP);
208094e47eGeorge Wilson		*guid = vd->vdev_guid;
209094e47eGeorge Wilson
210094e47eGeorge Wilson		/* This is the first write of this txg. */
211094e47eGeorge Wilson		dsl_sync_task_nowait(spa_get_dsl(spa),
212094e47eGeorge Wilson		    vdev_initialize_zap_update_sync, guid, 2,
213094e47eGeorge Wilson		    ZFS_SPACE_CHECK_RESERVED, tx);
214094e47eGeorge Wilson	}
215094e47eGeorge Wilson
216094e47eGeorge Wilson	/*
217094e47eGeorge Wilson	 * We know the vdev struct will still be around since all
218094e47eGeorge Wilson	 * consumers of vdev_free must stop the initialization first.
219094e47eGeorge Wilson	 */
220094e47eGeorge Wilson	if (vdev_initialize_should_stop(vd)) {
221094e47eGeorge Wilson		mutex_enter(&vd->vdev_initialize_io_lock);
222094e47eGeorge Wilson		ASSERT3U(vd->vdev_initialize_inflight, >, 0);
223094e47eGeorge Wilson		vd->vdev_initialize_inflight--;
224094e47eGeorge Wilson		mutex_exit(&vd->vdev_initialize_io_lock);
225094e47eGeorge Wilson		spa_config_exit(vd->vdev_spa, SCL_STATE_ALL, vd);
226094e47eGeorge Wilson		mutex_exit(&vd->vdev_initialize_lock);
227094e47eGeorge Wilson		dmu_tx_commit(tx);
228094e47eGeorge Wilson		return (SET_ERROR(EINTR));
229094e47eGeorge Wilson	}
230094e47eGeorge Wilson	mutex_exit(&vd->vdev_initialize_lock);
231094e47eGeorge Wilson
232094e47eGeorge Wilson	vd->vdev_initialize_offset[txg & TXG_MASK] = start + size;
233094e47eGeorge Wilson	zio_nowait(zio_write_phys(spa->spa_txg_zio[txg & TXG_MASK], vd, start,
234094e47eGeorge Wilson	    size, data, ZIO_CHECKSUM_OFF, vdev_initialize_cb, NULL,
236094e47eGeorge Wilson	/* vdev_initialize_cb releases SCL_STATE_ALL */
237094e47eGeorge Wilson
238094e47eGeorge Wilson	dmu_tx_commit(tx);
239094e47eGeorge Wilson
240094e47eGeorge Wilson	return (0);
241094e47eGeorge Wilson}
242094e47eGeorge Wilson
243094e47eGeorge Wilson/*
244094e47eGeorge Wilson * Callback to fill each ABD chunk with zfs_initialize_value. len must be
245094e47eGeorge Wilson * divisible by sizeof (uint64_t), and buf must be 8-byte aligned. The ABD
246094e47eGeorge Wilson * allocation will guarantee these for us.
247094e47eGeorge Wilson */
248094e47eGeorge Wilson/* ARGSUSED */
249094e47eGeorge Wilsonstatic int
250094e47eGeorge Wilsonvdev_initialize_block_fill(void *buf, size_t len, void *unused)
251094e47eGeorge Wilson{
252094e47eGeorge Wilson	ASSERT0(len % sizeof (uint64_t));
253094e47eGeorge Wilson	for (uint64_t i = 0; i < len; i += sizeof (uint64_t)) {
254094e47eGeorge Wilson		*(uint64_t *)((char *)(buf) + i) = zfs_initialize_value;
255094e47eGeorge Wilson	}
256094e47eGeorge Wilson	return (0);
257094e47eGeorge Wilson}
258094e47eGeorge Wilson
259094e47eGeorge Wilsonstatic abd_t *
260094e47eGeorge Wilsonvdev_initialize_block_alloc()
261094e47eGeorge Wilson{
262094e47eGeorge Wilson	/* Allocate ABD for filler data */
263094e47eGeorge Wilson	abd_t *data = abd_alloc_for_io(zfs_initialize_chunk_size, B_FALSE);
264094e47eGeorge Wilson
265094e47eGeorge Wilson	ASSERT0(zfs_initialize_chunk_size % sizeof (uint64_t));
266094e47eGeorge Wilson	(void) abd_iterate_func(data, 0, zfs_initialize_chunk_size,
267094e47eGeorge Wilson	    vdev_initialize_block_fill, NULL);
268094e47eGeorge Wilson
269094e47eGeorge Wilson	return (data);
270094e47eGeorge Wilson}
271094e47eGeorge Wilson
272094e47eGeorge Wilsonstatic void
273094e47eGeorge Wilsonvdev_initialize_block_free(abd_t *data)
274094e47eGeorge Wilson{
275094e47eGeorge Wilson	abd_free(data);
276094e47eGeorge Wilson}
277094e47eGeorge Wilson
278094e47eGeorge Wilsonstatic int
279094e47eGeorge Wilsonvdev_initialize_ranges(vdev_t *vd, abd_t *data)
280094e47eGeorge Wilson{
2814d7988dPaul Dagnelie	range_tree_t *rt = vd->vdev_initialize_tree;
2824d7988dPaul Dagnelie	zfs_btree_t *bt = &rt->rt_root;
2834d7988dPaul Dagnelie	zfs_btree_index_t where;
284094e47eGeorge Wilson
2854d7988dPaul Dagnelie	for (range_seg_t *rs = zfs_btree_first(bt, &where); rs != NULL;
2864d7988dPaul Dagnelie	    rs = zfs_btree_next(bt, &where, &where)) {
2874d7988dPaul Dagnelie		uint64_t size = rs_get_end(rs, rt) - rs_get_start(rs, rt);
288094e47eGeorge Wilson
289094e47eGeorge Wilson		/* Split range into legally-sized physical chunks */
290094e47eGeorge Wilson		uint64_t writes_required =
291094e47eGeorge Wilson		    ((size - 1) / zfs_initialize_chunk_size) + 1;
292094e47eGeorge Wilson
293094e47eGeorge Wilson		for (uint64_t w = 0; w < writes_required; w++) {
294094e47eGeorge Wilson			int error;
295094e47eGeorge Wilson
296094e47eGeorge Wilson			error = vdev_initialize_write(vd,
2974d7988dPaul Dagnelie			    VDEV_LABEL_START_SIZE + rs_get_start(rs, rt) +
298094e47eGeorge Wilson			    (w * zfs_initialize_chunk_size),
299094e47eGeorge Wilson			    MIN(size - (w * zfs_initialize_chunk_size),
300094e47eGeorge Wilson			    zfs_initialize_chunk_size), data);
301094e47eGeorge Wilson			if (error != 0)
302094e47eGeorge Wilson				return (error);
303094e47eGeorge Wilson		}
304094e47eGeorge Wilson	}
305094e47eGeorge Wilson	return (0);
306094e47eGeorge Wilson}
307094e47eGeorge Wilson
308094e47eGeorge Wilsonstatic void
309094e47eGeorge Wilsonvdev_initialize_calculate_progress(vdev_t *vd)
310094e47eGeorge Wilson{
311094e47eGeorge Wilson	ASSERT(spa_config_held(vd->vdev_spa, SCL_CONFIG, RW_READER) ||
312094e47eGeorge Wilson	    spa_config_held(vd->vdev_spa, SCL_CONFIG, RW_WRITER));
313094e47eGeorge Wilson	ASSERT(vd->vdev_leaf_zap != 0);
314094e47eGeorge Wilson
315094e47eGeorge Wilson	vd->vdev_initialize_bytes_est = 0;
316094e47eGeorge Wilson	vd->vdev_initialize_bytes_done = 0;
317094e47eGeorge Wilson
318094e47eGeorge Wilson	for (uint64_t i = 0; i < vd->vdev_top->vdev_ms_count; i++) {
319094e47eGeorge Wilson		metaslab_t *msp = vd->vdev_top->vdev_ms[i];
320094e47eGeorge Wilson		mutex_enter(&msp->ms_lock);
321094e47eGeorge Wilson
322094e47eGeorge Wilson		uint64_t ms_free = msp->ms_size -
323555d674Serapheim Dimitropoulos		    metaslab_allocated_space(msp);
324094e47eGeorge Wilson
325094e47eGeorge Wilson		if (vd->vdev_top->vdev_ops == &vdev_raidz_ops)
326094e47eGeorge Wilson			ms_free /= vd->vdev_top->vdev_children;
327094e47eGeorge Wilson
328094e47eGeorge Wilson		/*
329094e47eGeorge Wilson		 * Convert the metaslab range to a physical range
330094e47eGeorge Wilson		 * on our vdev. We use this to determine if we are
331094e47eGeorge Wilson		 * in the middle of this metaslab range.
332094e47eGeorge Wilson		 */
3334d7988dPaul Dagnelie		range_seg64_t logical_rs, physical_rs;
334094e47eGeorge Wilson		logical_rs.rs_start = msp->ms_start;
335094e47eGeorge Wilson		logical_rs.rs_end = msp->ms_start + msp->ms_size;
336094e47eGeorge Wilson		vdev_xlate(vd, &logical_rs, &physical_rs);
337094e47eGeorge Wilson
338094e47eGeorge Wilson		if (vd->vdev_initialize_last_offset <= physical_rs.rs_start) {
339094e47eGeorge Wilson			vd->vdev_initialize_bytes_est += ms_free;
340094e47eGeorge Wilson			mutex_exit(&msp->ms_lock);
341094e47eGeorge Wilson			continue;
342094e47eGeorge Wilson		} else if (vd->vdev_initialize_last_offset >
343094e47eGeorge Wilson		    physical_rs.rs_end) {
344094e47eGeorge Wilson			vd->vdev_initialize_bytes_done += ms_free;
345094e47eGeorge Wilson			vd->vdev_initialize_bytes_est += ms_free;
346094e47eGeorge Wilson			mutex_exit(&msp->ms_lock);
347094e47eGeorge Wilson			continue;
348094e47eGeorge Wilson		}
349094e47eGeorge Wilson
350094e47eGeorge Wilson		/*
351094e47eGeorge Wilson		 * If we get here, we're in the middle of initializing this
352094e47eGeorge Wilson		 * metaslab. Load it and walk the free tree for more accurate
353094e47eGeorge Wilson		 * progress estimation.
354094e47eGeorge Wilson		 */
355a0b03b1Serapheim Dimitropoulos		VERIFY0(metaslab_load(msp));
356094e47eGeorge Wilson
3574d7988dPaul Dagnelie		zfs_btree_index_t where;
3584d7988dPaul Dagnelie		range_tree_t *rt = msp->ms_allocatable;
3594d7988dPaul Dagnelie		for (range_seg_t *rs =
3604d7988dPaul Dagnelie		    zfs_btree_first(&rt->rt_root, &where); rs;
3614d7988dPaul Dagnelie		    rs = zfs_btree_next(&rt->rt_root, &where,
3624d7988dPaul Dagnelie		    &where)) {
3634d7988dPaul Dagnelie			logical_rs.rs_start = rs_get_start(rs, rt);
3644d7988dPaul Dagnelie			logical_rs.rs_end = rs_get_end(rs, rt);
365094e47eGeorge Wilson			vdev_xlate(vd, &logical_rs, &physical_rs);
366094e47eGeorge Wilson
367094e47eGeorge Wilson			uint64_t size = physical_rs.rs_end -
368094e47eGeorge Wilson			    physical_rs.rs_start;
369094e47eGeorge Wilson			vd->vdev_initialize_bytes_est += size;
370094e47eGeorge Wilson			if (vd->vdev_initialize_last_offset >
371094e47eGeorge Wilson			    physical_rs.rs_end) {
372094e47eGeorge Wilson				vd->vdev_initialize_bytes_done += size;
373094e47eGeorge Wilson			} else if (vd->vdev_initialize_last_offset >
374094e47eGeorge Wilson			    physical_rs.rs_start &&
375094e47eGeorge Wilson			    vd->vdev_initialize_last_offset <
376094e47eGeorge Wilson			    physical_rs.rs_end) {
377094e47eGeorge Wilson				vd->vdev_initialize_bytes_done +=
378094e47eGeorge Wilson				    vd->vdev_initialize_last_offset -
379094e47eGeorge Wilson				    physical_rs.rs_start;
380094e47eGeorge Wilson			}
381094e47eGeorge Wilson		}
382094e47eGeorge Wilson		mutex_exit(&msp->ms_lock);
383094e47eGeorge Wilson	}
384094e47eGeorge Wilson}
385094e47eGeorge Wilson
386084fd14Brian Behlendorfstatic int
387094e47eGeorge Wilsonvdev_initialize_load(vdev_t *vd)
388094e47eGeorge Wilson{
389084fd14Brian Behlendorf	int err = 0;
390094e47eGeorge Wilson	ASSERT(spa_config_held(vd->vdev_spa, SCL_CONFIG, RW_READER) ||
391094e47eGeorge Wilson	    spa_config_held(vd->vdev_spa, SCL_CONFIG, RW_WRITER));
392094e47eGeorge Wilson	ASSERT(vd->vdev_leaf_zap != 0);
393094e47eGeorge Wilson
394094e47eGeorge Wilson	if (vd->vdev_initialize_state == VDEV_INITIALIZE_ACTIVE ||
395094e47eGeorge Wilson	    vd->vdev_initialize_state == VDEV_INITIALIZE_SUSPENDED) {
396084fd14Brian Behlendorf		err = zap_lookup(vd->vdev_spa->spa_meta_objset,
397094e47eGeorge Wilson		    vd->vdev_leaf_zap, VDEV_LEAF_ZAP_INITIALIZE_LAST_OFFSET,
398094e47eGeorge Wilson		    sizeof (vd->vdev_initialize_last_offset), 1,
399094e47eGeorge Wilson		    &vd->vdev_initialize_last_offset);
400084fd14Brian Behlendorf		if (err == ENOENT) {
401084fd14Brian Behlendorf			vd->vdev_initialize_last_offset = 0;
402084fd14Brian Behlendorf			err = 0;
403084fd14Brian Behlendorf		}
404094e47eGeorge Wilson	}
405094e47eGeorge Wilson
406094e47eGeorge Wilson	vdev_initialize_calculate_progress(vd);
407084fd14Brian Behlendorf	return (err);
408094e47eGeorge Wilson}
409094e47eGeorge Wilson
410094e47eGeorge Wilson
411094e47eGeorge Wilson/*
412084fd14Brian Behlendorf * Convert the logical range into a physical range and add it to our
413094e47eGeorge Wilson * avl tree.
414094e47eGeorge Wilson */
415094e47eGeorge Wilsonvoid
416094e47eGeorge Wilsonvdev_initialize_range_add(void *arg, uint64_t start, uint64_t size)
417094e47eGeorge Wilson{
418094e47eGeorge Wilson	vdev_t *vd = arg;
4194d7988dPaul Dagnelie	range_seg64_t logical_rs, physical_rs;
420094e47eGeorge Wilson	logical_rs.rs_start = start;
421094e47eGeorge Wilson	logical_rs.rs_end = start + size;
422094e47eGeorge Wilson
423094e47eGeorge Wilson	ASSERT(vd->vdev_ops->vdev_op_leaf);
424094e47eGeorge Wilson	vdev_xlate(vd, &logical_rs, &physical_rs);
425094e47eGeorge Wilson
426094e47eGeorge Wilson	IMPLY(vd->vdev_top == vd,
427094e47eGeorge Wilson	    logical_rs.rs_start == physical_rs.rs_start);
428094e47eGeorge Wilson	IMPLY(vd->vdev_top == vd,
429094e47eGeorge Wilson	    logical_rs.rs_end == physical_rs.rs_end);
430094e47eGeorge Wilson
431094e47eGeorge Wilson	/* Only add segments that we have not visited yet */
432094e47eGeorge Wilson	if (physical_rs.rs_end <= vd->vdev_initialize_last_offset)
433094e47eGeorge Wilson		return;
434094e47eGeorge Wilson
435094e47eGeorge Wilson	/* Pick up where we left off mid-range. */
436094e47eGeorge Wilson	if (vd->vdev_initialize_last_offset > physical_rs.rs_start) {
437094e47eGeorge Wilson		zfs_dbgmsg("range write: vd %s changed (%llu, %llu) to "
438094e47eGeorge Wilson		    "(%llu, %llu)", vd->vdev_path,
439094e47eGeorge Wilson		    (u_longlong_t)physical_rs.rs_start,
440094e47eGeorge Wilson		    (u_longlong_t)physical_rs.rs_end,
441094e47eGeorge Wilson		    (u_longlong_t)vd->vdev_initialize_last_offset,
442094e47eGeorge Wilson		    (u_longlong_t)physical_rs.rs_end);
443094e47eGeorge Wilson		ASSERT3U(physical_rs.rs_end, >,
444094e47eGeorge Wilson		    vd->vdev_initialize_last_offset);
445094e47eGeorge Wilson		physical_rs.rs_start = vd->vdev_initialize_last_offset;
446094e47eGeorge Wilson	}
447094e47eGeorge Wilson	ASSERT3U(physical_rs.rs_end, >=, physical_rs.rs_start);
448094e47eGeorge Wilson
449094e47eGeorge Wilson	/*
450094e47eGeorge Wilson	 * With raidz, it's possible that the logical range does not live on
451094e47eGeorge Wilson	 * this leaf vdev. We only add the physical range to this vdev's if it
452094e47eGeorge Wilson	 * has a length greater than 0.
453094e47eGeorge Wilson	 */
454094e47eGeorge Wilson	if (physical_rs.rs_end > physical_rs.rs_start) {
455094e47eGeorge Wilson		range_tree_add(vd->vdev_initialize_tree, physical_rs.rs_start,
456094e47eGeorge Wilson		    physical_rs.rs_end - physical_rs.rs_start);
457094e47eGeorge Wilson	} else {
458094e47eGeorge Wilson		ASSERT3U(physical_rs.rs_end, ==, physical_rs.rs_start);
459094e47eGeorge Wilson	}
460094e47eGeorge Wilson}
461094e47eGeorge Wilson
462094e47eGeorge Wilsonstatic void
463094e47eGeorge Wilsonvdev_initialize_thread(void *arg)
464094e47eGeorge Wilson{
465094e47eGeorge Wilson	vdev_t *vd = arg;
466094e47eGeorge Wilson	spa_t *spa = vd->vdev_spa;
467094e47eGeorge Wilson	int error = 0;
468094e47eGeorge Wilson	uint64_t ms_count = 0;
469094e47eGeorge Wilson
470094e47eGeorge Wilson	ASSERT(vdev_is_concrete(vd));
471094e47eGeorge Wilson	spa_config_enter(spa, SCL_CONFIG, FTAG, RW_READER);
472094e47eGeorge Wilson
473094e47eGeorge Wilson	vd->vdev_initialize_last_offset = 0;
474084fd14Brian Behlendorf	VERIFY0(vdev_initialize_load(vd));
475094e47eGeorge Wilson
476094e47eGeorge Wilson	abd_t *deadbeef = vdev_initialize_block_alloc();
477094e47eGeorge Wilson
4784d7988dPaul Dagnelie	vd->vdev_initialize_tree = range_tree_create(NULL, RANGE_SEG64, NULL,
4794d7988dPaul Dagnelie	    0, 0);
480094e47eGeorge Wilson
481094e47eGeorge Wilson	for (uint64_t i = 0; !vd->vdev_detached &&
482094e47eGeorge Wilson	    i < vd->vdev_top->vdev_ms_count; i++) {
483094e47eGeorge Wilson		metaslab_t *msp = vd->vdev_top->vdev_ms[i];
484af1d63aPaul Dagnelie		boolean_t unload_when_done = B_FALSE;
485094e47eGeorge Wilson
486094e47eGeorge Wilson		/*
487094e47eGeorge Wilson		 * If we've expanded the top-level vdev or it's our
488094e47eGeorge Wilson		 * first pass, calculate our progress.
489094e47eGeorge Wilson		 */
490094e47eGeorge Wilson		if (vd->vdev_top->vdev_ms_count != ms_count) {
491094e47eGeorge Wilson			vdev_initialize_calculate_progress(vd);
492094e47eGeorge Wilson			ms_count = vd->vdev_top->vdev_ms_count;
493094e47eGeorge Wilson		}
494094e47eGeorge Wilson
495084fd14Brian Behlendorf		spa_config_exit(spa, SCL_CONFIG, FTAG);
496084fd14Brian Behlendorf		metaslab_disable(msp);
497094e47eGeorge Wilson		mutex_enter(&msp->ms_lock);
498af1d63aPaul Dagnelie		if (!msp->ms_loaded && !msp->ms_loading)
499af1d63aPaul Dagnelie			unload_when_done = B_TRUE;
500a0b03b1Serapheim Dimitropoulos		VERIFY0(metaslab_load(msp));
501094e47eGeorge Wilson
502094e47eGeorge Wilson		range_tree_walk(msp->ms_allocatable, vdev_initialize_range_add,
503094e47eGeorge Wilson		    vd);
504094e47eGeorge Wilson		mutex_exit(&msp->ms_lock);
505094e47eGeorge Wilson
506094e47eGeorge Wilson		error = vdev_initialize_ranges(vd, deadbeef);
507af1d63aPaul Dagnelie		metaslab_enable(msp, B_TRUE, unload_when_done);
508094e47eGeorge Wilson		spa_config_enter(spa, SCL_CONFIG, FTAG, RW_READER);
509094e47eGeorge Wilson
510094e47eGeorge Wilson		range_tree_vacate(vd->vdev_initialize_tree, NULL, NULL);
511094e47eGeorge Wilson		if (error != 0)
512094e47eGeorge Wilson			break;
513094e47eGeorge Wilson	}
514094e47eGeorge Wilson
515094e47eGeorge Wilson	spa_config_exit(spa, SCL_CONFIG, FTAG);
516094e47eGeorge Wilson	mutex_enter(&vd->vdev_initialize_io_lock);
517094e47eGeorge Wilson	while (vd->vdev_initialize_inflight > 0) {
518094e47eGeorge Wilson		cv_wait(&vd->vdev_initialize_io_cv,
519094e47eGeorge Wilson		    &vd->vdev_initialize_io_lock);
520094e47eGeorge Wilson	}
521094e47eGeorge Wilson	mutex_exit(&vd->vdev_initialize_io_lock);
522094e47eGeorge Wilson
523094e47eGeorge Wilson	range_tree_destroy(vd->vdev_initialize_tree);
524094e47eGeorge Wilson	vdev_initialize_block_free(deadbeef);
525094e47eGeorge Wilson	vd->vdev_initialize_tree = NULL;
526094e47eGeorge Wilson
527094e47eGeorge Wilson	mutex_enter(&vd->vdev_initialize_lock);
528094e47eGeorge Wilson	if (!vd->vdev_initialize_exit_wanted && vdev_writeable(vd)) {
529094e47eGeorge Wilson		vdev_initialize_change_state(vd, VDEV_INITIALIZE_COMPLETE);
530094e47eGeorge Wilson	}
531094e47eGeorge Wilson	ASSERT(vd->vdev_initialize_thread != NULL ||
532094e47eGeorge Wilson	    vd->vdev_initialize_inflight == 0);
533094e47eGeorge Wilson
534094e47eGeorge Wilson	/*
535094e47eGeorge Wilson	 * Drop the vdev_initialize_lock while we sync out the
536094e47eGeorge Wilson	 * txg since it's possible that a device might be trying to
537094e47eGeorge Wilson	 * come online and must check to see if it needs to restart an
538094e47eGeorge Wilson	 * initialization. That thread will be holding the spa_config_lock
539094e47eGeorge Wilson	 * which would prevent the txg_wait_synced from completing.
540094e47eGeorge Wilson	 */
541094e47eGeorge Wilson	mutex_exit(&vd->vdev_initialize_lock);
542094e47eGeorge Wilson	txg_wait_synced(spa_get_dsl(spa), 0);
543094e47eGeorge Wilson	mutex_enter(&vd->vdev_initialize_lock);
544094e47eGeorge Wilson
545094e47eGeorge Wilson	vd->vdev_initialize_thread = NULL;
546094e47eGeorge Wilson	cv_broadcast(&vd->vdev_initialize_cv);
547094e47eGeorge Wilson	mutex_exit(&vd->vdev_initialize_lock);
548094e47eGeorge Wilson}
549094e47eGeorge Wilson
550094e47eGeorge Wilson/*
551094e47eGeorge Wilson * Initiates a device. Caller must hold vdev_initialize_lock.
552094e47eGeorge Wilson * Device must be a leaf and not already be initializing.
553094e47eGeorge Wilson */
554094e47eGeorge Wilsonvoid
555094e47eGeorge Wilsonvdev_initialize(vdev_t *vd)
556094e47eGeorge Wilson{
557094e47eGeorge Wilson	ASSERT(MUTEX_HELD(&vd->vdev_initialize_lock));
558094e47eGeorge Wilson	ASSERT(vd->vdev_ops->vdev_op_leaf);
559094e47eGeorge Wilson	ASSERT(vdev_is_concrete(vd));
560094e47eGeorge Wilson	ASSERT3P(vd->vdev_initialize_thread, ==, NULL);
561094e47eGeorge Wilson	ASSERT(!vd->vdev_detached);
562094e47eGeorge Wilson	ASSERT(!vd->vdev_initialize_exit_wanted);
563094e47eGeorge Wilson	ASSERT(!vd->vdev_top->vdev_removing);
564094e47eGeorge Wilson
565094e47eGeorge Wilson	vdev_initialize_change_state(vd, VDEV_INITIALIZE_ACTIVE);
566094e47eGeorge Wilson	vd->vdev_initialize_thread = thread_create(NULL, 0,
567094e47eGeorge Wilson	    vdev_initialize_thread, vd, 0, &p0, TS_RUN, maxclsyspri);
568094e47eGeorge Wilson}
569094e47eGeorge Wilson
570094e47eGeorge Wilson/*
571084fd14Brian Behlendorf * Wait for the initialize thread to be terminated (cancelled or stopped).
572084fd14Brian Behlendorf */
573084fd14Brian Behlendorfstatic void
574084fd14Brian Behlendorfvdev_initialize_stop_wait_impl(vdev_t *vd)
575084fd14Brian Behlendorf{
576084fd14Brian Behlendorf	ASSERT(MUTEX_HELD(&vd->vdev_initialize_lock));
577084fd14Brian Behlendorf
578084fd14Brian Behlendorf	while (vd->vdev_initialize_thread != NULL)
579084fd14Brian Behlendorf		cv_wait(&vd->vdev_initialize_cv, &vd->vdev_initialize_lock);
580084fd14Brian Behlendorf
581084fd14Brian Behlendorf	ASSERT3P(vd->vdev_initialize_thread, ==, NULL);
582084fd14Brian Behlendorf	vd->vdev_initialize_exit_wanted = B_FALSE;
583084fd14Brian Behlendorf}
584084fd14Brian Behlendorf
585084fd14Brian Behlendorf/*
586084fd14Brian Behlendorf * Wait for vdev initialize threads which were either to cleanly exit.
587094e47eGeorge Wilson */
588094e47eGeorge Wilsonvoid
589084fd14Brian Behlendorfvdev_initialize_stop_wait(spa_t *spa, list_t *vd_list)
590094e47eGeorge Wilson{
591084fd14Brian Behlendorf	vdev_t *vd;
592094e47eGeorge Wilson
593084fd14Brian Behlendorf	ASSERT(MUTEX_HELD(&spa_namespace_lock));
594084fd14Brian Behlendorf
595084fd14Brian Behlendorf	while ((vd = list_remove_head(vd_list)) != NULL) {
596084fd14Brian Behlendorf		mutex_enter(&vd->vdev_initialize_lock);
597084fd14Brian Behlendorf		vdev_initialize_stop_wait_impl(vd);
598084fd14Brian Behlendorf		mutex_exit(&vd->vdev_initialize_lock);
599084fd14Brian Behlendorf	}
600084fd14Brian Behlendorf}
601084fd14Brian Behlendorf
602084fd14Brian Behlendorf/*
603084fd14Brian Behlendorf * Stop initializing a device, with the resultant initializing state being
604084fd14Brian Behlendorf * tgt_state.  For blocking behavior pass NULL for vd_list.  Otherwise, when
605084fd14Brian Behlendorf * a list_t is provided the stopping vdev is inserted in to the list.  Callers
606084fd14Brian Behlendorf * are then required to call vdev_initialize_stop_wait() to block for all the
607084fd14Brian Behlendorf * initialization threads to exit.  The caller must hold vdev_initialize_lock
608084fd14Brian Behlendorf * and must not be writing to the spa config, as the initializing thread may
609084fd14Brian Behlendorf * try to enter the config as a reader before exiting.
610084fd14Brian Behlendorf */
611084fd14Brian Behlendorfvoid
612084fd14Brian Behlendorfvdev_initialize_stop(vdev_t *vd, vdev_initializing_state_t tgt_state,
613084fd14Brian Behlendorf    list_t *vd_list)
614084fd14Brian Behlendorf{
615084fd14Brian Behlendorf	ASSERT(!spa_config_held(vd->vdev_spa, SCL_CONFIG|SCL_STATE, RW_WRITER));
616094e47eGeorge Wilson	ASSERT(MUTEX_HELD(&vd->vdev_initialize_lock));
617094e47eGeorge Wilson	ASSERT(vd->vdev_ops->vdev_op_leaf);
618094e47eGeorge Wilson	ASSERT(vdev_is_concrete(vd));
619094e47eGeorge Wilson
620094e47eGeorge Wilson	/*
621094e47eGeorge Wilson	 * Allow cancel requests to proceed even if the initialize thread
622094e47eGeorge Wilson	 * has stopped.
623094e47eGeorge Wilson	 */
624094e47eGeorge Wilson	if (vd->vdev_initialize_thread == NULL &&
625094e47eGeorge Wilson	    tgt_state != VDEV_INITIALIZE_CANCELED) {
626094e47eGeorge Wilson		return;
627094e47eGeorge Wilson	}
628094e47eGeorge Wilson
629094e47eGeorge Wilson	vdev_initialize_change_state(vd, tgt_state);
630094e47eGeorge Wilson	vd->vdev_initialize_exit_wanted = B_TRUE;
631094e47eGeorge Wilson
632084fd14Brian Behlendorf	if (vd_list == NULL) {
633084fd14Brian Behlendorf		vdev_initialize_stop_wait_impl(vd);
634084fd14Brian Behlendorf	} else {
635084fd14Brian Behlendorf		ASSERT(MUTEX_HELD(&spa_namespace_lock));
636084fd14Brian Behlendorf		list_insert_tail(vd_list, vd);
637084fd14Brian Behlendorf	}
638094e47eGeorge Wilson}
639094e47eGeorge Wilson
640094e47eGeorge Wilsonstatic void
641084fd14Brian Behlendorfvdev_initialize_stop_all_impl(vdev_t *vd, vdev_initializing_state_t tgt_state,
642084fd14Brian Behlendorf    list_t *vd_list)
643094e47eGeorge Wilson{
644094e47eGeorge Wilson	if (vd->vdev_ops->vdev_op_leaf && vdev_is_concrete(vd)) {
645094e47eGeorge Wilson		mutex_enter(&vd->vdev_initialize_lock);
646084fd14Brian Behlendorf		vdev_initialize_stop(vd, tgt_state, vd_list);
647094e47eGeorge Wilson		mutex_exit(&vd->vdev_initialize_lock);
648094e47eGeorge Wilson		return;
649094e47eGeorge Wilson	}
650094e47eGeorge Wilson
651094e47eGeorge Wilson	for (uint64_t i = 0; i < vd->vdev_children; i++) {
652084fd14Brian Behlendorf		vdev_initialize_stop_all_impl(vd->vdev_child[i], tgt_state,
653084fd14Brian Behlendorf		    vd_list);
654094e47eGeorge Wilson	}
655094e47eGeorge Wilson}
656094e47eGeorge Wilson
657094e47eGeorge Wilson/*
658094e47eGeorge Wilson * Convenience function to stop initializing of a vdev tree and set all
659094e47eGeorge Wilson * initialize thread pointers to NULL.
660094e47eGeorge Wilson */
661094e47eGeorge Wilsonvoid
662094e47eGeorge Wilsonvdev_initialize_stop_all(vdev_t *vd, vdev_initializing_state_t tgt_state)
663094e47eGeorge Wilson{
664084fd14Brian Behlendorf	spa_t *spa = vd->vdev_spa;
665084fd14Brian Behlendorf	list_t vd_list;
666084fd14Brian Behlendorf
667084fd14Brian Behlendorf	ASSERT(MUTEX_HELD(&spa_namespace_lock));
668084fd14Brian Behlendorf
669084fd14Brian Behlendorf	list_create(&vd_list, sizeof (vdev_t),
670084fd14Brian Behlendorf	    offsetof(vdev_t, vdev_initialize_node));
671084fd14Brian Behlendorf
672084fd14Brian Behlendorf	vdev_initialize_stop_all_impl(vd, tgt_state, &vd_list);
673084fd14Brian Behlendorf	vdev_initialize_stop_wait(spa, &vd_list);
674094e47eGeorge Wilson
675094e47eGeorge Wilson	if (vd->vdev_spa->spa_sync_on) {
676094e47eGeorge Wilson		/* Make sure that our state has been synced to disk */
677094e47eGeorge Wilson		txg_wait_synced(spa_get_dsl(vd->vdev_spa), 0);
678094e47eGeorge Wilson	}
679084fd14Brian Behlendorf
680084fd14Brian Behlendorf	list_destroy(&vd_list);
681094e47eGeorge Wilson}
682094e47eGeorge Wilson
683094e47eGeorge Wilsonvoid
684094e47eGeorge Wilsonvdev_initialize_restart(vdev_t *vd)
685094e47eGeorge Wilson{
686094e47eGeorge Wilson	ASSERT(MUTEX_HELD(&spa_namespace_lock));
687094e47eGeorge Wilson	ASSERT(!spa_config_held(vd->vdev_spa, SCL_ALL, RW_WRITER));
688094e47eGeorge Wilson
689094e47eGeorge Wilson	if (vd->vdev_leaf_zap != 0) {
690094e47eGeorge Wilson		mutex_enter(&vd->vdev_initialize_lock);
691094e47eGeorge Wilson		uint64_t initialize_state = VDEV_INITIALIZE_NONE;
692094e47eGeorge Wilson		int err = zap_lookup(vd->vdev_spa->spa_meta_objset,
693094e47eGeorge Wilson		    vd->vdev_leaf_zap, VDEV_LEAF_ZAP_INITIALIZE_STATE,
694094e47eGeorge Wilson		    sizeof (initialize_state), 1, &initialize_state);
695094e47eGeorge Wilson		ASSERT(err == 0 || err == ENOENT);
696094e47eGeorge Wilson		vd->vdev_initialize_state = initialize_state;
697094e47eGeorge Wilson
698094e47eGeorge Wilson		uint64_t timestamp = 0;
699094e47eGeorge Wilson		err = zap_lookup(vd->vdev_spa->spa_meta_objset,
700094e47eGeorge Wilson		    vd->vdev_leaf_zap, VDEV_LEAF_ZAP_INITIALIZE_ACTION_TIME,
701094e47eGeorge Wilson		    sizeof (timestamp), 1, &timestamp);