xref: /illumos-gate/usr/src/lib/libzfs/common/libzfs_pool.c (revision 1195e687f1c03c8d57417b5999578922e20a3554)
1fa9e4066Sahrens /*
2fa9e4066Sahrens  * CDDL HEADER START
3fa9e4066Sahrens  *
4fa9e4066Sahrens  * The contents of this file are subject to the terms of the
5441d80aaSlling  * Common Development and Distribution License (the "License").
6441d80aaSlling  * You may not use this file except in compliance with the License.
7fa9e4066Sahrens  *
8fa9e4066Sahrens  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fa9e4066Sahrens  * or http://www.opensolaris.org/os/licensing.
10fa9e4066Sahrens  * See the License for the specific language governing permissions
11fa9e4066Sahrens  * and limitations under the License.
12fa9e4066Sahrens  *
13fa9e4066Sahrens  * When distributing Covered Code, include this CDDL HEADER in each
14fa9e4066Sahrens  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fa9e4066Sahrens  * If applicable, add the following below this CDDL HEADER, with the
16fa9e4066Sahrens  * fields enclosed by brackets "[]" replaced with your own identifying
17fa9e4066Sahrens  * information: Portions Copyright [yyyy] [name of copyright owner]
18fa9e4066Sahrens  *
19fa9e4066Sahrens  * CDDL HEADER END
20fa9e4066Sahrens  */
2199653d4eSeschrock 
22fa9e4066Sahrens /*
23*1195e687SMark J Musante  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24fa9e4066Sahrens  * Use is subject to license terms.
25fa9e4066Sahrens  */
26fa9e4066Sahrens 
27fa9e4066Sahrens #include <ctype.h>
28fa9e4066Sahrens #include <errno.h>
29fa9e4066Sahrens #include <devid.h>
30fa9e4066Sahrens #include <fcntl.h>
31fa9e4066Sahrens #include <libintl.h>
32fa9e4066Sahrens #include <stdio.h>
33fa9e4066Sahrens #include <stdlib.h>
34f3861e1aSahl #include <strings.h>
35fa9e4066Sahrens #include <unistd.h>
368488aeb5Staylor #include <sys/efi_partition.h>
378488aeb5Staylor #include <sys/vtoc.h>
38fa9e4066Sahrens #include <sys/zfs_ioctl.h>
39573ca77eSGeorge Wilson #include <dlfcn.h>
40fa9e4066Sahrens 
41fa9e4066Sahrens #include "zfs_namecheck.h"
42b1b8ab34Slling #include "zfs_prop.h"
43fa9e4066Sahrens #include "libzfs_impl.h"
44468c413aSTim Haley #include "zfs_comutil.h"
45fa9e4066Sahrens 
468f18d1faSGeorge Wilson const char *hist_event_table[LOG_END] = {
478f18d1faSGeorge Wilson 	"invalid event",
488f18d1faSGeorge Wilson 	"pool create",
498f18d1faSGeorge Wilson 	"vdev add",
508f18d1faSGeorge Wilson 	"pool remove",
518f18d1faSGeorge Wilson 	"pool destroy",
528f18d1faSGeorge Wilson 	"pool export",
538f18d1faSGeorge Wilson 	"pool import",
548f18d1faSGeorge Wilson 	"vdev attach",
558f18d1faSGeorge Wilson 	"vdev replace",
568f18d1faSGeorge Wilson 	"vdev detach",
578f18d1faSGeorge Wilson 	"vdev online",
588f18d1faSGeorge Wilson 	"vdev offline",
598f18d1faSGeorge Wilson 	"vdev upgrade",
608f18d1faSGeorge Wilson 	"pool clear",
618f18d1faSGeorge Wilson 	"pool scrub",
628f18d1faSGeorge Wilson 	"pool property set",
638f18d1faSGeorge Wilson 	"create",
648f18d1faSGeorge Wilson 	"clone",
658f18d1faSGeorge Wilson 	"destroy",
668f18d1faSGeorge Wilson 	"destroy_begin_sync",
678f18d1faSGeorge Wilson 	"inherit",
688f18d1faSGeorge Wilson 	"property set",
698f18d1faSGeorge Wilson 	"quota set",
708f18d1faSGeorge Wilson 	"permission update",
718f18d1faSGeorge Wilson 	"permission remove",
728f18d1faSGeorge Wilson 	"permission who remove",
738f18d1faSGeorge Wilson 	"promote",
748f18d1faSGeorge Wilson 	"receive",
758f18d1faSGeorge Wilson 	"rename",
768f18d1faSGeorge Wilson 	"reservation set",
778f18d1faSGeorge Wilson 	"replay_inc_sync",
788f18d1faSGeorge Wilson 	"replay_full_sync",
798f18d1faSGeorge Wilson 	"rollback",
808f18d1faSGeorge Wilson 	"snapshot",
818f18d1faSGeorge Wilson 	"filesystem version upgrade",
828f18d1faSGeorge Wilson 	"refquota set",
838f18d1faSGeorge Wilson 	"refreservation set",
848f18d1faSGeorge Wilson 	"pool scrub done",
858f18d1faSGeorge Wilson 	"user hold",
868f18d1faSGeorge Wilson 	"user release",
87*1195e687SMark J Musante 	"pool split",
888f18d1faSGeorge Wilson };
898f18d1faSGeorge Wilson 
9015e6edf1Sgw static int read_efi_label(nvlist_t *config, diskaddr_t *sb);
91990b4856Slling 
92b5b76fecSGeorge Wilson #if defined(__i386) || defined(__amd64)
93b5b76fecSGeorge Wilson #define	BOOTCMD	"installgrub(1M)"
94b5b76fecSGeorge Wilson #else
95b5b76fecSGeorge Wilson #define	BOOTCMD	"installboot(1M)"
96b5b76fecSGeorge Wilson #endif
97b5b76fecSGeorge Wilson 
98573ca77eSGeorge Wilson #define	DISK_ROOT	"/dev/dsk"
99573ca77eSGeorge Wilson #define	RDISK_ROOT	"/dev/rdsk"
100573ca77eSGeorge Wilson #define	BACKUP_SLICE	"s2"
101573ca77eSGeorge Wilson 
102990b4856Slling /*
103990b4856Slling  * ====================================================================
104990b4856Slling  *   zpool property functions
105990b4856Slling  * ====================================================================
106990b4856Slling  */
107990b4856Slling 
108990b4856Slling static int
109990b4856Slling zpool_get_all_props(zpool_handle_t *zhp)
110990b4856Slling {
111990b4856Slling 	zfs_cmd_t zc = { 0 };
112990b4856Slling 	libzfs_handle_t *hdl = zhp->zpool_hdl;
113990b4856Slling 
114990b4856Slling 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
115990b4856Slling 
116990b4856Slling 	if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0)
117990b4856Slling 		return (-1);
118990b4856Slling 
119990b4856Slling 	while (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_PROPS, &zc) != 0) {
120990b4856Slling 		if (errno == ENOMEM) {
121990b4856Slling 			if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
122990b4856Slling 				zcmd_free_nvlists(&zc);
123990b4856Slling 				return (-1);
124990b4856Slling 			}
125990b4856Slling 		} else {
126990b4856Slling 			zcmd_free_nvlists(&zc);
127990b4856Slling 			return (-1);
128990b4856Slling 		}
129990b4856Slling 	}
130990b4856Slling 
131990b4856Slling 	if (zcmd_read_dst_nvlist(hdl, &zc, &zhp->zpool_props) != 0) {
132990b4856Slling 		zcmd_free_nvlists(&zc);
133990b4856Slling 		return (-1);
134990b4856Slling 	}
135990b4856Slling 
136990b4856Slling 	zcmd_free_nvlists(&zc);
137990b4856Slling 
138990b4856Slling 	return (0);
139990b4856Slling }
140990b4856Slling 
141990b4856Slling static int
142990b4856Slling zpool_props_refresh(zpool_handle_t *zhp)
143990b4856Slling {
144990b4856Slling 	nvlist_t *old_props;
145990b4856Slling 
146990b4856Slling 	old_props = zhp->zpool_props;
147990b4856Slling 
148990b4856Slling 	if (zpool_get_all_props(zhp) != 0)
149990b4856Slling 		return (-1);
150990b4856Slling 
151990b4856Slling 	nvlist_free(old_props);
152990b4856Slling 	return (0);
153990b4856Slling }
154990b4856Slling 
155990b4856Slling static char *
156990b4856Slling zpool_get_prop_string(zpool_handle_t *zhp, zpool_prop_t prop,
157990b4856Slling     zprop_source_t *src)
158990b4856Slling {
159990b4856Slling 	nvlist_t *nv, *nvl;
160990b4856Slling 	uint64_t ival;
161990b4856Slling 	char *value;
162990b4856Slling 	zprop_source_t source;
163990b4856Slling 
164990b4856Slling 	nvl = zhp->zpool_props;
165990b4856Slling 	if (nvlist_lookup_nvlist(nvl, zpool_prop_to_name(prop), &nv) == 0) {
166990b4856Slling 		verify(nvlist_lookup_uint64(nv, ZPROP_SOURCE, &ival) == 0);
167990b4856Slling 		source = ival;
168990b4856Slling 		verify(nvlist_lookup_string(nv, ZPROP_VALUE, &value) == 0);
169990b4856Slling 	} else {
170990b4856Slling 		source = ZPROP_SRC_DEFAULT;
171990b4856Slling 		if ((value = (char *)zpool_prop_default_string(prop)) == NULL)
172990b4856Slling 			value = "-";
173990b4856Slling 	}
174990b4856Slling 
175990b4856Slling 	if (src)
176990b4856Slling 		*src = source;
177990b4856Slling 
178990b4856Slling 	return (value);
179990b4856Slling }
180990b4856Slling 
181990b4856Slling uint64_t
182990b4856Slling zpool_get_prop_int(zpool_handle_t *zhp, zpool_prop_t prop, zprop_source_t *src)
183990b4856Slling {
184990b4856Slling 	nvlist_t *nv, *nvl;
185990b4856Slling 	uint64_t value;
186990b4856Slling 	zprop_source_t source;
187990b4856Slling 
188b87f3af3Sperrin 	if (zhp->zpool_props == NULL && zpool_get_all_props(zhp)) {
189b87f3af3Sperrin 		/*
190b87f3af3Sperrin 		 * zpool_get_all_props() has most likely failed because
191b87f3af3Sperrin 		 * the pool is faulted, but if all we need is the top level
192b87f3af3Sperrin 		 * vdev's guid then get it from the zhp config nvlist.
193b87f3af3Sperrin 		 */
194b87f3af3Sperrin 		if ((prop == ZPOOL_PROP_GUID) &&
195b87f3af3Sperrin 		    (nvlist_lookup_nvlist(zhp->zpool_config,
196b87f3af3Sperrin 		    ZPOOL_CONFIG_VDEV_TREE, &nv) == 0) &&
197b87f3af3Sperrin 		    (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &value)
198b87f3af3Sperrin 		    == 0)) {
199b87f3af3Sperrin 			return (value);
200b87f3af3Sperrin 		}
201990b4856Slling 		return (zpool_prop_default_numeric(prop));
202b87f3af3Sperrin 	}
203990b4856Slling 
204990b4856Slling 	nvl = zhp->zpool_props;
205990b4856Slling 	if (nvlist_lookup_nvlist(nvl, zpool_prop_to_name(prop), &nv) == 0) {
206990b4856Slling 		verify(nvlist_lookup_uint64(nv, ZPROP_SOURCE, &value) == 0);
207990b4856Slling 		source = value;
208990b4856Slling 		verify(nvlist_lookup_uint64(nv, ZPROP_VALUE, &value) == 0);
209990b4856Slling 	} else {
210990b4856Slling 		source = ZPROP_SRC_DEFAULT;
211990b4856Slling 		value = zpool_prop_default_numeric(prop);
212990b4856Slling 	}
213990b4856Slling 
214990b4856Slling 	if (src)
215990b4856Slling 		*src = source;
216990b4856Slling 
217990b4856Slling 	return (value);
218990b4856Slling }
219990b4856Slling 
220990b4856Slling /*
221990b4856Slling  * Map VDEV STATE to printed strings.
222990b4856Slling  */
223990b4856Slling char *
224990b4856Slling zpool_state_to_name(vdev_state_t state, vdev_aux_t aux)
225990b4856Slling {
226990b4856Slling 	switch (state) {
227990b4856Slling 	case VDEV_STATE_CLOSED:
228990b4856Slling 	case VDEV_STATE_OFFLINE:
229990b4856Slling 		return (gettext("OFFLINE"));
230990b4856Slling 	case VDEV_STATE_REMOVED:
231990b4856Slling 		return (gettext("REMOVED"));
232990b4856Slling 	case VDEV_STATE_CANT_OPEN:
233b87f3af3Sperrin 		if (aux == VDEV_AUX_CORRUPT_DATA || aux == VDEV_AUX_BAD_LOG)
234990b4856Slling 			return (gettext("FAULTED"));
235*1195e687SMark J Musante 		else if (aux == VDEV_AUX_SPLIT_POOL)
236*1195e687SMark J Musante 			return (gettext("SPLIT"));
237990b4856Slling 		else
238990b4856Slling 			return (gettext("UNAVAIL"));
239990b4856Slling 	case VDEV_STATE_FAULTED:
240990b4856Slling 		return (gettext("FAULTED"));
241990b4856Slling 	case VDEV_STATE_DEGRADED:
242990b4856Slling 		return (gettext("DEGRADED"));
243990b4856Slling 	case VDEV_STATE_HEALTHY:
244990b4856Slling 		return (gettext("ONLINE"));
245990b4856Slling 	}
246990b4856Slling 
247990b4856Slling 	return (gettext("UNKNOWN"));
248990b4856Slling }
249990b4856Slling 
250990b4856Slling /*
251990b4856Slling  * Get a zpool property value for 'prop' and return the value in
252990b4856Slling  * a pre-allocated buffer.
253990b4856Slling  */
254990b4856Slling int
255990b4856Slling zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, size_t len,
256990b4856Slling     zprop_source_t *srctype)
257990b4856Slling {
258990b4856Slling 	uint64_t intval;
259990b4856Slling 	const char *strval;
260990b4856Slling 	zprop_source_t src = ZPROP_SRC_NONE;
261990b4856Slling 	nvlist_t *nvroot;
262990b4856Slling 	vdev_stat_t *vs;
263990b4856Slling 	uint_t vsc;
264990b4856Slling 
265990b4856Slling 	if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
266379c004dSEric Schrock 		switch (prop) {
267379c004dSEric Schrock 		case ZPOOL_PROP_NAME:
268990b4856Slling 			(void) strlcpy(buf, zpool_get_name(zhp), len);
269379c004dSEric Schrock 			break;
270379c004dSEric Schrock 
271379c004dSEric Schrock 		case ZPOOL_PROP_HEALTH:
272990b4856Slling 			(void) strlcpy(buf, "FAULTED", len);
273379c004dSEric Schrock 			break;
274379c004dSEric Schrock 
275379c004dSEric Schrock 		case ZPOOL_PROP_GUID:
276379c004dSEric Schrock 			intval = zpool_get_prop_int(zhp, prop, &src);
277379c004dSEric Schrock 			(void) snprintf(buf, len, "%llu", intval);
278379c004dSEric Schrock 			break;
279379c004dSEric Schrock 
280379c004dSEric Schrock 		case ZPOOL_PROP_ALTROOT:
281379c004dSEric Schrock 		case ZPOOL_PROP_CACHEFILE:
282379c004dSEric Schrock 			if (zhp->zpool_props != NULL ||
283379c004dSEric Schrock 			    zpool_get_all_props(zhp) == 0) {
284379c004dSEric Schrock 				(void) strlcpy(buf,
285379c004dSEric Schrock 				    zpool_get_prop_string(zhp, prop, &src),
286379c004dSEric Schrock 				    len);
287379c004dSEric Schrock 				if (srctype != NULL)
288379c004dSEric Schrock 					*srctype = src;
289379c004dSEric Schrock 				return (0);
290379c004dSEric Schrock 			}
291379c004dSEric Schrock 			/* FALLTHROUGH */
292379c004dSEric Schrock 		default:
293990b4856Slling 			(void) strlcpy(buf, "-", len);
294379c004dSEric Schrock 			break;
295379c004dSEric Schrock 		}
296379c004dSEric Schrock 
297379c004dSEric Schrock 		if (srctype != NULL)
298379c004dSEric Schrock 			*srctype = src;
299990b4856Slling 		return (0);
300990b4856Slling 	}
301990b4856Slling 
302990b4856Slling 	if (zhp->zpool_props == NULL && zpool_get_all_props(zhp) &&
303990b4856Slling 	    prop != ZPOOL_PROP_NAME)
304990b4856Slling 		return (-1);
305990b4856Slling 
306990b4856Slling 	switch (zpool_prop_get_type(prop)) {
307990b4856Slling 	case PROP_TYPE_STRING:
308990b4856Slling 		(void) strlcpy(buf, zpool_get_prop_string(zhp, prop, &src),
309990b4856Slling 		    len);
310990b4856Slling 		break;
311990b4856Slling 
312990b4856Slling 	case PROP_TYPE_NUMBER:
313990b4856Slling 		intval = zpool_get_prop_int(zhp, prop, &src);
314990b4856Slling 
315990b4856Slling 		switch (prop) {
316990b4856Slling 		case ZPOOL_PROP_SIZE:
317485bbbf5SGeorge Wilson 		case ZPOOL_PROP_ALLOCATED:
318485bbbf5SGeorge Wilson 		case ZPOOL_PROP_FREE:
319990b4856Slling 			(void) zfs_nicenum(intval, buf, len);
320990b4856Slling 			break;
321990b4856Slling 
322990b4856Slling 		case ZPOOL_PROP_CAPACITY:
323990b4856Slling 			(void) snprintf(buf, len, "%llu%%",
324990b4856Slling 			    (u_longlong_t)intval);
325990b4856Slling 			break;
326990b4856Slling 
327b24ab676SJeff Bonwick 		case ZPOOL_PROP_DEDUPRATIO:
328b24ab676SJeff Bonwick 			(void) snprintf(buf, len, "%llu.%02llux",
329b24ab676SJeff Bonwick 			    (u_longlong_t)(intval / 100),
330b24ab676SJeff Bonwick 			    (u_longlong_t)(intval % 100));
331b24ab676SJeff Bonwick 			break;
332b24ab676SJeff Bonwick 
333990b4856Slling 		case ZPOOL_PROP_HEALTH:
334990b4856Slling 			verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL),
335990b4856Slling 			    ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
336990b4856Slling 			verify(nvlist_lookup_uint64_array(nvroot,
337990b4856Slling 			    ZPOOL_CONFIG_STATS, (uint64_t **)&vs, &vsc) == 0);
338990b4856Slling 
339990b4856Slling 			(void) strlcpy(buf, zpool_state_to_name(intval,
340990b4856Slling 			    vs->vs_aux), len);
341990b4856Slling 			break;
342990b4856Slling 		default:
343990b4856Slling 			(void) snprintf(buf, len, "%llu", intval);
344990b4856Slling 		}
345990b4856Slling 		break;
346990b4856Slling 
347990b4856Slling 	case PROP_TYPE_INDEX:
348990b4856Slling 		intval = zpool_get_prop_int(zhp, prop, &src);
349990b4856Slling 		if (zpool_prop_index_to_string(prop, intval, &strval)
350990b4856Slling 		    != 0)
351990b4856Slling 			return (-1);
352990b4856Slling 		(void) strlcpy(buf, strval, len);
353990b4856Slling 		break;
354990b4856Slling 
355990b4856Slling 	default:
356990b4856Slling 		abort();
357990b4856Slling 	}
358990b4856Slling 
359990b4856Slling 	if (srctype)
360990b4856Slling 		*srctype = src;
361990b4856Slling 
362990b4856Slling 	return (0);
363990b4856Slling }
364990b4856Slling 
365990b4856Slling /*
366990b4856Slling  * Check if the bootfs name has the same pool name as it is set to.
367990b4856Slling  * Assuming bootfs is a valid dataset name.
368990b4856Slling  */
369990b4856Slling static boolean_t
370990b4856Slling bootfs_name_valid(const char *pool, char *bootfs)
371990b4856Slling {
372990b4856Slling 	int len = strlen(pool);
373990b4856Slling 
374fe3e2633SEric Taylor 	if (!zfs_name_valid(bootfs, ZFS_TYPE_FILESYSTEM|ZFS_TYPE_SNAPSHOT))
375990b4856Slling 		return (B_FALSE);
376990b4856Slling 
377990b4856Slling 	if (strncmp(pool, bootfs, len) == 0 &&
378990b4856Slling 	    (bootfs[len] == '/' || bootfs[len] == '\0'))
379990b4856Slling 		return (B_TRUE);
380990b4856Slling 
381990b4856Slling 	return (B_FALSE);
382990b4856Slling }
383990b4856Slling 
38415e6edf1Sgw /*
38515e6edf1Sgw  * Inspect the configuration to determine if any of the devices contain
38615e6edf1Sgw  * an EFI label.
38715e6edf1Sgw  */
38815e6edf1Sgw static boolean_t
38915e6edf1Sgw pool_uses_efi(nvlist_t *config)
39015e6edf1Sgw {
39115e6edf1Sgw 	nvlist_t **child;
39215e6edf1Sgw 	uint_t c, children;
39315e6edf1Sgw 
39415e6edf1Sgw 	if (nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_CHILDREN,
39515e6edf1Sgw 	    &child, &children) != 0)
39615e6edf1Sgw 		return (read_efi_label(config, NULL) >= 0);
39715e6edf1Sgw 
39815e6edf1Sgw 	for (c = 0; c < children; c++) {
39915e6edf1Sgw 		if (pool_uses_efi(child[c]))
40015e6edf1Sgw 			return (B_TRUE);
40115e6edf1Sgw 	}
40215e6edf1Sgw 	return (B_FALSE);
40315e6edf1Sgw }
40415e6edf1Sgw 
405b5b76fecSGeorge Wilson static boolean_t
406b5b76fecSGeorge Wilson pool_is_bootable(zpool_handle_t *zhp)
407b5b76fecSGeorge Wilson {
408b5b76fecSGeorge Wilson 	char bootfs[ZPOOL_MAXNAMELEN];
409b5b76fecSGeorge Wilson 
410b5b76fecSGeorge Wilson 	return (zpool_get_prop(zhp, ZPOOL_PROP_BOOTFS, bootfs,
411b5b76fecSGeorge Wilson 	    sizeof (bootfs), NULL) == 0 && strncmp(bootfs, "-",
412b5b76fecSGeorge Wilson 	    sizeof (bootfs)) != 0);
413b5b76fecSGeorge Wilson }
414b5b76fecSGeorge Wilson 
415b5b76fecSGeorge Wilson 
416990b4856Slling /*
417990b4856Slling  * Given an nvlist of zpool properties to be set, validate that they are
418990b4856Slling  * correct, and parse any numeric properties (index, boolean, etc) if they are
419990b4856Slling  * specified as strings.
420990b4856Slling  */
421990b4856Slling static nvlist_t *
4220a48a24eStimh zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname,
423990b4856Slling     nvlist_t *props, uint64_t version, boolean_t create_or_import, char *errbuf)
424990b4856Slling {
425990b4856Slling 	nvpair_t *elem;
426990b4856Slling 	nvlist_t *retprops;
427990b4856Slling 	zpool_prop_t prop;
428990b4856Slling 	char *strval;
429990b4856Slling 	uint64_t intval;
4302f8aaab3Seschrock 	char *slash;
4312f8aaab3Seschrock 	struct stat64 statbuf;
43215e6edf1Sgw 	zpool_handle_t *zhp;
43315e6edf1Sgw 	nvlist_t *nvroot;
434990b4856Slling 
435990b4856Slling 	if (nvlist_alloc(&retprops, NV_UNIQUE_NAME, 0) != 0) {
436990b4856Slling 		(void) no_memory(hdl);
437990b4856Slling 		return (NULL);
438990b4856Slling 	}
439990b4856Slling 
440990b4856Slling 	elem = NULL;
441990b4856Slling 	while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
442990b4856Slling 		const char *propname = nvpair_name(elem);
443990b4856Slling 
444990b4856Slling 		/*
445990b4856Slling 		 * Make sure this property is valid and applies to this type.
446990b4856Slling 		 */
447990b4856Slling 		if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL) {
448990b4856Slling 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
449990b4856Slling 			    "invalid property '%s'"), propname);
450990b4856Slling 			(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
451990b4856Slling 			goto error;
452990b4856Slling 		}
453990b4856Slling 
454990b4856Slling 		if (zpool_prop_readonly(prop)) {
455990b4856Slling 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' "
456990b4856Slling 			    "is readonly"), propname);
457990b4856Slling 			(void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf);
458990b4856Slling 			goto error;
459990b4856Slling 		}
460990b4856Slling 
461990b4856Slling 		if (zprop_parse_value(hdl, elem, prop, ZFS_TYPE_POOL, retprops,
462990b4856Slling 		    &strval, &intval, errbuf) != 0)
463990b4856Slling 			goto error;
464990b4856Slling 
465990b4856Slling 		/*
466990b4856Slling 		 * Perform additional checking for specific properties.
467990b4856Slling 		 */
468990b4856Slling 		switch (prop) {
469990b4856Slling 		case ZPOOL_PROP_VERSION:
470990b4856Slling 			if (intval < version || intval > SPA_VERSION) {
471990b4856Slling 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
472990b4856Slling 				    "property '%s' number %d is invalid."),
473990b4856Slling 				    propname, intval);
474990b4856Slling 				(void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
475990b4856Slling 				goto error;
476990b4856Slling 			}
477990b4856Slling 			break;
478990b4856Slling 
479990b4856Slling 		case ZPOOL_PROP_BOOTFS:
480990b4856Slling 			if (create_or_import) {
481990b4856Slling 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
482990b4856Slling 				    "property '%s' cannot be set at creation "
483990b4856Slling 				    "or import time"), propname);
484990b4856Slling 				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
485990b4856Slling 				goto error;
486990b4856Slling 			}
487990b4856Slling 
488990b4856Slling 			if (version < SPA_VERSION_BOOTFS) {
489990b4856Slling 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
490990b4856Slling 				    "pool must be upgraded to support "
491990b4856Slling 				    "'%s' property"), propname);
492990b4856Slling 				(void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
493990b4856Slling 				goto error;
494990b4856Slling 			}
495990b4856Slling 
496990b4856Slling 			/*
497990b4856Slling 			 * bootfs property value has to be a dataset name and
498990b4856Slling 			 * the dataset has to be in the same pool as it sets to.
499990b4856Slling 			 */
500990b4856Slling 			if (strval[0] != '\0' && !bootfs_name_valid(poolname,
501990b4856Slling 			    strval)) {
502990b4856Slling 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' "
503990b4856Slling 				    "is an invalid name"), strval);
504990b4856Slling 				(void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf);
505990b4856Slling 				goto error;
506990b4856Slling 			}
50715e6edf1Sgw 
50815e6edf1Sgw 			if ((zhp = zpool_open_canfail(hdl, poolname)) == NULL) {
50915e6edf1Sgw 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
51015e6edf1Sgw 				    "could not open pool '%s'"), poolname);
51115e6edf1Sgw 				(void) zfs_error(hdl, EZFS_OPENFAILED, errbuf);
51215e6edf1Sgw 				goto error;
51315e6edf1Sgw 			}
51415e6edf1Sgw 			verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL),
51515e6edf1Sgw 			    ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
51615e6edf1Sgw 
51715e6edf1Sgw 			/*
51815e6edf1Sgw 			 * bootfs property cannot be set on a disk which has
51915e6edf1Sgw 			 * been EFI labeled.
52015e6edf1Sgw 			 */
52115e6edf1Sgw 			if (pool_uses_efi(nvroot)) {
52215e6edf1Sgw 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
52315e6edf1Sgw 				    "property '%s' not supported on "
52415e6edf1Sgw 				    "EFI labeled devices"), propname);
52515e6edf1Sgw 				(void) zfs_error(hdl, EZFS_POOL_NOTSUP, errbuf);
52615e6edf1Sgw 				zpool_close(zhp);
52715e6edf1Sgw 				goto error;
52815e6edf1Sgw 			}
52915e6edf1Sgw 			zpool_close(zhp);
530990b4856Slling 			break;
531990b4856Slling 
5322f8aaab3Seschrock 		case ZPOOL_PROP_ALTROOT:
533990b4856Slling 			if (!create_or_import) {
534990b4856Slling 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
535990b4856Slling 				    "property '%s' can only be set during pool "
536990b4856Slling 				    "creation or import"), propname);
537990b4856Slling 				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
538990b4856Slling 				goto error;
539990b4856Slling 			}
540990b4856Slling 
5412f8aaab3Seschrock 			if (strval[0] != '/') {
542990b4856Slling 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
5432f8aaab3Seschrock 				    "bad alternate root '%s'"), strval);
5442f8aaab3Seschrock 				(void) zfs_error(hdl, EZFS_BADPATH, errbuf);
545990b4856Slling 				goto error;
546990b4856Slling 			}
5472f8aaab3Seschrock 			break;
5482f8aaab3Seschrock 
5492f8aaab3Seschrock 		case ZPOOL_PROP_CACHEFILE:
5502f8aaab3Seschrock 			if (strval[0] == '\0')
5512f8aaab3Seschrock 				break;
5522f8aaab3Seschrock 
5532f8aaab3Seschrock 			if (strcmp(strval, "none") == 0)
5542f8aaab3Seschrock 				break;
555990b4856Slling 
556990b4856Slling 			if (strval[0] != '/') {
557990b4856Slling 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
5582f8aaab3Seschrock 				    "property '%s' must be empty, an "
5592f8aaab3Seschrock 				    "absolute path, or 'none'"), propname);
560990b4856Slling 				(void) zfs_error(hdl, EZFS_BADPATH, errbuf);
561990b4856Slling 				goto error;
562990b4856Slling 			}
563990b4856Slling 
5642f8aaab3Seschrock 			slash = strrchr(strval, '/');
565990b4856Slling 
5662f8aaab3Seschrock 			if (slash[1] == '\0' || strcmp(slash, "/.") == 0 ||
5672f8aaab3Seschrock 			    strcmp(slash, "/..") == 0) {
5682f8aaab3Seschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
5692f8aaab3Seschrock 				    "'%s' is not a valid file"), strval);
5702f8aaab3Seschrock 				(void) zfs_error(hdl, EZFS_BADPATH, errbuf);
5712f8aaab3Seschrock 				goto error;
5722f8aaab3Seschrock 			}
573990b4856Slling 
5742f8aaab3Seschrock 			*slash = '\0';
5752f8aaab3Seschrock 
5762c32020fSeschrock 			if (strval[0] != '\0' &&
5772c32020fSeschrock 			    (stat64(strval, &statbuf) != 0 ||
5782c32020fSeschrock 			    !S_ISDIR(statbuf.st_mode))) {
5792f8aaab3Seschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
5802f8aaab3Seschrock 				    "'%s' is not a valid directory"),
5812f8aaab3Seschrock 				    strval);
5822f8aaab3Seschrock 				(void) zfs_error(hdl, EZFS_BADPATH, errbuf);
5832f8aaab3Seschrock 				goto error;
5842f8aaab3Seschrock 			}
5852f8aaab3Seschrock 
5862f8aaab3Seschrock 			*slash = '/';
5872f8aaab3Seschrock 			break;
588990b4856Slling 		}
589990b4856Slling 	}
590990b4856Slling 
591990b4856Slling 	return (retprops);
592990b4856Slling error:
593990b4856Slling 	nvlist_free(retprops);
594990b4856Slling 	return (NULL);
595990b4856Slling }
596990b4856Slling 
597990b4856Slling /*
598990b4856Slling  * Set zpool property : propname=propval.
599990b4856Slling  */
600990b4856Slling int
601990b4856Slling zpool_set_prop(zpool_handle_t *zhp, const char *propname, const char *propval)
602990b4856Slling {
603990b4856Slling 	zfs_cmd_t zc = { 0 };
604990b4856Slling 	int ret = -1;
605990b4856Slling 	char errbuf[1024];
606990b4856Slling 	nvlist_t *nvl = NULL;
607990b4856Slling 	nvlist_t *realprops;
608990b4856Slling 	uint64_t version;
609990b4856Slling 
610990b4856Slling 	(void) snprintf(errbuf, sizeof (errbuf),
611990b4856Slling 	    dgettext(TEXT_DOMAIN, "cannot set property for '%s'"),
612990b4856Slling 	    zhp->zpool_name);
613990b4856Slling 
614990b4856Slling 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
615990b4856Slling 		return (no_memory(zhp->zpool_hdl));
616990b4856Slling 
617990b4856Slling 	if (nvlist_add_string(nvl, propname, propval) != 0) {
618990b4856Slling 		nvlist_free(nvl);
619990b4856Slling 		return (no_memory(zhp->zpool_hdl));
620990b4856Slling 	}
621990b4856Slling 
622990b4856Slling 	version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
6230a48a24eStimh 	if ((realprops = zpool_valid_proplist(zhp->zpool_hdl,
624990b4856Slling 	    zhp->zpool_name, nvl, version, B_FALSE, errbuf)) == NULL) {
625990b4856Slling 		nvlist_free(nvl);
626990b4856Slling 		return (-1);
627990b4856Slling 	}
628990b4856Slling 
629990b4856Slling 	nvlist_free(nvl);
630990b4856Slling 	nvl = realprops;
631990b4856Slling 
632990b4856Slling 	/*
633990b4856Slling 	 * Execute the corresponding ioctl() to set this property.
634990b4856Slling 	 */
635990b4856Slling 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
636990b4856Slling 
637990b4856Slling 	if (zcmd_write_src_nvlist(zhp->zpool_hdl, &zc, nvl) != 0) {
638990b4856Slling 		nvlist_free(nvl);
639990b4856Slling 		return (-1);
640990b4856Slling 	}
641990b4856Slling 
642990b4856Slling 	ret = zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_SET_PROPS, &zc);
643990b4856Slling 
644990b4856Slling 	zcmd_free_nvlists(&zc);
645990b4856Slling 	nvlist_free(nvl);
646990b4856Slling 
647990b4856Slling 	if (ret)
648990b4856Slling 		(void) zpool_standard_error(zhp->zpool_hdl, errno, errbuf);
649990b4856Slling 	else
650990b4856Slling 		(void) zpool_props_refresh(zhp);
651990b4856Slling 
652990b4856Slling 	return (ret);
653990b4856Slling }
654990b4856Slling 
655990b4856Slling int
656990b4856Slling zpool_expand_proplist(zpool_handle_t *zhp, zprop_list_t **plp)
657990b4856Slling {
658990b4856Slling 	libzfs_handle_t *hdl = zhp->zpool_hdl;
659990b4856Slling 	zprop_list_t *entry;
660990b4856Slling 	char buf[ZFS_MAXPROPLEN];
661990b4856Slling 
662990b4856Slling 	if (zprop_expand_list(hdl, plp, ZFS_TYPE_POOL) != 0)
663990b4856Slling 		return (-1);
664990b4856Slling 
665990b4856Slling 	for (entry = *plp; entry != NULL; entry = entry->pl_next) {
666990b4856Slling 
667990b4856Slling 		if (entry->pl_fixed)
668990b4856Slling 			continue;
669990b4856Slling 
670990b4856Slling 		if (entry->pl_prop != ZPROP_INVAL &&
671990b4856Slling 		    zpool_get_prop(zhp, entry->pl_prop, buf, sizeof (buf),
672990b4856Slling 		    NULL) == 0) {
673990b4856Slling 			if (strlen(buf) > entry->pl_width)
674990b4856Slling 				entry->pl_width = strlen(buf);
675990b4856Slling 		}
676990b4856Slling 	}
677990b4856Slling 
678990b4856Slling 	return (0);
679990b4856Slling }
680990b4856Slling 
681990b4856Slling 
682573ca77eSGeorge Wilson /*
683573ca77eSGeorge Wilson  * Don't start the slice at the default block of 34; many storage
684573ca77eSGeorge Wilson  * devices will use a stripe width of 128k, so start there instead.
685573ca77eSGeorge Wilson  */
686573ca77eSGeorge Wilson #define	NEW_START_BLOCK	256
687573ca77eSGeorge Wilson 
688fa9e4066Sahrens /*
689fa9e4066Sahrens  * Validate the given pool name, optionally putting an extended error message in
690fa9e4066Sahrens  * 'buf'.
691fa9e4066Sahrens  */
692e7cbe64fSgw boolean_t
69399653d4eSeschrock zpool_name_valid(libzfs_handle_t *hdl, boolean_t isopen, const char *pool)
694fa9e4066Sahrens {
695fa9e4066Sahrens 	namecheck_err_t why;
696fa9e4066Sahrens 	char what;
697b468a217Seschrock 	int ret;
698b468a217Seschrock 
699b468a217Seschrock 	ret = pool_namecheck(pool, &why, &what);
700b468a217Seschrock 
701b468a217Seschrock 	/*
702b468a217Seschrock 	 * The rules for reserved pool names were extended at a later point.
703b468a217Seschrock 	 * But we need to support users with existing pools that may now be
704b468a217Seschrock 	 * invalid.  So we only check for this expanded set of names during a
705b468a217Seschrock 	 * create (or import), and only in userland.
706b468a217Seschrock 	 */
707b468a217Seschrock 	if (ret == 0 && !isopen &&
708b468a217Seschrock 	    (strncmp(pool, "mirror", 6) == 0 ||
709b468a217Seschrock 	    strncmp(pool, "raidz", 5) == 0 ||
7108654d025Sperrin 	    strncmp(pool, "spare", 5) == 0 ||
7118654d025Sperrin 	    strcmp(pool, "log") == 0)) {
712e7cbe64fSgw 		if (hdl != NULL)
713e7cbe64fSgw 			zfs_error_aux(hdl,
714e7cbe64fSgw 			    dgettext(TEXT_DOMAIN, "name is reserved"));
71599653d4eSeschrock 		return (B_FALSE);
716b468a217Seschrock 	}
717b468a217Seschrock 
718fa9e4066Sahrens 
719b468a217Seschrock 	if (ret != 0) {
72099653d4eSeschrock 		if (hdl != NULL) {
721fa9e4066Sahrens 			switch (why) {
722b81d61a6Slling 			case NAME_ERR_TOOLONG:
72399653d4eSeschrock 				zfs_error_aux(hdl,
724b81d61a6Slling 				    dgettext(TEXT_DOMAIN, "name is too long"));
725b81d61a6Slling 				break;
726b81d61a6Slling 
727fa9e4066Sahrens 			case NAME_ERR_INVALCHAR:
72899653d4eSeschrock 				zfs_error_aux(hdl,
729fa9e4066Sahrens 				    dgettext(TEXT_DOMAIN, "invalid character "
730fa9e4066Sahrens 				    "'%c' in pool name"), what);
731fa9e4066Sahrens 				break;
732fa9e4066Sahrens 
733fa9e4066Sahrens 			case NAME_ERR_NOLETTER:
73499653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
73599653d4eSeschrock 				    "name must begin with a letter"));
736fa9e4066Sahrens 				break;
737fa9e4066Sahrens 
738fa9e4066Sahrens 			case NAME_ERR_RESERVED:
73999653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
74099653d4eSeschrock 				    "name is reserved"));
741fa9e4066Sahrens 				break;
742fa9e4066Sahrens 
743fa9e4066Sahrens 			case NAME_ERR_DISKLIKE:
74499653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
74599653d4eSeschrock 				    "pool name is reserved"));
746fa9e4066Sahrens 				break;
7475ad82045Snd 
7485ad82045Snd 			case NAME_ERR_LEADING_SLASH:
7495ad82045Snd 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
7505ad82045Snd 				    "leading slash in name"));
7515ad82045Snd 				break;
7525ad82045Snd 
7535ad82045Snd 			case NAME_ERR_EMPTY_COMPONENT:
7545ad82045Snd 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
7555ad82045Snd 				    "empty component in name"));
7565ad82045Snd 				break;
7575ad82045Snd 
7585ad82045Snd 			case NAME_ERR_TRAILING_SLASH:
7595ad82045Snd 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
7605ad82045Snd 				    "trailing slash in name"));
7615ad82045Snd 				break;
7625ad82045Snd 
7635ad82045Snd 			case NAME_ERR_MULTIPLE_AT:
7645ad82045Snd 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
7655ad82045Snd 				    "multiple '@' delimiters in name"));
7665ad82045Snd 				break;
7675ad82045Snd 
768fa9e4066Sahrens 			}
769fa9e4066Sahrens 		}
77099653d4eSeschrock 		return (B_FALSE);
771fa9e4066Sahrens 	}
772fa9e4066Sahrens 
77399653d4eSeschrock 	return (B_TRUE);
774fa9e4066Sahrens }
775fa9e4066Sahrens 
776fa9e4066Sahrens /*
777fa9e4066Sahrens  * Open a handle to the given pool, even if the pool is currently in the FAULTED
778fa9e4066Sahrens  * state.
779fa9e4066Sahrens  */
780fa9e4066Sahrens zpool_handle_t *
78199653d4eSeschrock zpool_open_canfail(libzfs_handle_t *hdl, const char *pool)
782fa9e4066Sahrens {
783fa9e4066Sahrens 	zpool_handle_t *zhp;
78494de1d4cSeschrock 	boolean_t missing;
785fa9e4066Sahrens 
786fa9e4066Sahrens 	/*
787fa9e4066Sahrens 	 * Make sure the pool name is valid.
788fa9e4066Sahrens 	 */
78999653d4eSeschrock 	if (!zpool_name_valid(hdl, B_TRUE, pool)) {
790ece3d9b3Slling 		(void) zfs_error_fmt(hdl, EZFS_INVALIDNAME,
79199653d4eSeschrock 		    dgettext(TEXT_DOMAIN, "cannot open '%s'"),
79299653d4eSeschrock 		    pool);
793fa9e4066Sahrens 		return (NULL);
794fa9e4066Sahrens 	}
795fa9e4066Sahrens 
79699653d4eSeschrock 	if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL)
79799653d4eSeschrock 		return (NULL);
798fa9e4066Sahrens 
79999653d4eSeschrock 	zhp->zpool_hdl = hdl;
800fa9e4066Sahrens 	(void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name));
801fa9e4066Sahrens 
80294de1d4cSeschrock 	if (zpool_refresh_stats(zhp, &missing) != 0) {
80394de1d4cSeschrock 		zpool_close(zhp);
80494de1d4cSeschrock 		return (NULL);
80594de1d4cSeschrock 	}
80694de1d4cSeschrock 
80794de1d4cSeschrock 	if (missing) {
808990b4856Slling 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "no such pool"));
809ece3d9b3Slling 		(void) zfs_error_fmt(hdl, EZFS_NOENT,
810990b4856Slling 		    dgettext(TEXT_DOMAIN, "cannot open '%s'"), pool);
81194de1d4cSeschrock 		zpool_close(zhp);
81294de1d4cSeschrock 		return (NULL);
813fa9e4066Sahrens 	}
814fa9e4066Sahrens 
815fa9e4066Sahrens 	return (zhp);
816fa9e4066Sahrens }
817fa9e4066Sahrens 
818fa9e4066Sahrens /*
819fa9e4066Sahrens  * Like the above, but silent on error.  Used when iterating over pools (because
820fa9e4066Sahrens  * the configuration cache may be out of date).
821fa9e4066Sahrens  */
82294de1d4cSeschrock int
82394de1d4cSeschrock zpool_open_silent(libzfs_handle_t *hdl, const char *pool, zpool_handle_t **ret)
824fa9e4066Sahrens {
825fa9e4066Sahrens 	zpool_handle_t *zhp;
82694de1d4cSeschrock 	boolean_t missing;
827fa9e4066Sahrens 
82894de1d4cSeschrock 	if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL)
82994de1d4cSeschrock 		return (-1);
830fa9e4066Sahrens 
83199653d4eSeschrock 	zhp->zpool_hdl = hdl;
832fa9e4066Sahrens 	(void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name));
833fa9e4066Sahrens 
83494de1d4cSeschrock 	if (zpool_refresh_stats(zhp, &missing) != 0) {
83594de1d4cSeschrock 		zpool_close(zhp);
83694de1d4cSeschrock 		return (-1);
837fa9e4066Sahrens 	}
838fa9e4066Sahrens 
83994de1d4cSeschrock 	if (missing) {
84094de1d4cSeschrock 		zpool_close(zhp);
84194de1d4cSeschrock 		*ret = NULL;
84294de1d4cSeschrock 		return (0);
84394de1d4cSeschrock 	}
84494de1d4cSeschrock 
84594de1d4cSeschrock 	*ret = zhp;
84694de1d4cSeschrock 	return (0);
847fa9e4066Sahrens }
848fa9e4066Sahrens 
849fa9e4066Sahrens /*
850fa9e4066Sahrens  * Similar to zpool_open_canfail(), but refuses to open pools in the faulted
851fa9e4066Sahrens  * state.
852fa9e4066Sahrens  */
853fa9e4066Sahrens zpool_handle_t *
85499653d4eSeschrock zpool_open(libzfs_handle_t *hdl, const char *pool)
855fa9e4066Sahrens {
856fa9e4066Sahrens 	zpool_handle_t *zhp;
857fa9e4066Sahrens 
85899653d4eSeschrock 	if ((zhp = zpool_open_canfail(hdl, pool)) == NULL)
859fa9e4066Sahrens 		return (NULL);
860fa9e4066Sahrens 
861fa9e4066Sahrens 	if (zhp->zpool_state == POOL_STATE_UNAVAIL) {
862ece3d9b3Slling 		(void) zfs_error_fmt(hdl, EZFS_POOLUNAVAIL,
86399653d4eSeschrock 		    dgettext(TEXT_DOMAIN, "cannot open '%s'"), zhp->zpool_name);
864fa9e4066Sahrens 		zpool_close(zhp);
865fa9e4066Sahrens 		return (NULL);
866fa9e4066Sahrens 	}
867fa9e4066Sahrens 
868fa9e4066Sahrens 	return (zhp);
869fa9e4066Sahrens }
870fa9e4066Sahrens 
871fa9e4066Sahrens /*
872fa9e4066Sahrens  * Close the handle.  Simply frees the memory associated with the handle.
873fa9e4066Sahrens  */
874fa9e4066Sahrens void
875fa9e4066Sahrens zpool_close(zpool_handle_t *zhp)
876fa9e4066Sahrens {
877fa9e4066Sahrens 	if (zhp->zpool_config)
878fa9e4066Sahrens 		nvlist_free(zhp->zpool_config);
879088e9d47Seschrock 	if (zhp->zpool_old_config)
880088e9d47Seschrock 		nvlist_free(zhp->zpool_old_config);
881b1b8ab34Slling 	if (zhp->zpool_props)
882b1b8ab34Slling 		nvlist_free(zhp->zpool_props);
883fa9e4066Sahrens 	free(zhp);
884fa9e4066Sahrens }
885fa9e4066Sahrens 
886fa9e4066Sahrens /*
887fa9e4066Sahrens  * Return the name of the pool.
888fa9e4066Sahrens  */
889fa9e4066Sahrens const char *
890fa9e4066Sahrens zpool_get_name(zpool_handle_t *zhp)
891fa9e4066Sahrens {
892fa9e4066Sahrens 	return (zhp->zpool_name);
893fa9e4066Sahrens }
894fa9e4066Sahrens 
895fa9e4066Sahrens 
896fa9e4066Sahrens /*
897fa9e4066Sahrens  * Return the state of the pool (ACTIVE or UNAVAILABLE)
898fa9e4066Sahrens  */
899fa9e4066Sahrens int
900fa9e4066Sahrens zpool_get_state(zpool_handle_t *zhp)
901fa9e4066Sahrens {
902fa9e4066Sahrens 	return (zhp->zpool_state);
903fa9e4066Sahrens }
904fa9e4066Sahrens 
905fa9e4066Sahrens /*
906fa9e4066Sahrens  * Create the named pool, using the provided vdev list.  It is assumed
907fa9e4066Sahrens  * that the consumer has already validated the contents of the nvlist, so we
908fa9e4066Sahrens  * don't have to worry about error semantics.
909fa9e4066Sahrens  */
910fa9e4066Sahrens int
91199653d4eSeschrock zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot,
9120a48a24eStimh     nvlist_t *props, nvlist_t *fsprops)
913fa9e4066Sahrens {
914fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
9150a48a24eStimh 	nvlist_t *zc_fsprops = NULL;
9160a48a24eStimh 	nvlist_t *zc_props = NULL;
91799653d4eSeschrock 	char msg[1024];
918990b4856Slling 	char *altroot;
9190a48a24eStimh 	int ret = -1;
920fa9e4066Sahrens 
92199653d4eSeschrock 	(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
92299653d4eSeschrock 	    "cannot create '%s'"), pool);
923fa9e4066Sahrens 
92499653d4eSeschrock 	if (!zpool_name_valid(hdl, B_FALSE, pool))
92599653d4eSeschrock 		return (zfs_error(hdl, EZFS_INVALIDNAME, msg));
926fa9e4066Sahrens 
927351420b3Slling 	if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0)
928990b4856Slling 		return (-1);
929fa9e4066Sahrens 
9300a48a24eStimh 	if (props) {
9310a48a24eStimh 		if ((zc_props = zpool_valid_proplist(hdl, pool, props,
9320a48a24eStimh 		    SPA_VERSION_1, B_TRUE, msg)) == NULL) {
9330a48a24eStimh 			goto create_failed;
9340a48a24eStimh 		}
9350a48a24eStimh 	}
93699653d4eSeschrock 
9370a48a24eStimh 	if (fsprops) {
9380a48a24eStimh 		uint64_t zoned;
9390a48a24eStimh 		char *zonestr;
9400a48a24eStimh 
9410a48a24eStimh 		zoned = ((nvlist_lookup_string(fsprops,
9420a48a24eStimh 		    zfs_prop_to_name(ZFS_PROP_ZONED), &zonestr) == 0) &&
9430a48a24eStimh 		    strcmp(zonestr, "on") == 0);
9440a48a24eStimh 
9450a48a24eStimh 		if ((zc_fsprops = zfs_valid_proplist(hdl,
9460a48a24eStimh 		    ZFS_TYPE_FILESYSTEM, fsprops, zoned, NULL, msg)) == NULL) {
9470a48a24eStimh 			goto create_failed;
9480a48a24eStimh 		}
9490a48a24eStimh 		if (!zc_props &&
9500a48a24eStimh 		    (nvlist_alloc(&zc_props, NV_UNIQUE_NAME, 0) != 0)) {
9510a48a24eStimh 			goto create_failed;
9520a48a24eStimh 		}
9530a48a24eStimh 		if (nvlist_add_nvlist(zc_props,
9540a48a24eStimh 		    ZPOOL_ROOTFS_PROPS, zc_fsprops) != 0) {
9550a48a24eStimh 			goto create_failed;
9560a48a24eStimh 		}
957351420b3Slling 	}
958fa9e4066Sahrens 
9590a48a24eStimh 	if (zc_props && zcmd_write_src_nvlist(hdl, &zc, zc_props) != 0)
9600a48a24eStimh 		goto create_failed;
9610a48a24eStimh 
962990b4856Slling 	(void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name));
963fa9e4066Sahrens 
9640a48a24eStimh 	if ((ret = zfs_ioctl(hdl, ZFS_IOC_POOL_CREATE, &zc)) != 0) {
965351420b3Slling 
966e9dbad6fSeschrock 		zcmd_free_nvlists(&zc);
9670a48a24eStimh 		nvlist_free(zc_props);
9680a48a24eStimh 		nvlist_free(zc_fsprops);
969fa9e4066Sahrens 
97099653d4eSeschrock 		switch (errno) {
971fa9e4066Sahrens 		case EBUSY:
972fa9e4066Sahrens 			/*
973fa9e4066Sahrens 			 * This can happen if the user has specified the same
974fa9e4066Sahrens 			 * device multiple times.  We can't reliably detect this
975fa9e4066Sahrens 			 * until we try to add it and see we already have a
976fa9e4066Sahrens 			 * label.
977fa9e4066Sahrens 			 */
97899653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
97999653d4eSeschrock 			    "one or more vdevs refer to the same device"));
98099653d4eSeschrock 			return (zfs_error(hdl, EZFS_BADDEV, msg));
981fa9e4066Sahrens 
982fa9e4066Sahrens 		case EOVERFLOW:
983fa9e4066Sahrens 			/*
98499653d4eSeschrock 			 * This occurs when one of the devices is below
985fa9e4066Sahrens 			 * SPA_MINDEVSIZE.  Unfortunately, we can't detect which
986fa9e4066Sahrens 			 * device was the problem device since there's no
987fa9e4066Sahrens 			 * reliable way to determine device size from userland.
988fa9e4066Sahrens 			 */
989fa9e4066Sahrens 			{
990fa9e4066Sahrens 				char buf[64];
991fa9e4066Sahrens 
992fa9e4066Sahrens 				zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf));
993fa9e4066Sahrens 
99499653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
99599653d4eSeschrock 				    "one or more devices is less than the "
99699653d4eSeschrock 				    "minimum size (%s)"), buf);
997fa9e4066Sahrens 			}
99899653d4eSeschrock 			return (zfs_error(hdl, EZFS_BADDEV, msg));
999fa9e4066Sahrens 
1000fa9e4066Sahrens 		case ENOSPC:
100199653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
100299653d4eSeschrock 			    "one or more devices is out of space"));
100399653d4eSeschrock 			return (zfs_error(hdl, EZFS_BADDEV, msg));
1004fa9e4066Sahrens 
1005fa94a07fSbrendan 		case ENOTBLK:
1006fa94a07fSbrendan 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1007fa94a07fSbrendan 			    "cache device must be a disk or disk slice"));
1008fa94a07fSbrendan 			return (zfs_error(hdl, EZFS_BADDEV, msg));
1009fa94a07fSbrendan 
1010fa9e4066Sahrens 		default:
101199653d4eSeschrock 			return (zpool_standard_error(hdl, errno, msg));
1012fa9e4066Sahrens 		}
1013fa9e4066Sahrens 	}
1014fa9e4066Sahrens 
1015fa9e4066Sahrens 	/*
1016fa9e4066Sahrens 	 * If this is an alternate root pool, then we automatically set the
1017e9dbad6fSeschrock 	 * mountpoint of the root dataset to be '/'.
1018fa9e4066Sahrens 	 */
1019990b4856Slling 	if (nvlist_lookup_string(props, zpool_prop_to_name(ZPOOL_PROP_ALTROOT),
1020990b4856Slling 	    &altroot) == 0) {
1021fa9e4066Sahrens 		zfs_handle_t *zhp;
1022fa9e4066Sahrens 
1023990b4856Slling 		verify((zhp = zfs_open(hdl, pool, ZFS_TYPE_DATASET)) != NULL);
1024e9dbad6fSeschrock 		verify(zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
1025e9dbad6fSeschrock 		    "/") == 0);
1026fa9e4066Sahrens 
1027fa9e4066Sahrens 		zfs_close(zhp);
1028fa9e4066Sahrens 	}
1029fa9e4066Sahrens 
10300a48a24eStimh create_failed:
1031351420b3Slling 	zcmd_free_nvlists(&zc);
10320a48a24eStimh 	nvlist_free(zc_props);
10330a48a24eStimh 	nvlist_free(zc_fsprops);
10340a48a24eStimh 	return (ret);
1035fa9e4066Sahrens }
1036fa9e4066Sahrens 
1037fa9e4066Sahrens /*
1038fa9e4066Sahrens  * Destroy the given pool.  It is up to the caller to ensure that there are no
1039fa9e4066Sahrens  * datasets left in the pool.
1040fa9e4066Sahrens  */
1041fa9e4066Sahrens int
1042fa9e4066Sahrens zpool_destroy(zpool_handle_t *zhp)
1043fa9e4066Sahrens {
1044fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
1045fa9e4066Sahrens 	zfs_handle_t *zfp = NULL;
104699653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
104799653d4eSeschrock 	char msg[1024];
1048fa9e4066Sahrens 
1049fa9e4066Sahrens 	if (zhp->zpool_state == POOL_STATE_ACTIVE &&
105099653d4eSeschrock 	    (zfp = zfs_open(zhp->zpool_hdl, zhp->zpool_name,
105199653d4eSeschrock 	    ZFS_TYPE_FILESYSTEM)) == NULL)
1052fa9e4066Sahrens 		return (-1);
1053fa9e4066Sahrens 
1054fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
1055fa9e4066Sahrens 
1056ecd6cf80Smarks 	if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_DESTROY, &zc) != 0) {
105799653d4eSeschrock 		(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
105899653d4eSeschrock 		    "cannot destroy '%s'"), zhp->zpool_name);
1059fa9e4066Sahrens 
106099653d4eSeschrock 		if (errno == EROFS) {
106199653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
106299653d4eSeschrock 			    "one or more devices is read only"));
106399653d4eSeschrock 			(void) zfs_error(hdl, EZFS_BADDEV, msg);
106499653d4eSeschrock 		} else {
106599653d4eSeschrock 			(void) zpool_standard_error(hdl, errno, msg);
1066fa9e4066Sahrens 		}
1067fa9e4066Sahrens 
1068fa9e4066Sahrens 		if (zfp)
1069fa9e4066Sahrens 			zfs_close(zfp);
1070fa9e4066Sahrens 		return (-1);
1071fa9e4066Sahrens 	}
1072fa9e4066Sahrens 
1073fa9e4066Sahrens 	if (zfp) {
1074fa9e4066Sahrens 		remove_mountpoint(zfp);
1075fa9e4066Sahrens 		zfs_close(zfp);
1076fa9e4066Sahrens 	}
1077fa9e4066Sahrens 
1078fa9e4066Sahrens 	return (0);
1079fa9e4066Sahrens }
1080fa9e4066Sahrens 
1081fa9e4066Sahrens /*
1082fa9e4066Sahrens  * Add the given vdevs to the pool.  The caller must have already performed the
1083fa9e4066Sahrens  * necessary verification to ensure that the vdev specification is well-formed.
1084fa9e4066Sahrens  */
1085fa9e4066Sahrens int
1086fa9e4066Sahrens zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot)
1087fa9e4066Sahrens {
1088e9dbad6fSeschrock 	zfs_cmd_t zc = { 0 };
108999653d4eSeschrock 	int ret;
109099653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
109199653d4eSeschrock 	char msg[1024];
1092fa94a07fSbrendan 	nvlist_t **spares, **l2cache;
1093fa94a07fSbrendan 	uint_t nspares, nl2cache;
109499653d4eSeschrock 
109599653d4eSeschrock 	(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
109699653d4eSeschrock 	    "cannot add to '%s'"), zhp->zpool_name);
109799653d4eSeschrock 
1098fa94a07fSbrendan 	if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) <
1099fa94a07fSbrendan 	    SPA_VERSION_SPARES &&
110099653d4eSeschrock 	    nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
110199653d4eSeschrock 	    &spares, &nspares) == 0) {
110299653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be "
110399653d4eSeschrock 		    "upgraded to add hot spares"));
110499653d4eSeschrock 		return (zfs_error(hdl, EZFS_BADVERSION, msg));
110599653d4eSeschrock 	}
1106fa9e4066Sahrens 
1107b5b76fecSGeorge Wilson 	if (pool_is_bootable(zhp) && nvlist_lookup_nvlist_array(nvroot,
1108b5b76fecSGeorge Wilson 	    ZPOOL_CONFIG_SPARES, &spares, &nspares) == 0) {
1109b5b76fecSGeorge Wilson 		uint64_t s;
1110b5b76fecSGeorge Wilson 
1111b5b76fecSGeorge Wilson 		for (s = 0; s < nspares; s++) {
1112b5b76fecSGeorge Wilson 			char *path;
1113b5b76fecSGeorge Wilson 
1114b5b76fecSGeorge Wilson 			if (nvlist_lookup_string(spares[s], ZPOOL_CONFIG_PATH,
1115b5b76fecSGeorge Wilson 			    &path) == 0 && pool_uses_efi(spares[s])) {
1116b5b76fecSGeorge Wilson 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1117b5b76fecSGeorge Wilson 				    "device '%s' contains an EFI label and "
1118b5b76fecSGeorge Wilson 				    "cannot be used on root pools."),
111988ecc943SGeorge Wilson 				    zpool_vdev_name(hdl, NULL, spares[s],
112088ecc943SGeorge Wilson 				    B_FALSE));
1121b5b76fecSGeorge Wilson 				return (zfs_error(hdl, EZFS_POOL_NOTSUP, msg));
1122b5b76fecSGeorge Wilson 			}
1123b5b76fecSGeorge Wilson 		}
1124b5b76fecSGeorge Wilson 	}
1125b5b76fecSGeorge Wilson 
1126fa94a07fSbrendan 	if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) <
1127fa94a07fSbrendan 	    SPA_VERSION_L2CACHE &&
1128fa94a07fSbrendan 	    nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
1129fa94a07fSbrendan 	    &l2cache, &nl2cache) == 0) {
1130fa94a07fSbrendan 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be "
1131fa94a07fSbrendan 		    "upgraded to add cache devices"));
1132fa94a07fSbrendan 		return (zfs_error(hdl, EZFS_BADVERSION, msg));
1133fa94a07fSbrendan 	}
1134fa94a07fSbrendan 
1135990b4856Slling 	if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0)
113699653d4eSeschrock 		return (-1);
1137fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
1138fa9e4066Sahrens 
1139ecd6cf80Smarks 	if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_ADD, &zc) != 0) {
1140fa9e4066Sahrens 		switch (errno) {
1141fa9e4066Sahrens 		case EBUSY:
1142fa9e4066Sahrens 			/*
1143fa9e4066Sahrens 			 * This can happen if the user has specified the same
1144fa9e4066Sahrens 			 * device multiple times.  We can't reliably detect this
1145fa9e4066Sahrens 			 * until we try to add it and see we already have a
1146fa9e4066Sahrens 			 * label.
1147fa9e4066Sahrens 			 */
114899653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
114999653d4eSeschrock 			    "one or more vdevs refer to the same device"));
115099653d4eSeschrock 			(void) zfs_error(hdl, EZFS_BADDEV, msg);
1151fa9e4066Sahrens 			break;
1152fa9e4066Sahrens 
1153fa9e4066Sahrens 		case EOVERFLOW:
1154fa9e4066Sahrens 			/*
1155fa9e4066Sahrens 			 * This occurrs when one of the devices is below
1156fa9e4066Sahrens 			 * SPA_MINDEVSIZE.  Unfortunately, we can't detect which
1157fa9e4066Sahrens 			 * device was the problem device since there's no
1158fa9e4066Sahrens 			 * reliable way to determine device size from userland.
1159fa9e4066Sahrens 			 */
1160fa9e4066Sahrens 			{
1161fa9e4066Sahrens 				char buf[64];
1162fa9e4066Sahrens 
1163fa9e4066Sahrens 				zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf));
1164fa9e4066Sahrens 
116599653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
116699653d4eSeschrock 				    "device is less than the minimum "
116799653d4eSeschrock 				    "size (%s)"), buf);
1168fa9e4066Sahrens 			}
116999653d4eSeschrock 			(void) zfs_error(hdl, EZFS_BADDEV, msg);
117099653d4eSeschrock 			break;
117199653d4eSeschrock 
117299653d4eSeschrock 		case ENOTSUP:
117399653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
11748654d025Sperrin 			    "pool must be upgraded to add these vdevs"));
117599653d4eSeschrock 			(void) zfs_error(hdl, EZFS_BADVERSION, msg);
1176fa9e4066Sahrens 			break;
1177fa9e4066Sahrens 
1178b1b8ab34Slling 		case EDOM:
1179b1b8ab34Slling 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
11808654d025Sperrin 			    "root pool can not have multiple vdevs"
11818654d025Sperrin 			    " or separate logs"));
1182b1b8ab34Slling 			(void) zfs_error(hdl, EZFS_POOL_NOTSUP, msg);
1183b1b8ab34Slling 			break;
1184b1b8ab34Slling 
1185fa94a07fSbrendan 		case ENOTBLK:
1186fa94a07fSbrendan 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1187fa94a07fSbrendan 			    "cache device must be a disk or disk slice"));
1188fa94a07fSbrendan 			(void) zfs_error(hdl, EZFS_BADDEV, msg);
1189fa94a07fSbrendan 			break;
1190fa94a07fSbrendan 
1191fa9e4066Sahrens 		default:
119299653d4eSeschrock 			(void) zpool_standard_error(hdl, errno, msg);
1193fa9e4066Sahrens 		}
1194fa9e4066Sahrens 
119599653d4eSeschrock 		ret = -1;
119699653d4eSeschrock 	} else {
119799653d4eSeschrock 		ret = 0;
1198fa9e4066Sahrens 	}
1199fa9e4066Sahrens 
1200e9dbad6fSeschrock 	zcmd_free_nvlists(&zc);
1201fa9e4066Sahrens 
120299653d4eSeschrock 	return (ret);
1203fa9e4066Sahrens }
1204fa9e4066Sahrens 
1205fa9e4066Sahrens /*
1206fa9e4066Sahrens  * Exports the pool from the system.  The caller must ensure that there are no
1207fa9e4066Sahrens  * mounted datasets in the pool.
1208fa9e4066Sahrens  */
1209fa9e4066Sahrens int
1210394ab0cbSGeorge Wilson zpool_export_common(zpool_handle_t *zhp, boolean_t force, boolean_t hardforce)
1211fa9e4066Sahrens {
1212fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
121389a89ebfSlling 	char msg[1024];
1214fa9e4066Sahrens 
121589a89ebfSlling 	(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
121689a89ebfSlling 	    "cannot export '%s'"), zhp->zpool_name);
121789a89ebfSlling 
1218fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
121989a89ebfSlling 	zc.zc_cookie = force;
1220394ab0cbSGeorge Wilson 	zc.zc_guid = hardforce;
122189a89ebfSlling 
122289a89ebfSlling 	if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_EXPORT, &zc) != 0) {
122389a89ebfSlling 		switch (errno) {
122489a89ebfSlling 		case EXDEV:
122589a89ebfSlling 			zfs_error_aux(zhp->zpool_hdl, dgettext(TEXT_DOMAIN,
122689a89ebfSlling 			    "use '-f' to override the following errors:\n"
122789a89ebfSlling 			    "'%s' has an active shared spare which could be"
122889a89ebfSlling 			    " used by other pools once '%s' is exported."),
122989a89ebfSlling 			    zhp->zpool_name, zhp->zpool_name);
123089a89ebfSlling 			return (zfs_error(zhp->zpool_hdl, EZFS_ACTIVE_SPARE,
123189a89ebfSlling 			    msg));
123289a89ebfSlling 		default:
123389a89ebfSlling 			return (zpool_standard_error_fmt(zhp->zpool_hdl, errno,
123489a89ebfSlling 			    msg));
123589a89ebfSlling 		}
123689a89ebfSlling 	}
1237fa9e4066Sahrens 
1238fa9e4066Sahrens 	return (0);
1239fa9e4066Sahrens }
1240fa9e4066Sahrens 
1241394ab0cbSGeorge Wilson int
1242394ab0cbSGeorge Wilson zpool_export(zpool_handle_t *zhp, boolean_t force)
1243394ab0cbSGeorge Wilson {
1244394ab0cbSGeorge Wilson 	return (zpool_export_common(zhp, force, B_FALSE));
1245394ab0cbSGeorge Wilson }
1246394ab0cbSGeorge Wilson 
1247394ab0cbSGeorge Wilson int
1248394ab0cbSGeorge Wilson zpool_export_force(zpool_handle_t *zhp)
1249394ab0cbSGeorge Wilson {
1250394ab0cbSGeorge Wilson 	return (zpool_export_common(zhp, B_TRUE, B_TRUE));
1251394ab0cbSGeorge Wilson }
1252394ab0cbSGeorge Wilson 
1253468c413aSTim Haley static void
1254468c413aSTim Haley zpool_rewind_exclaim(libzfs_handle_t *hdl, const char *name, boolean_t dryrun,
1255468c413aSTim Haley     nvlist_t *rbi)
1256468c413aSTim Haley {
1257468c413aSTim Haley 	uint64_t rewindto;
1258468c413aSTim Haley 	int64_t loss = -1;
1259468c413aSTim Haley 	struct tm t;
1260468c413aSTim Haley 	char timestr[128];
1261468c413aSTim Haley 
1262468c413aSTim Haley 	if (!hdl->libzfs_printerr || rbi == NULL)
1263468c413aSTim Haley 		return;
1264468c413aSTim Haley 
1265468c413aSTim Haley 	if (nvlist_lookup_uint64(rbi, ZPOOL_CONFIG_LOAD_TIME, &rewindto) != 0)
1266468c413aSTim Haley 		return;
1267468c413aSTim Haley 	(void) nvlist_lookup_int64(rbi, ZPOOL_CONFIG_REWIND_TIME, &loss);
1268468c413aSTim Haley 
1269468c413aSTim Haley 	if (localtime_r((time_t *)&rewindto, &t) != NULL &&
1270468c413aSTim Haley 	    strftime(timestr, 128, 0, &t) != 0) {
1271468c413aSTim Haley 		if (dryrun) {
1272468c413aSTim Haley 			(void) printf(dgettext(TEXT_DOMAIN,
1273468c413aSTim Haley 			    "Would be able to return %s "
1274468c413aSTim Haley 			    "to its state as of %s.\n"),
1275468c413aSTim Haley 			    name, timestr);
1276468c413aSTim Haley 		} else {
1277468c413aSTim Haley 			(void) printf(dgettext(TEXT_DOMAIN,
1278468c413aSTim Haley 			    "Pool %s returned to its state as of %s.\n"),
1279468c413aSTim Haley 			    name, timestr);
1280468c413aSTim Haley 		}
1281468c413aSTim Haley 		if (loss > 120) {
1282468c413aSTim Haley 			(void) printf(dgettext(TEXT_DOMAIN,
1283468c413aSTim Haley 			    "%s approximately %lld "),
1284468c413aSTim Haley 			    dryrun ? "Would discard" : "Discarded",
1285468c413aSTim Haley 			    (loss + 30) / 60);
1286468c413aSTim Haley 			(void) printf(dgettext(TEXT_DOMAIN,
1287468c413aSTim Haley 			    "minutes of transactions.\n"));
1288468c413aSTim Haley 		} else if (loss > 0) {
1289468c413aSTim Haley 			(void) printf(dgettext(TEXT_DOMAIN,
1290468c413aSTim Haley 			    "%s approximately %lld "),
1291468c413aSTim Haley 			    dryrun ? "Would discard" : "Discarded", loss);
1292468c413aSTim Haley 			(void) printf(dgettext(TEXT_DOMAIN,
1293468c413aSTim Haley 			    "seconds of transactions.\n"));
1294468c413aSTim Haley 		}
1295468c413aSTim Haley 	}
1296468c413aSTim Haley }
1297468c413aSTim Haley 
1298468c413aSTim Haley void
1299468c413aSTim Haley zpool_explain_recover(libzfs_handle_t *hdl, const char *name, int reason,
1300468c413aSTim Haley     nvlist_t *config)
1301468c413aSTim Haley {
1302468c413aSTim Haley 	int64_t loss = -1;
1303468c413aSTim Haley 	uint64_t edata = UINT64_MAX;
1304468c413aSTim Haley 	uint64_t rewindto;
1305468c413aSTim Haley 	struct tm t;
1306468c413aSTim Haley 	char timestr[128];
1307468c413aSTim Haley 
1308468c413aSTim Haley 	if (!hdl->libzfs_printerr)
1309468c413aSTim Haley 		return;
1310468c413aSTim Haley 
1311468c413aSTim Haley 	if (reason >= 0)
1312468c413aSTim Haley 		(void) printf(dgettext(TEXT_DOMAIN, "action: "));
1313468c413aSTim Haley 	else
1314468c413aSTim Haley 		(void) printf(dgettext(TEXT_DOMAIN, "\t"));
1315468c413aSTim Haley 
1316468c413aSTim Haley 	/* All attempted rewinds failed if ZPOOL_CONFIG_LOAD_TIME missing */
1317468c413aSTim Haley 	if (nvlist_lookup_uint64(config,
1318468c413aSTim Haley 	    ZPOOL_CONFIG_LOAD_TIME, &rewindto) != 0)
1319468c413aSTim Haley 		goto no_info;
1320468c413aSTim Haley 
1321468c413aSTim Haley 	(void) nvlist_lookup_int64(config, ZPOOL_CONFIG_REWIND_TIME, &loss);
1322468c413aSTim Haley 	(void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_LOAD_DATA_ERRORS,
1323468c413aSTim Haley 	    &edata);
1324468c413aSTim Haley 
1325468c413aSTim Haley 	(void) printf(dgettext(TEXT_DOMAIN,
1326468c413aSTim Haley 	    "Recovery is possible, but will result in some data loss.\n"));
1327468c413aSTim Haley 
1328468c413aSTim Haley 	if (localtime_r((time_t *)&rewindto, &t) != NULL &&
1329468c413aSTim Haley 	    strftime(timestr, 128, 0, &t) != 0) {
1330468c413aSTim Haley 		(void) printf(dgettext(TEXT_DOMAIN,
1331468c413aSTim Haley 		    "\tReturning the pool to its state as of %s\n"
1332468c413aSTim Haley 		    "\tshould correct the problem.  "),
1333468c413aSTim Haley 		    timestr);
1334468c413aSTim Haley 	} else {
1335468c413aSTim Haley 		(void) printf(dgettext(TEXT_DOMAIN,
1336468c413aSTim Haley 		    "\tReverting the pool to an earlier state "
1337468c413aSTim Haley 		    "should correct the problem.\n\t"));
1338468c413aSTim Haley 	}
1339468c413aSTim Haley 
1340468c413aSTim Haley 	if (loss > 120) {
1341468c413aSTim Haley 		(void) printf(dgettext(TEXT_DOMAIN,
1342468c413aSTim Haley 		    "Approximately %lld minutes of data\n"
1343468c413aSTim Haley 		    "\tmust be discarded, irreversibly.  "), (loss + 30) / 60);
1344468c413aSTim Haley 	} else if (loss > 0) {
1345468c413aSTim Haley 		(void) printf(dgettext(TEXT_DOMAIN,
1346468c413aSTim Haley 		    "Approximately %lld seconds of data\n"
1347468c413aSTim Haley 		    "\tmust be discarded, irreversibly.  "), loss);
1348468c413aSTim Haley 	}
1349468c413aSTim Haley 	if (edata != 0 && edata != UINT64_MAX) {
1350468c413aSTim Haley 		if (edata == 1) {
1351468c413aSTim Haley 			(void) printf(dgettext(TEXT_DOMAIN,
1352468c413aSTim Haley 			    "After rewind, at least\n"
1353468c413aSTim Haley 			    "\tone persistent user-data error will remain.  "));
1354468c413aSTim Haley 		} else {
1355468c413aSTim Haley 			(void) printf(dgettext(TEXT_DOMAIN,
1356468c413aSTim Haley 			    "After rewind, several\n"
1357468c413aSTim Haley 			    "\tpersistent user-data errors will remain.  "));
1358468c413aSTim Haley 		}
1359468c413aSTim Haley 	}
1360468c413aSTim Haley 	(void) printf(dgettext(TEXT_DOMAIN,
1361a33cae98STim Haley 	    "Recovery can be attempted\n\tby executing 'zpool %s -F %s'.  "),
1362a33cae98STim Haley 	    reason >= 0 ? "clear" : "import", name);
1363468c413aSTim Haley 
1364468c413aSTim Haley 	(void) printf(dgettext(TEXT_DOMAIN,
1365468c413aSTim Haley 	    "A scrub of the pool\n"
1366468c413aSTim Haley 	    "\tis strongly recommended after recovery.\n"));
1367468c413aSTim Haley 	return;
1368468c413aSTim Haley 
1369468c413aSTim Haley no_info:
1370468c413aSTim Haley 	(void) printf(dgettext(TEXT_DOMAIN,
1371468c413aSTim Haley 	    "Destroy and re-create the pool from\n\ta backup source.\n"));
1372468c413aSTim Haley }
1373468c413aSTim Haley 
1374fa9e4066Sahrens /*
1375990b4856Slling  * zpool_import() is a contracted interface. Should be kept the same
1376990b4856Slling  * if possible.
1377990b4856Slling  *
1378990b4856Slling  * Applications should use zpool_import_props() to import a pool with
1379990b4856Slling  * new properties value to be set.
1380fa9e4066Sahrens  */
1381fa9e4066Sahrens int
138299653d4eSeschrock zpool_import(libzfs_handle_t *hdl, nvlist_t *config, const char *newname,
1383990b4856Slling     char *altroot)
1384990b4856Slling {
1385990b4856Slling 	nvlist_t *props = NULL;
1386990b4856Slling 	int ret;
1387990b4856Slling 
1388990b4856Slling 	if (altroot != NULL) {
1389990b4856Slling 		if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) {
1390990b4856Slling 			return (zfs_error_fmt(hdl, EZFS_NOMEM,
1391990b4856Slling 			    dgettext(TEXT_DOMAIN, "cannot import '%s'"),
1392990b4856Slling 			    newname));
1393990b4856Slling 		}
1394990b4856Slling 
1395990b4856Slling 		if (nvlist_add_string(props,
1396352d8027SGeorge Wilson 		    zpool_prop_to_name(ZPOOL_PROP_ALTROOT), altroot) != 0 ||
1397352d8027SGeorge Wilson 		    nvlist_add_string(props,
1398352d8027SGeorge Wilson 		    zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), "none") != 0) {
1399990b4856Slling 			nvlist_free(props);
1400990b4856Slling 			return (zfs_error_fmt(hdl, EZFS_NOMEM,
1401990b4856Slling 			    dgettext(TEXT_DOMAIN, "cannot import '%s'"),
1402990b4856Slling 			    newname));
1403990b4856Slling 		}
1404990b4856Slling 	}
1405990b4856Slling 
1406c5904d13Seschrock 	ret = zpool_import_props(hdl, config, newname, props, B_FALSE);
1407990b4856Slling 	if (props)
1408990b4856Slling 		nvlist_free(props);
1409990b4856Slling 	return (ret);
1410990b4856Slling }
1411990b4856Slling 
1412990b4856Slling /*
1413990b4856Slling  * Import the given pool using the known configuration and a list of
1414990b4856Slling  * properties to be set. The configuration should have come from
1415990b4856Slling  * zpool_find_import(). The 'newname' parameters control whether the pool
1416990b4856Slling  * is imported with a different name.
1417990b4856Slling  */
1418990b4856Slling int
1419990b4856Slling zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname,
1420c5904d13Seschrock     nvlist_t *props, boolean_t importfaulted)
1421fa9e4066Sahrens {
1422e9dbad6fSeschrock 	zfs_cmd_t zc = { 0 };
1423468c413aSTim Haley 	zpool_rewind_policy_t policy;
1424468c413aSTim Haley 	nvlist_t *nvi = NULL;
1425fa9e4066Sahrens 	char *thename;
1426fa9e4066Sahrens 	char *origname;
1427468c413aSTim Haley 	uint64_t returned_size;
1428fa9e4066Sahrens 	int ret;
1429990b4856Slling 	char errbuf[1024];
1430fa9e4066Sahrens 
1431fa9e4066Sahrens 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1432fa9e4066Sahrens 	    &origname) == 0);
1433fa9e4066Sahrens 
1434990b4856Slling 	(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
1435990b4856Slling 	    "cannot import pool '%s'"), origname);
1436990b4856Slling 
1437fa9e4066Sahrens 	if (newname != NULL) {
143899653d4eSeschrock 		if (!zpool_name_valid(hdl, B_FALSE, newname))
1439ece3d9b3Slling 			return (zfs_error_fmt(hdl, EZFS_INVALIDNAME,
144099653d4eSeschrock 			    dgettext(TEXT_DOMAIN, "cannot import '%s'"),
144199653d4eSeschrock 			    newname));
1442fa9e4066Sahrens 		thename = (char *)newname;
1443fa9e4066Sahrens 	} else {
1444fa9e4066Sahrens 		thename = origname;
1445fa9e4066Sahrens 	}
1446fa9e4066Sahrens 
1447990b4856Slling 	if (props) {
1448990b4856Slling 		uint64_t version;
1449fa9e4066Sahrens 
1450990b4856Slling 		verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
1451990b4856Slling 		    &version) == 0);
1452fa9e4066Sahrens 
14530a48a24eStimh 		if ((props = zpool_valid_proplist(hdl, origname,
1454351420b3Slling 		    props, version, B_TRUE, errbuf)) == NULL) {
1455990b4856Slling 			return (-1);
1456351420b3Slling 		} else if (zcmd_write_src_nvlist(hdl, &zc, props) != 0) {
1457351420b3Slling 			nvlist_free(props);
1458990b4856Slling 			return (-1);
1459351420b3Slling 		}
1460990b4856Slling 	}
1461990b4856Slling 
1462990b4856Slling 	(void) strlcpy(zc.zc_name, thename, sizeof (zc.zc_name));
1463fa9e4066Sahrens 
1464fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
1465ea8dc4b6Seschrock 	    &zc.zc_guid) == 0);
1466fa9e4066Sahrens 
1467351420b3Slling 	if (zcmd_write_conf_nvlist(hdl, &zc, config) != 0) {
1468351420b3Slling 		nvlist_free(props);
146999653d4eSeschrock 		return (-1);
1470351420b3Slling 	}
1471468c413aSTim Haley 	returned_size =  zc.zc_nvlist_conf_size + 512;
1472468c413aSTim Haley 	if (zcmd_alloc_dst_nvlist(hdl, &zc, returned_size) != 0) {
1473468c413aSTim Haley 		nvlist_free(props);
1474468c413aSTim Haley 		return (-1);
1475468c413aSTim Haley 	}
1476fa9e4066Sahrens 
1477c5904d13Seschrock 	zc.zc_cookie = (uint64_t)importfaulted;
1478fa9e4066Sahrens 	ret = 0;
1479ecd6cf80Smarks 	if (zfs_ioctl(hdl, ZFS_IOC_POOL_IMPORT, &zc) != 0) {
1480fa9e4066Sahrens 		char desc[1024];
1481468c413aSTim Haley 
1482468c413aSTim Haley 		(void) zcmd_read_dst_nvlist(hdl, &zc, &nvi);
1483468c413aSTim Haley 		zpool_get_rewind_policy(config, &policy);
1484468c413aSTim Haley 		/*
1485468c413aSTim Haley 		 * Dry-run failed, but we print out what success
1486468c413aSTim Haley 		 * looks like if we found a best txg
1487468c413aSTim Haley 		 */
1488468c413aSTim Haley 		if ((policy.zrp_request & ZPOOL_TRY_REWIND) && nvi) {
1489468c413aSTim Haley 			zpool_rewind_exclaim(hdl, newname ? origname : thename,
1490468c413aSTim Haley 			    B_TRUE, nvi);
1491468c413aSTim Haley 			nvlist_free(nvi);
1492468c413aSTim Haley 			return (-1);
1493468c413aSTim Haley 		}
1494468c413aSTim Haley 
1495fa9e4066Sahrens 		if (newname == NULL)
1496fa9e4066Sahrens 			(void) snprintf(desc, sizeof (desc),
1497fa9e4066Sahrens 			    dgettext(TEXT_DOMAIN, "cannot import '%s'"),
1498fa9e4066Sahrens 			    thename);
1499fa9e4066Sahrens 		else
1500fa9e4066Sahrens 			(void) snprintf(desc, sizeof (desc),
1501fa9e4066Sahrens 			    dgettext(TEXT_DOMAIN, "cannot import '%s' as '%s'"),
1502fa9e4066Sahrens 			    origname, thename);
1503fa9e4066Sahrens 
1504fa9e4066Sahrens 		switch (errno) {
1505ea8dc4b6Seschrock 		case ENOTSUP:
1506ea8dc4b6Seschrock 			/*
1507ea8dc4b6Seschrock 			 * Unsupported version.
1508ea8dc4b6Seschrock 			 */
150999653d4eSeschrock 			(void) zfs_error(hdl, EZFS_BADVERSION, desc);
1510ea8dc4b6Seschrock 			break;
1511ea8dc4b6Seschrock 
1512b5989ec7Seschrock 		case EINVAL:
1513b5989ec7Seschrock 			(void) zfs_error(hdl, EZFS_INVALCONFIG, desc);
1514b5989ec7Seschrock 			break;
1515b5989ec7Seschrock 
1516fa9e4066Sahrens 		default:
1517468c413aSTim Haley 			(void) zcmd_read_dst_nvlist(hdl, &zc, &nvi);
151899653d4eSeschrock 			(void) zpool_standard_error(hdl, errno, desc);
1519468c413aSTim Haley 			zpool_explain_recover(hdl,
1520468c413aSTim Haley 			    newname ? origname : thename, -errno, nvi);
1521468c413aSTim Haley 			nvlist_free(nvi);
1522468c413aSTim Haley 			break;
1523fa9e4066Sahrens 		}
1524fa9e4066Sahrens 
1525fa9e4066Sahrens 		ret = -1;
1526fa9e4066Sahrens 	} else {
1527fa9e4066Sahrens 		zpool_handle_t *zhp;
1528ecd6cf80Smarks 
1529fa9e4066Sahrens 		/*
1530fa9e4066Sahrens 		 * This should never fail, but play it safe anyway.
1531fa9e4066Sahrens 		 */
1532681d9761SEric Taylor 		if (zpool_open_silent(hdl, thename, &zhp) != 0)
153394de1d4cSeschrock 			ret = -1;
1534681d9761SEric Taylor 		else if (zhp != NULL)
1535fa9e4066Sahrens 			zpool_close(zhp);
1536468c413aSTim Haley 		(void) zcmd_read_dst_nvlist(hdl, &zc, &nvi);
1537468c413aSTim Haley 		zpool_get_rewind_policy(config, &policy);
1538468c413aSTim Haley 		if (policy.zrp_request &
1539468c413aSTim Haley 		    (ZPOOL_DO_REWIND | ZPOOL_TRY_REWIND)) {
1540468c413aSTim Haley 			zpool_rewind_exclaim(hdl, newname ? origname : thename,
1541468c413aSTim Haley 			    ((policy.zrp_request & ZPOOL_TRY_REWIND) != 0),
1542468c413aSTim Haley 			    nvi);
1543468c413aSTim Haley 		}
1544468c413aSTim Haley 		nvlist_free(nvi);
1545468c413aSTim Haley 		return (0);
1546fa9e4066Sahrens 	}
1547fa9e4066Sahrens 
1548e9dbad6fSeschrock 	zcmd_free_nvlists(&zc);
1549351420b3Slling 	nvlist_free(props);
1550351420b3Slling 
1551fa9e4066Sahrens 	return (ret);
1552fa9e4066Sahrens }
1553fa9e4066Sahrens 
1554fa9e4066Sahrens /*
1555fa9e4066Sahrens  * Scrub the pool.
1556fa9e4066Sahrens  */
1557fa9e4066Sahrens int
1558fa9e4066Sahrens zpool_scrub(zpool_handle_t *zhp, pool_scrub_type_t type)
1559fa9e4066Sahrens {
1560fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
1561fa9e4066Sahrens 	char msg[1024];
156299653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
1563fa9e4066Sahrens 
1564fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
1565fa9e4066Sahrens 	zc.zc_cookie = type;
1566fa9e4066Sahrens 
1567ecd6cf80Smarks 	if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_SCRUB, &zc) == 0)
1568fa9e4066Sahrens 		return (0);
1569fa9e4066Sahrens 
1570fa9e4066Sahrens 	(void) snprintf(msg, sizeof (msg),
1571fa9e4066Sahrens 	    dgettext(TEXT_DOMAIN, "cannot scrub %s"), zc.zc_name);
1572fa9e4066Sahrens 
157399653d4eSeschrock 	if (errno == EBUSY)
157499653d4eSeschrock 		return (zfs_error(hdl, EZFS_RESILVERING, msg));
157599653d4eSeschrock 	else
157699653d4eSeschrock 		return (zpool_standard_error(hdl, errno, msg));
1577fa9e4066Sahrens }
1578fa9e4066Sahrens 
1579a43d325bSek /*
1580573ca77eSGeorge Wilson  * Find a vdev that matches the search criteria specified. We use the
1581573ca77eSGeorge Wilson  * the nvpair name to determine how we should look for the device.
1582a43d325bSek  * 'avail_spare' is set to TRUE if the provided guid refers to an AVAIL
1583a43d325bSek  * spare; but FALSE if its an INUSE spare.
1584a43d325bSek  */
158599653d4eSeschrock static nvlist_t *
1586573ca77eSGeorge Wilson vdev_to_nvlist_iter(nvlist_t *nv, nvlist_t *search, boolean_t *avail_spare,
1587573ca77eSGeorge Wilson     boolean_t *l2cache, boolean_t *log)
1588ea8dc4b6Seschrock {
1589ea8dc4b6Seschrock 	uint_t c, children;
1590ea8dc4b6Seschrock 	nvlist_t **child;
159199653d4eSeschrock 	nvlist_t *ret;
1592ee0eb9f2SEric Schrock 	uint64_t is_log;
1593573ca77eSGeorge Wilson 	char *srchkey;
1594573ca77eSGeorge Wilson 	nvpair_t *pair = nvlist_next_nvpair(search, NULL);
1595573ca77eSGeorge Wilson 
1596573ca77eSGeorge Wilson 	/* Nothing to look for */
1597573ca77eSGeorge Wilson 	if (search == NULL || pair == NULL)
1598573ca77eSGeorge Wilson 		return (NULL);
1599ea8dc4b6Seschrock 
1600573ca77eSGeorge Wilson 	/* Obtain the key we will use to search */
1601573ca77eSGeorge Wilson 	srchkey = nvpair_name(pair);
1602573ca77eSGeorge Wilson 
1603573ca77eSGeorge Wilson 	switch (nvpair_type(pair)) {
1604573ca77eSGeorge Wilson 	case DATA_TYPE_UINT64: {
1605573ca77eSGeorge Wilson 		uint64_t srchval, theguid, present;
1606573ca77eSGeorge Wilson 
1607573ca77eSGeorge Wilson 		verify(nvpair_value_uint64(pair, &srchval) == 0);
1608573ca77eSGeorge Wilson 		if (strcmp(srchkey, ZPOOL_CONFIG_GUID) == 0) {
1609573ca77eSGeorge Wilson 			if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT,
1610573ca77eSGeorge Wilson 			    &present) == 0) {
1611573ca77eSGeorge Wilson 				/*
1612573ca77eSGeorge Wilson 				 * If the device has never been present since
1613573ca77eSGeorge Wilson 				 * import, the only reliable way to match the
1614573ca77eSGeorge Wilson 				 * vdev is by GUID.
1615573ca77eSGeorge Wilson 				 */
1616573ca77eSGeorge Wilson 				verify(nvlist_lookup_uint64(nv,
1617573ca77eSGeorge Wilson 				    ZPOOL_CONFIG_GUID, &theguid) == 0);
1618573ca77eSGeorge Wilson 				if (theguid == srchval)
1619573ca77eSGeorge Wilson 					return (nv);
1620573ca77eSGeorge Wilson 			}
1621573ca77eSGeorge Wilson 		}
1622573ca77eSGeorge Wilson 		break;
1623573ca77eSGeorge Wilson 	}
1624573ca77eSGeorge Wilson 
1625573ca77eSGeorge Wilson 	case DATA_TYPE_STRING: {
1626573ca77eSGeorge Wilson 		char *srchval, *val;
1627573ca77eSGeorge Wilson 
1628573ca77eSGeorge Wilson 		verify(nvpair_value_string(pair, &srchval) == 0);
1629573ca77eSGeorge Wilson 		if (nvlist_lookup_string(nv, srchkey, &val) != 0)
1630573ca77eSGeorge Wilson 			break;
1631ea8dc4b6Seschrock 
1632ea8dc4b6Seschrock 		/*
1633573ca77eSGeorge Wilson 		 * Search for the requested value. We special case the search
163488ecc943SGeorge Wilson 		 * for ZPOOL_CONFIG_PATH when it's a wholedisk and when
163588ecc943SGeorge Wilson 		 * Looking for a top-level vdev name (i.e. ZPOOL_CONFIG_TYPE).
163688ecc943SGeorge Wilson 		 * Otherwise, all other searches are simple string compares.
1637ea8dc4b6Seschrock 		 */
1638573ca77eSGeorge Wilson 		if (strcmp(srchkey, ZPOOL_CONFIG_PATH) == 0 && val) {
1639573ca77eSGeorge Wilson 			uint64_t wholedisk = 0;
1640573ca77eSGeorge Wilson 
1641573ca77eSGeorge Wilson 			(void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK,
1642573ca77eSGeorge Wilson 			    &wholedisk);
1643573ca77eSGeorge Wilson 			if (wholedisk) {
1644573ca77eSGeorge Wilson 				/*
1645573ca77eSGeorge Wilson 				 * For whole disks, the internal path has 's0',
1646573ca77eSGeorge Wilson 				 * but the path passed in by the user doesn't.
1647573ca77eSGeorge Wilson 				 */
1648573ca77eSGeorge Wilson 				if (strlen(srchval) == strlen(val) - 2 &&
1649573ca77eSGeorge Wilson 				    strncmp(srchval, val, strlen(srchval)) == 0)
1650573ca77eSGeorge Wilson 					return (nv);
1651573ca77eSGeorge Wilson 				break;
1652573ca77eSGeorge Wilson 			}
165388ecc943SGeorge Wilson 		} else if (strcmp(srchkey, ZPOOL_CONFIG_TYPE) == 0 && val) {
165488ecc943SGeorge Wilson 			char *type, *idx, *end, *p;
165588ecc943SGeorge Wilson 			uint64_t id, vdev_id;
165688ecc943SGeorge Wilson 
165788ecc943SGeorge Wilson 			/*
165888ecc943SGeorge Wilson 			 * Determine our vdev type, keeping in mind
165988ecc943SGeorge Wilson 			 * that the srchval is composed of a type and
166088ecc943SGeorge Wilson 			 * vdev id pair (i.e. mirror-4).
166188ecc943SGeorge Wilson 			 */
166288ecc943SGeorge Wilson 			if ((type = strdup(srchval)) == NULL)
166388ecc943SGeorge Wilson 				return (NULL);
166488ecc943SGeorge Wilson 
166588ecc943SGeorge Wilson 			if ((p = strrchr(type, '-')) == NULL) {
166688ecc943SGeorge Wilson 				free(type);
166788ecc943SGeorge Wilson 				break;
166888ecc943SGeorge Wilson 			}
166988ecc943SGeorge Wilson 			idx = p + 1;
167088ecc943SGeorge Wilson 			*p = '\0';
167188ecc943SGeorge Wilson 
167288ecc943SGeorge Wilson 			/*
167388ecc943SGeorge Wilson 			 * If the types don't match then keep looking.
167488ecc943SGeorge Wilson 			 */
167588ecc943SGeorge Wilson 			if (strncmp(val, type, strlen(val)) != 0) {
167688ecc943SGeorge Wilson 				free(type);
167788ecc943SGeorge Wilson 				break;
167888ecc943SGeorge Wilson 			}
167988ecc943SGeorge Wilson 
168088ecc943SGeorge Wilson 			verify(strncmp(type, VDEV_TYPE_RAIDZ,
168188ecc943SGeorge Wilson 			    strlen(VDEV_TYPE_RAIDZ)) == 0 ||
168288ecc943SGeorge Wilson 			    strncmp(type, VDEV_TYPE_MIRROR,
168388ecc943SGeorge Wilson 			    strlen(VDEV_TYPE_MIRROR)) == 0);
168488ecc943SGeorge Wilson 			verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_ID,
168588ecc943SGeorge Wilson 			    &id) == 0);
168688ecc943SGeorge Wilson 
168788ecc943SGeorge Wilson 			errno = 0;
168888ecc943SGeorge Wilson 			vdev_id = strtoull(idx, &end, 10);
168988ecc943SGeorge Wilson 
169088ecc943SGeorge Wilson 			free(type);
169188ecc943SGeorge Wilson 			if (errno != 0)
169288ecc943SGeorge Wilson 				return (NULL);
169388ecc943SGeorge Wilson 
169488ecc943SGeorge Wilson 			/*
169588ecc943SGeorge Wilson 			 * Now verify that we have the correct vdev id.
169688ecc943SGeorge Wilson 			 */
169788ecc943SGeorge Wilson 			if (vdev_id == id)
169888ecc943SGeorge Wilson 				return (nv);
1699ea8dc4b6Seschrock 		}
1700573ca77eSGeorge Wilson 
1701573ca77eSGeorge Wilson 		/*
1702573ca77eSGeorge Wilson 		 * Common case
1703573ca77eSGeorge Wilson 		 */
1704573ca77eSGeorge Wilson 		if (strcmp(srchval, val) == 0)
1705573ca77eSGeorge Wilson 			return (nv);
1706573ca77eSGeorge Wilson 		break;
1707573ca77eSGeorge Wilson 	}
1708573ca77eSGeorge Wilson 
1709573ca77eSGeorge Wilson 	default:
1710573ca77eSGeorge Wilson 		break;
1711ea8dc4b6Seschrock 	}
1712ea8dc4b6Seschrock 
1713ea8dc4b6Seschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
1714ea8dc4b6Seschrock 	    &child, &children) != 0)
171599653d4eSeschrock 		return (NULL);
1716ea8dc4b6Seschrock 
1717ee0eb9f2SEric Schrock 	for (c = 0; c < children; c++) {
1718573ca77eSGeorge Wilson 		if ((ret = vdev_to_nvlist_iter(child[c], search,
1719ee0eb9f2SEric Schrock 		    avail_spare, l2cache, NULL)) != NULL) {
1720ee0eb9f2SEric Schrock 			/*
1721ee0eb9f2SEric Schrock 			 * The 'is_log' value is only set for the toplevel
1722ee0eb9f2SEric Schrock 			 * vdev, not the leaf vdevs.  So we always lookup the
1723ee0eb9f2SEric Schrock 			 * log device from the root of the vdev tree (where
1724ee0eb9f2SEric Schrock 			 * 'log' is non-NULL).
1725ee0eb9f2SEric Schrock 			 */
1726ee0eb9f2SEric Schrock 			if (log != NULL &&
1727ee0eb9f2SEric Schrock 			    nvlist_lookup_uint64(child[c],
1728ee0eb9f2SEric Schrock 			    ZPOOL_CONFIG_IS_LOG, &is_log) == 0 &&
1729ee0eb9f2SEric Schrock 			    is_log) {
1730ee0eb9f2SEric Schrock 				*log = B_TRUE;
1731ee0eb9f2SEric Schrock 			}
1732ea8dc4b6Seschrock 			return (ret);
1733ee0eb9f2SEric Schrock 		}
1734ee0eb9f2SEric Schrock 	}
1735ea8dc4b6Seschrock 
173699653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
173799653d4eSeschrock 	    &child, &children) == 0) {
173899653d4eSeschrock 		for (c = 0; c < children; c++) {
1739573ca77eSGeorge Wilson 			if ((ret = vdev_to_nvlist_iter(child[c], search,
1740ee0eb9f2SEric Schrock 			    avail_spare, l2cache, NULL)) != NULL) {
1741a43d325bSek 				*avail_spare = B_TRUE;
174299653d4eSeschrock 				return (ret);
174399653d4eSeschrock 			}
174499653d4eSeschrock 		}
174599653d4eSeschrock 	}
174699653d4eSeschrock 
1747fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
1748fa94a07fSbrendan 	    &child, &children) == 0) {
1749fa94a07fSbrendan 		for (c = 0; c < children; c++) {
1750573ca77eSGeorge Wilson 			if ((ret = vdev_to_nvlist_iter(child[c], search,
1751ee0eb9f2SEric Schrock 			    avail_spare, l2cache, NULL)) != NULL) {
1752fa94a07fSbrendan 				*l2cache = B_TRUE;
1753fa94a07fSbrendan 				return (ret);
1754fa94a07fSbrendan 			}
1755fa94a07fSbrendan 		}
1756fa94a07fSbrendan 	}
1757fa94a07fSbrendan 
175899653d4eSeschrock 	return (NULL);
1759ea8dc4b6Seschrock }
1760ea8dc4b6Seschrock 
1761573ca77eSGeorge Wilson /*
1762573ca77eSGeorge Wilson  * Given a physical path (minus the "/devices" prefix), find the
1763573ca77eSGeorge Wilson  * associated vdev.
1764573ca77eSGeorge Wilson  */
1765573ca77eSGeorge Wilson nvlist_t *
1766573ca77eSGeorge Wilson zpool_find_vdev_by_physpath(zpool_handle_t *zhp, const char *ppath,
1767573ca77eSGeorge Wilson     boolean_t *avail_spare, boolean_t *l2cache, boolean_t *log)
1768573ca77eSGeorge Wilson {
1769573ca77eSGeorge Wilson 	nvlist_t *search, *nvroot, *ret;
1770573ca77eSGeorge Wilson 
1771573ca77eSGeorge Wilson 	verify(nvlist_alloc(&search, NV_UNIQUE_NAME, KM_SLEEP) == 0);
1772573ca77eSGeorge Wilson 	verify(nvlist_add_string(search, ZPOOL_CONFIG_PHYS_PATH, ppath) == 0);
1773573ca77eSGeorge Wilson 
1774573ca77eSGeorge Wilson 	verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE,
1775573ca77eSGeorge Wilson 	    &nvroot) == 0);
1776573ca77eSGeorge Wilson 
1777573ca77eSGeorge Wilson 	*avail_spare = B_FALSE;
1778573ca77eSGeorge Wilson 	ret = vdev_to_nvlist_iter(nvroot, search, avail_spare, l2cache, log);
1779573ca77eSGeorge Wilson 	nvlist_free(search);
1780573ca77eSGeorge Wilson 
1781573ca77eSGeorge Wilson 	return (ret);
1782573ca77eSGeorge Wilson }
1783573ca77eSGeorge Wilson 
178488ecc943SGeorge Wilson /*
178588ecc943SGeorge Wilson  * Determine if we have an "interior" top-level vdev (i.e mirror/raidz).
178688ecc943SGeorge Wilson  */
178788ecc943SGeorge Wilson boolean_t
178888ecc943SGeorge Wilson zpool_vdev_is_interior(const char *name)
178988ecc943SGeorge Wilson {
179088ecc943SGeorge Wilson 	if (strncmp(name, VDEV_TYPE_RAIDZ, strlen(VDEV_TYPE_RAIDZ)) == 0 ||
179188ecc943SGeorge Wilson 	    strncmp(name, VDEV_TYPE_MIRROR, strlen(VDEV_TYPE_MIRROR)) == 0)
179288ecc943SGeorge Wilson 		return (B_TRUE);
179388ecc943SGeorge Wilson 	return (B_FALSE);
179488ecc943SGeorge Wilson }
179588ecc943SGeorge Wilson 
179699653d4eSeschrock nvlist_t *
1797fa94a07fSbrendan zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare,
1798ee0eb9f2SEric Schrock     boolean_t *l2cache, boolean_t *log)
1799ea8dc4b6Seschrock {
1800ea8dc4b6Seschrock 	char buf[MAXPATHLEN];
1801ea8dc4b6Seschrock 	char *end;
1802573ca77eSGeorge Wilson 	nvlist_t *nvroot, *search, *ret;
1803ea8dc4b6Seschrock 	uint64_t guid;
1804ea8dc4b6Seschrock 
1805573ca77eSGeorge Wilson 	verify(nvlist_alloc(&search, NV_UNIQUE_NAME, KM_SLEEP) == 0);
1806573ca77eSGeorge Wilson 
18070917b783Seschrock 	guid = strtoull(path, &end, 10);
1808ea8dc4b6Seschrock 	if (guid != 0 && *end == '\0') {
1809573ca77eSGeorge Wilson 		verify(nvlist_add_uint64(search, ZPOOL_CONFIG_GUID, guid) == 0);
181088ecc943SGeorge Wilson 	} else if (zpool_vdev_is_interior(path)) {
181188ecc943SGeorge Wilson 		verify(nvlist_add_string(search, ZPOOL_CONFIG_TYPE, path) == 0);
1812ea8dc4b6Seschrock 	} else if (path[0] != '/') {
1813ea8dc4b6Seschrock 		(void) snprintf(buf, sizeof (buf), "%s%s", "/dev/dsk/", path);
1814573ca77eSGeorge Wilson 		verify(nvlist_add_string(search, ZPOOL_CONFIG_PATH, buf) == 0);
1815ea8dc4b6Seschrock 	} else {
1816573ca77eSGeorge Wilson 		verify(nvlist_add_string(search, ZPOOL_CONFIG_PATH, path) == 0);
1817ea8dc4b6Seschrock 	}
1818ea8dc4b6Seschrock 
1819ea8dc4b6Seschrock 	verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE,
1820ea8dc4b6Seschrock 	    &nvroot) == 0);
1821ea8dc4b6Seschrock 
1822a43d325bSek 	*avail_spare = B_FALSE;
1823fa94a07fSbrendan 	*l2cache = B_FALSE;
1824ee0eb9f2SEric Schrock 	if (log != NULL)
1825ee0eb9f2SEric Schrock 		*log = B_FALSE;
1826573ca77eSGeorge Wilson 	ret = vdev_to_nvlist_iter(nvroot, search, avail_spare, l2cache, log);
1827573ca77eSGeorge Wilson 	nvlist_free(search);
1828573ca77eSGeorge Wilson 
1829573ca77eSGeorge Wilson 	return (ret);
1830a43d325bSek }
1831a43d325bSek 
183219397407SSherry Moore static int
183319397407SSherry Moore vdev_online(nvlist_t *nv)
183419397407SSherry Moore {
183519397407SSherry Moore 	uint64_t ival;
183619397407SSherry Moore 
183719397407SSherry Moore 	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_OFFLINE, &ival) == 0 ||
183819397407SSherry Moore 	    nvlist_lookup_uint64(nv, ZPOOL_CONFIG_FAULTED, &ival) == 0 ||
183919397407SSherry Moore 	    nvlist_lookup_uint64(nv, ZPOOL_CONFIG_REMOVED, &ival) == 0)
184019397407SSherry Moore 		return (0);
184119397407SSherry Moore 
184219397407SSherry Moore 	return (1);
184319397407SSherry Moore }
184419397407SSherry Moore 
184519397407SSherry Moore /*
184621ecdf64SLin Ling  * Helper function for zpool_get_physpaths().
184719397407SSherry Moore  */
1848753a6d45SSherry Moore static int
184921ecdf64SLin Ling vdev_get_one_physpath(nvlist_t *config, char *physpath, size_t physpath_size,
1850753a6d45SSherry Moore     size_t *bytes_written)
185119397407SSherry Moore {
1852753a6d45SSherry Moore 	size_t bytes_left, pos, rsz;
1853753a6d45SSherry Moore 	char *tmppath;
1854753a6d45SSherry Moore 	const char *format;
1855753a6d45SSherry Moore 
1856753a6d45SSherry Moore 	if (nvlist_lookup_string(config, ZPOOL_CONFIG_PHYS_PATH,
1857753a6d45SSherry Moore 	    &tmppath) != 0)
1858753a6d45SSherry Moore 		return (EZFS_NODEVICE);
1859753a6d45SSherry Moore 
1860753a6d45SSherry Moore 	pos = *bytes_written;
1861753a6d45SSherry Moore 	bytes_left = physpath_size - pos;
1862753a6d45SSherry Moore 	format = (pos == 0) ? "%s" : " %s";
1863753a6d45SSherry Moore 
1864753a6d45SSherry Moore 	rsz = snprintf(physpath + pos, bytes_left, format, tmppath);
1865753a6d45SSherry Moore 	*bytes_written += rsz;
1866753a6d45SSherry Moore 
1867753a6d45SSherry Moore 	if (rsz >= bytes_left) {
1868753a6d45SSherry Moore 		/* if physpath was not copied properly, clear it */
1869753a6d45SSherry Moore 		if (bytes_left != 0) {
1870753a6d45SSherry Moore 			physpath[pos] = 0;
1871753a6d45SSherry Moore 		}
1872753a6d45SSherry Moore 		return (EZFS_NOSPC);
1873753a6d45SSherry Moore 	}
1874753a6d45SSherry Moore 	return (0);
1875753a6d45SSherry Moore }
1876753a6d45SSherry Moore 
187721ecdf64SLin Ling static int
187821ecdf64SLin Ling vdev_get_physpaths(nvlist_t *nv, char *physpath, size_t phypath_size,
187921ecdf64SLin Ling     size_t *rsz, boolean_t is_spare)
188021ecdf64SLin Ling {
188121ecdf64SLin Ling 	char *type;
188221ecdf64SLin Ling 	int ret;
188321ecdf64SLin Ling 
188421ecdf64SLin Ling 	if (nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) != 0)
188521ecdf64SLin Ling 		return (EZFS_INVALCONFIG);
188621ecdf64SLin Ling 
188721ecdf64SLin Ling 	if (strcmp(type, VDEV_TYPE_DISK) == 0) {
188821ecdf64SLin Ling 		/*
188921ecdf64SLin Ling 		 * An active spare device has ZPOOL_CONFIG_IS_SPARE set.
189021ecdf64SLin Ling 		 * For a spare vdev, we only want to boot from the active
189121ecdf64SLin Ling 		 * spare device.
189221ecdf64SLin Ling 		 */
189321ecdf64SLin Ling 		if (is_spare) {
189421ecdf64SLin Ling 			uint64_t spare = 0;
189521ecdf64SLin Ling 			(void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_IS_SPARE,
189621ecdf64SLin Ling 			    &spare);
189721ecdf64SLin Ling 			if (!spare)
189821ecdf64SLin Ling 				return (EZFS_INVALCONFIG);
189921ecdf64SLin Ling 		}
190021ecdf64SLin Ling 
190121ecdf64SLin Ling 		if (vdev_online(nv)) {
190221ecdf64SLin Ling 			if ((ret = vdev_get_one_physpath(nv, physpath,
190321ecdf64SLin Ling 			    phypath_size, rsz)) != 0)
190421ecdf64SLin Ling 				return (ret);
190521ecdf64SLin Ling 		}
190621ecdf64SLin Ling 	} else if (strcmp(type, VDEV_TYPE_MIRROR) == 0 ||
190721ecdf64SLin Ling 	    strcmp(type, VDEV_TYPE_REPLACING) == 0 ||
190821ecdf64SLin Ling 	    (is_spare = (strcmp(type, VDEV_TYPE_SPARE) == 0))) {
190921ecdf64SLin Ling 		nvlist_t **child;
191021ecdf64SLin Ling 		uint_t count;
191121ecdf64SLin Ling 		int i, ret;
191221ecdf64SLin Ling 
191321ecdf64SLin Ling 		if (nvlist_lookup_nvlist_array(nv,
191421ecdf64SLin Ling 		    ZPOOL_CONFIG_CHILDREN, &child, &count) != 0)
191521ecdf64SLin Ling 			return (EZFS_INVALCONFIG);
191621ecdf64SLin Ling 
191721ecdf64SLin Ling 		for (i = 0; i < count; i++) {
191821ecdf64SLin Ling 			ret = vdev_get_physpaths(child[i], physpath,
191921ecdf64SLin Ling 			    phypath_size, rsz, is_spare);
192021ecdf64SLin Ling 			if (ret == EZFS_NOSPC)
192121ecdf64SLin Ling 				return (ret);
192221ecdf64SLin Ling 		}
192321ecdf64SLin Ling 	}
192421ecdf64SLin Ling 
192521ecdf64SLin Ling 	return (EZFS_POOL_INVALARG);
192621ecdf64SLin Ling }
192721ecdf64SLin Ling 
1928753a6d45SSherry Moore /*
1929753a6d45SSherry Moore  * Get phys_path for a root pool config.
1930753a6d45SSherry Moore  * Return 0 on success; non-zero on failure.
1931753a6d45SSherry Moore  */
1932753a6d45SSherry Moore static int
1933753a6d45SSherry Moore zpool_get_config_physpath(nvlist_t *config, char *physpath, size_t phypath_size)
1934753a6d45SSherry Moore {
1935753a6d45SSherry Moore 	size_t rsz;
193619397407SSherry Moore 	nvlist_t *vdev_root;
193719397407SSherry Moore 	nvlist_t **child;
193819397407SSherry Moore 	uint_t count;
1939753a6d45SSherry Moore 	char *type;
1940753a6d45SSherry Moore 
1941753a6d45SSherry Moore 	rsz = 0;
1942753a6d45SSherry Moore 
1943753a6d45SSherry Moore 	if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
1944753a6d45SSherry Moore 	    &vdev_root) != 0)
1945753a6d45SSherry Moore 		return (EZFS_INVALCONFIG);
1946753a6d45SSherry Moore 
1947753a6d45SSherry Moore 	if (nvlist_lookup_string(vdev_root, ZPOOL_CONFIG_TYPE, &type) != 0 ||
1948753a6d45SSherry Moore 	    nvlist_lookup_nvlist_array(vdev_root, ZPOOL_CONFIG_CHILDREN,
1949753a6d45SSherry Moore 	    &child, &count) != 0)
1950753a6d45SSherry Moore 		return (EZFS_INVALCONFIG);
195119397407SSherry Moore 
195219397407SSherry Moore 	/*
1953753a6d45SSherry Moore 	 * root pool can not have EFI labeled disks and can only have
1954753a6d45SSherry Moore 	 * a single top-level vdev.
195519397407SSherry Moore 	 */
1956753a6d45SSherry Moore 	if (strcmp(type, VDEV_TYPE_ROOT) != 0 || count != 1 ||
1957753a6d45SSherry Moore 	    pool_uses_efi(vdev_root))
1958753a6d45SSherry Moore 		return (EZFS_POOL_INVALARG);
195919397407SSherry Moore 
196021ecdf64SLin Ling 	(void) vdev_get_physpaths(child[0], physpath, phypath_size, &rsz,
196121ecdf64SLin Ling 	    B_FALSE);
196219397407SSherry Moore 
1963753a6d45SSherry Moore 	/* No online devices */
1964753a6d45SSherry Moore 	if (rsz == 0)
1965753a6d45SSherry Moore 		return (EZFS_NODEVICE);
1966753a6d45SSherry Moore 
196719397407SSherry Moore 	return (0);
196819397407SSherry Moore }
196919397407SSherry Moore 
1970753a6d45SSherry Moore /*
1971753a6d45SSherry Moore  * Get phys_path for a root pool
1972753a6d45SSherry Moore  * Return 0 on success; non-zero on failure.
1973753a6d45SSherry Moore  */
1974753a6d45SSherry Moore int
1975753a6d45SSherry Moore zpool_get_physpath(zpool_handle_t *zhp, char *physpath, size_t phypath_size)
1976753a6d45SSherry Moore {
1977753a6d45SSherry Moore 	return (zpool_get_config_physpath(zhp->zpool_config, physpath,
1978753a6d45SSherry Moore 	    phypath_size));
1979753a6d45SSherry Moore }
1980753a6d45SSherry Moore 
1981573ca77eSGeorge Wilson /*
1982573ca77eSGeorge Wilson  * If the device has being dynamically expanded then we need to relabel
1983573ca77eSGeorge Wilson  * the disk to use the new unallocated space.
1984573ca77eSGeorge Wilson  */
1985573ca77eSGeorge Wilson static int
1986573ca77eSGeorge Wilson zpool_relabel_disk(libzfs_handle_t *hdl, const char *name)
1987573ca77eSGeorge Wilson {
1988573ca77eSGeorge Wilson 	char path[MAXPATHLEN];
1989573ca77eSGeorge Wilson 	char errbuf[1024];
1990573ca77eSGeorge Wilson 	int fd, error;
1991573ca77eSGeorge Wilson 	int (*_efi_use_whole_disk)(int);
1992573ca77eSGeorge Wilson 
1993573ca77eSGeorge Wilson 	if ((_efi_use_whole_disk = (int (*)(int))dlsym(RTLD_DEFAULT,
1994573ca77eSGeorge Wilson 	    "efi_use_whole_disk")) == NULL)
1995573ca77eSGeorge Wilson 		return (-1);
1996573ca77eSGeorge Wilson 
1997573ca77eSGeorge Wilson 	(void) snprintf(path, sizeof (path), "%s/%s", RDISK_ROOT, name);
1998573ca77eSGeorge Wilson 
1999573ca77eSGeorge Wilson 	if ((fd = open(path, O_RDWR | O_NDELAY)) < 0) {
2000573ca77eSGeorge Wilson 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot "
2001573ca77eSGeorge Wilson 		    "relabel '%s': unable to open device"), name);
2002573ca77eSGeorge Wilson 		return (zfs_error(hdl, EZFS_OPENFAILED, errbuf));
2003573ca77eSGeorge Wilson 	}
2004573ca77eSGeorge Wilson 
2005573ca77eSGeorge Wilson 	/*
2006573ca77eSGeorge Wilson 	 * It's possible that we might encounter an error if the device
2007573ca77eSGeorge Wilson 	 * does not have any unallocated space left. If so, we simply
2008573ca77eSGeorge Wilson 	 * ignore that error and continue on.
2009573ca77eSGeorge Wilson 	 */
2010573ca77eSGeorge Wilson 	error = _efi_use_whole_disk(fd);
2011573ca77eSGeorge Wilson 	(void) close(fd);
2012573ca77eSGeorge Wilson 	if (error && error != VT_ENOSPC) {
2013573ca77eSGeorge Wilson 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot "
2014573ca77eSGeorge Wilson 		    "relabel '%s': unable to read disk capacity"), name);
2015573ca77eSGeorge Wilson 		return (zfs_error(hdl, EZFS_NOCAP, errbuf));
2016573ca77eSGeorge Wilson 	}
2017573ca77eSGeorge Wilson 	return (0);
2018573ca77eSGeorge Wilson }
2019573ca77eSGeorge Wilson 
2020fa9e4066Sahrens /*
20213d7072f8Seschrock  * Bring the specified vdev online.   The 'flags' parameter is a set of the
20223d7072f8Seschrock  * ZFS_ONLINE_* flags.
2023fa9e4066Sahrens  */
2024fa9e4066Sahrens int
20253d7072f8Seschrock zpool_vdev_online(zpool_handle_t *zhp, const char *path, int flags,
20263d7072f8Seschrock     vdev_state_t *newstate)
2027fa9e4066Sahrens {
2028fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
2029fa9e4066Sahrens 	char msg[1024];
203099653d4eSeschrock 	nvlist_t *tgt;
2031573ca77eSGeorge Wilson 	boolean_t avail_spare, l2cache, islog;
203299653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
2033fa9e4066Sahrens 
2034573ca77eSGeorge Wilson 	if (flags & ZFS_ONLINE_EXPAND) {
2035573ca77eSGeorge Wilson 		(void) snprintf(msg, sizeof (msg),
2036573ca77eSGeorge Wilson 		    dgettext(TEXT_DOMAIN, "cannot expand %s"), path);
2037573ca77eSGeorge Wilson 	} else {
2038573ca77eSGeorge Wilson 		(void) snprintf(msg, sizeof (msg),
2039573ca77eSGeorge Wilson 		    dgettext(TEXT_DOMAIN, "cannot online %s"), path);
2040573ca77eSGeorge Wilson 	}
2041ea8dc4b6Seschrock 
2042fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
2043ee0eb9f2SEric Schrock 	if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache,
2044573ca77eSGeorge Wilson 	    &islog)) == NULL)
204599653d4eSeschrock 		return (zfs_error(hdl, EZFS_NODEVICE, msg));
2046fa9e4066Sahrens 
204799653d4eSeschrock 	verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
2048fa9e4066Sahrens 
2049069f55e2SEric Schrock 	if (avail_spare)
2050a43d325bSek 		return (zfs_error(hdl, EZFS_ISSPARE, msg));
2051a43d325bSek 
2052573ca77eSGeorge Wilson 	if (flags & ZFS_ONLINE_EXPAND ||
2053573ca77eSGeorge Wilson 	    zpool_get_prop_int(zhp, ZPOOL_PROP_AUTOEXPAND, NULL)) {
2054573ca77eSGeorge Wilson 		char *pathname = NULL;
2055573ca77eSGeorge Wilson 		uint64_t wholedisk = 0;
2056573ca77eSGeorge Wilson 
2057573ca77eSGeorge Wilson 		(void) nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_WHOLE_DISK,
2058573ca77eSGeorge Wilson 		    &wholedisk);
2059573ca77eSGeorge Wilson 		verify(nvlist_lookup_string(tgt, ZPOOL_CONFIG_PATH,
2060573ca77eSGeorge Wilson 		    &pathname) == 0);
2061573ca77eSGeorge Wilson 
2062573ca77eSGeorge Wilson 		/*
2063573ca77eSGeorge Wilson 		 * XXX - L2ARC 1.0 devices can't support expansion.
2064573ca77eSGeorge Wilson 		 */
2065573ca77eSGeorge Wilson 		if (l2cache) {
2066573ca77eSGeorge Wilson 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2067573ca77eSGeorge Wilson 			    "cannot expand cache devices"));
2068573ca77eSGeorge Wilson 			return (zfs_error(hdl, EZFS_VDEVNOTSUP, msg));
2069573ca77eSGeorge Wilson 		}
2070573ca77eSGeorge Wilson 
2071573ca77eSGeorge Wilson 		if (wholedisk) {
2072573ca77eSGeorge Wilson 			pathname += strlen(DISK_ROOT) + 1;
2073573ca77eSGeorge Wilson 			(void) zpool_relabel_disk(zhp->zpool_hdl, pathname);
2074573ca77eSGeorge Wilson 		}
2075573ca77eSGeorge Wilson 	}
2076573ca77eSGeorge Wilson 
20773d7072f8Seschrock 	zc.zc_cookie = VDEV_STATE_ONLINE;
20783d7072f8Seschrock 	zc.zc_obj = flags;
2079fa9e4066Sahrens 
2080*1195e687SMark J Musante 	if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_SET_STATE, &zc) != 0) {
2081*1195e687SMark J Musante 		if (errno == EINVAL) {
2082*1195e687SMark J Musante 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "was split "
2083*1195e687SMark J Musante 			    "from this pool into a new one.  Use '%s' "
2084*1195e687SMark J Musante 			    "instead"), "zpool detach");
2085*1195e687SMark J Musante 			return (zfs_error(hdl, EZFS_POSTSPLIT_ONLINE, msg));
2086*1195e687SMark J Musante 		}
20873d7072f8Seschrock 		return (zpool_standard_error(hdl, errno, msg));
2088*1195e687SMark J Musante 	}
20893d7072f8Seschrock 
20903d7072f8Seschrock 	*newstate = zc.zc_cookie;
20913d7072f8Seschrock 	return (0);
2092fa9e4066Sahrens }
2093fa9e4066Sahrens 
2094fa9e4066Sahrens /*
2095fa9e4066Sahrens  * Take the specified vdev offline
2096fa9e4066Sahrens  */
2097fa9e4066Sahrens int
20983d7072f8Seschrock zpool_vdev_offline(zpool_handle_t *zhp, const char *path, boolean_t istmp)
2099fa9e4066Sahrens {
2100fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
2101fa9e4066Sahrens 	char msg[1024];
210299653d4eSeschrock 	nvlist_t *tgt;
2103fa94a07fSbrendan 	boolean_t avail_spare, l2cache;
210499653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
2105fa9e4066Sahrens 
2106ea8dc4b6Seschrock 	(void) snprintf(msg, sizeof (msg),
2107ea8dc4b6Seschrock 	    dgettext(TEXT_DOMAIN, "cannot offline %s"), path);
2108ea8dc4b6Seschrock 
2109fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
2110ee0eb9f2SEric Schrock 	if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache,
2111ee0eb9f2SEric Schrock 	    NULL)) == NULL)
211299653d4eSeschrock 		return (zfs_error(hdl, EZFS_NODEVICE, msg));
211399653d4eSeschrock 
211499653d4eSeschrock 	verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
2115fa9e4066Sahrens 
2116069f55e2SEric Schrock 	if (avail_spare)
2117a43d325bSek 		return (zfs_error(hdl, EZFS_ISSPARE, msg));
2118a43d325bSek 
21193d7072f8Seschrock 	zc.zc_cookie = VDEV_STATE_OFFLINE;
21203d7072f8Seschrock 	zc.zc_obj = istmp ? ZFS_OFFLINE_TEMPORARY : 0;
21213d7072f8Seschrock 
2122ecd6cf80Smarks 	if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_SET_STATE, &zc) == 0)
21233d7072f8Seschrock 		return (0);
21243d7072f8Seschrock 
21253d7072f8Seschrock 	switch (errno) {
21263d7072f8Seschrock 	case EBUSY:
21273d7072f8Seschrock 
21283d7072f8Seschrock 		/*
21293d7072f8Seschrock 		 * There are no other replicas of this device.
21303d7072f8Seschrock 		 */
21313d7072f8Seschrock 		return (zfs_error(hdl, EZFS_NOREPLICAS, msg));
21323d7072f8Seschrock 
2133e6ca193dSGeorge Wilson 	case EEXIST:
2134e6ca193dSGeorge Wilson 		/*
2135e6ca193dSGeorge Wilson 		 * The log device has unplayed logs
2136e6ca193dSGeorge Wilson 		 */
2137e6ca193dSGeorge Wilson 		return (zfs_error(hdl, EZFS_UNPLAYED_LOGS, msg));
2138e6ca193dSGeorge Wilson 
21393d7072f8Seschrock 	default:
21403d7072f8Seschrock 		return (zpool_standard_error(hdl, errno, msg));
21413d7072f8Seschrock 	}
21423d7072f8Seschrock }
21433d7072f8Seschrock 
21443d7072f8Seschrock /*
21453d7072f8Seschrock  * Mark the given vdev faulted.
21463d7072f8Seschrock  */
21473d7072f8Seschrock int
2148069f55e2SEric Schrock zpool_vdev_fault(zpool_handle_t *zhp, uint64_t guid, vdev_aux_t aux)
21493d7072f8Seschrock {
21503d7072f8Seschrock 	zfs_cmd_t zc = { 0 };
21513d7072f8Seschrock 	char msg[1024];
21523d7072f8Seschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
21533d7072f8Seschrock 
21543d7072f8Seschrock 	(void) snprintf(msg, sizeof (msg),
21553d7072f8Seschrock 	    dgettext(TEXT_DOMAIN, "cannot fault %llu"), guid);
2156441d80aaSlling 
21573d7072f8Seschrock 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
21583d7072f8Seschrock 	zc.zc_guid = guid;
21593d7072f8Seschrock 	zc.zc_cookie = VDEV_STATE_FAULTED;
2160069f55e2SEric Schrock 	zc.zc_obj = aux;
21613d7072f8Seschrock 
21623d7072f8Seschrock 	if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0)
2163fa9e4066Sahrens 		return (0);
2164fa9e4066Sahrens 
2165fa9e4066Sahrens 	switch (errno) {
216699653d4eSeschrock 	case EBUSY:
2167fa9e4066Sahrens 
2168fa9e4066Sahrens 		/*
2169fa9e4066Sahrens 		 * There are no other replicas of this device.
2170fa9e4066Sahrens 		 */
217199653d4eSeschrock 		return (zfs_error(hdl, EZFS_NOREPLICAS, msg));
2172fa9e4066Sahrens 
217399653d4eSeschrock 	default:
217499653d4eSeschrock 		return (zpool_standard_error(hdl, errno, msg));
2175fa9e4066Sahrens 	}
21763d7072f8Seschrock 
21773d7072f8Seschrock }
21783d7072f8Seschrock 
21793d7072f8Seschrock /*
21803d7072f8Seschrock  * Mark the given vdev degraded.
21813d7072f8Seschrock  */
21823d7072f8Seschrock int
2183069f55e2SEric Schrock zpool_vdev_degrade(zpool_handle_t *zhp, uint64_t guid, vdev_aux_t aux)
21843d7072f8Seschrock {
21853d7072f8Seschrock 	zfs_cmd_t zc = { 0 };
21863d7072f8Seschrock 	char msg[1024];
21873d7072f8Seschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
21883d7072f8Seschrock 
21893d7072f8Seschrock 	(void) snprintf(msg, sizeof (msg),
21903d7072f8Seschrock 	    dgettext(TEXT_DOMAIN, "cannot degrade %llu"), guid);
21913d7072f8Seschrock 
21923d7072f8Seschrock 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
21933d7072f8Seschrock 	zc.zc_guid = guid;
21943d7072f8Seschrock 	zc.zc_cookie = VDEV_STATE_DEGRADED;
2195069f55e2SEric Schrock 	zc.zc_obj = aux;
21963d7072f8Seschrock 
21973d7072f8Seschrock 	if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0)
21983d7072f8Seschrock 		return (0);
21993d7072f8Seschrock 
22003d7072f8Seschrock 	return (zpool_standard_error(hdl, errno, msg));
220199653d4eSeschrock }
220299653d4eSeschrock 
220399653d4eSeschrock /*
220499653d4eSeschrock  * Returns TRUE if the given nvlist is a vdev that was originally swapped in as
220599653d4eSeschrock  * a hot spare.
220699653d4eSeschrock  */
220799653d4eSeschrock static boolean_t
220899653d4eSeschrock is_replacing_spare(nvlist_t *search, nvlist_t *tgt, int which)
220999653d4eSeschrock {
221099653d4eSeschrock 	nvlist_t **child;
221199653d4eSeschrock 	uint_t c, children;
221299653d4eSeschrock 	char *type;
221399653d4eSeschrock 
221499653d4eSeschrock 	if (nvlist_lookup_nvlist_array(search, ZPOOL_CONFIG_CHILDREN, &child,
221599653d4eSeschrock 	    &children) == 0) {
221699653d4eSeschrock 		verify(nvlist_lookup_string(search, ZPOOL_CONFIG_TYPE,
221799653d4eSeschrock 		    &type) == 0);
221899653d4eSeschrock 
221999653d4eSeschrock 		if (strcmp(type, VDEV_TYPE_SPARE) == 0 &&
222099653d4eSeschrock 		    children == 2 && child[which] == tgt)
222199653d4eSeschrock 			return (B_TRUE);
222299653d4eSeschrock 
222399653d4eSeschrock 		for (c = 0; c < children; c++)
222499653d4eSeschrock 			if (is_replacing_spare(child[c], tgt, which))
222599653d4eSeschrock 				return (B_TRUE);
222699653d4eSeschrock 	}
222799653d4eSeschrock 
222899653d4eSeschrock 	return (B_FALSE);
2229fa9e4066Sahrens }
2230fa9e4066Sahrens 
2231fa9e4066Sahrens /*
2232fa9e4066Sahrens  * Attach new_disk (fully described by nvroot) to old_disk.
22338654d025Sperrin  * If 'replacing' is specified, the new disk will replace the old one.
2234fa9e4066Sahrens  */
2235fa9e4066Sahrens int
2236fa9e4066Sahrens zpool_vdev_attach(zpool_handle_t *zhp,
2237fa9e4066Sahrens     const char *old_disk, const char *new_disk, nvlist_t *nvroot, int replacing)
2238fa9e4066Sahrens {
2239fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
2240fa9e4066Sahrens 	char msg[1024];
2241fa9e4066Sahrens 	int ret;
224299653d4eSeschrock 	nvlist_t *tgt;
2243ee0eb9f2SEric Schrock 	boolean_t avail_spare, l2cache, islog;
2244ee0eb9f2SEric Schrock 	uint64_t val;
22450430f8daSeschrock 	char *path, *newname;
224699653d4eSeschrock 	nvlist_t **child;
224799653d4eSeschrock 	uint_t children;
224899653d4eSeschrock 	nvlist_t *config_root;
224999653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
2250b5b76fecSGeorge Wilson 	boolean_t rootpool = pool_is_bootable(zhp);
2251fa9e4066Sahrens 
2252ea8dc4b6Seschrock 	if (replacing)
2253ea8dc4b6Seschrock 		(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
2254ea8dc4b6Seschrock 		    "cannot replace %s with %s"), old_disk, new_disk);
2255ea8dc4b6Seschrock 	else
2256ea8dc4b6Seschrock 		(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
2257ea8dc4b6Seschrock 		    "cannot attach %s to %s"), new_disk, old_disk);
2258ea8dc4b6Seschrock 
2259b5b76fecSGeorge Wilson 	/*
2260b5b76fecSGeorge Wilson 	 * If this is a root pool, make sure that we're not attaching an
2261b5b76fecSGeorge Wilson 	 * EFI labeled device.
2262b5b76fecSGeorge Wilson 	 */
2263b5b76fecSGeorge Wilson 	if (rootpool && pool_uses_efi(nvroot)) {
2264b5b76fecSGeorge Wilson 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2265b5b76fecSGeorge Wilson 		    "EFI labeled devices are not supported on root pools."));
2266b5b76fecSGeorge Wilson 		return (zfs_error(hdl, EZFS_POOL_NOTSUP, msg));
2267b5b76fecSGeorge Wilson 	}
2268b5b76fecSGeorge Wilson 
2269fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
2270ee0eb9f2SEric Schrock 	if ((tgt = zpool_find_vdev(zhp, old_disk, &avail_spare, &l2cache,
2271ee0eb9f2SEric Schrock 	    &islog)) == 0)
227299653d4eSeschrock 		return (zfs_error(hdl, EZFS_NODEVICE, msg));
227399653d4eSeschrock 
2274a43d325bSek 	if (avail_spare)
227599653d4eSeschrock 		return (zfs_error(hdl, EZFS_ISSPARE, msg));
227699653d4eSeschrock 
2277fa94a07fSbrendan 	if (l2cache)
2278fa94a07fSbrendan 		return (zfs_error(hdl, EZFS_ISL2CACHE, msg));
2279fa94a07fSbrendan 
228099653d4eSeschrock 	verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
2281fa9e4066Sahrens 	zc.zc_cookie = replacing;
2282fa9e4066Sahrens 
228399653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
228499653d4eSeschrock 	    &child, &children) != 0 || children != 1) {
228599653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
228699653d4eSeschrock 		    "new device must be a single disk"));
228799653d4eSeschrock 		return (zfs_error(hdl, EZFS_INVALCONFIG, msg));
228899653d4eSeschrock 	}
228999653d4eSeschrock 
229099653d4eSeschrock 	verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL),
229199653d4eSeschrock 	    ZPOOL_CONFIG_VDEV_TREE, &config_root) == 0);
229299653d4eSeschrock 
229388ecc943SGeorge Wilson 	if ((newname = zpool_vdev_name(NULL, NULL, child[0], B_FALSE)) == NULL)
22940430f8daSeschrock 		return (-1);
22950430f8daSeschrock 
229699653d4eSeschrock 	/*
229799653d4eSeschrock 	 * If the target is a hot spare that has been swapped in, we can only
229899653d4eSeschrock 	 * replace it with another hot spare.
229999653d4eSeschrock 	 */
230099653d4eSeschrock 	if (replacing &&
230199653d4eSeschrock 	    nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_IS_SPARE, &val) == 0 &&
2302ee0eb9f2SEric Schrock 	    (zpool_find_vdev(zhp, newname, &avail_spare, &l2cache,
2303ee0eb9f2SEric Schrock 	    NULL) == NULL || !avail_spare) &&
2304ee0eb9f2SEric Schrock 	    is_replacing_spare(config_root, tgt, 1)) {
230599653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
230699653d4eSeschrock 		    "can only be replaced by another hot spare"));
23070430f8daSeschrock 		free(newname);
230899653d4eSeschrock 		return (zfs_error(hdl, EZFS_BADTARGET, msg));
230999653d4eSeschrock 	}
231099653d4eSeschrock 
231199653d4eSeschrock 	/*
231299653d4eSeschrock 	 * If we are attempting to replace a spare, it canot be applied to an
231399653d4eSeschrock 	 * already spared device.
231499653d4eSeschrock 	 */
231599653d4eSeschrock 	if (replacing &&
231699653d4eSeschrock 	    nvlist_lookup_string(child[0], ZPOOL_CONFIG_PATH, &path) == 0 &&
2317ee0eb9f2SEric Schrock 	    zpool_find_vdev(zhp, newname, &avail_spare,
2318ee0eb9f2SEric Schrock 	    &l2cache, NULL) != NULL && avail_spare &&
2319ee0eb9f2SEric Schrock 	    is_replacing_spare(config_root, tgt, 0)) {
232099653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
232199653d4eSeschrock 		    "device has already been replaced with a spare"));
23220430f8daSeschrock 		free(newname);
232399653d4eSeschrock 		return (zfs_error(hdl, EZFS_BADTARGET, msg));
232499653d4eSeschrock 	}
232599653d4eSeschrock 
23260430f8daSeschrock 	free(newname);
23270430f8daSeschrock 
2328990b4856Slling 	if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0)
232999653d4eSeschrock 		return (-1);
2330fa9e4066Sahrens 
2331ecd6cf80Smarks 	ret = zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_ATTACH, &zc);
2332fa9e4066Sahrens 
2333e9dbad6fSeschrock 	zcmd_free_nvlists(&zc);
2334fa9e4066Sahrens 
2335b5b76fecSGeorge Wilson 	if (ret == 0) {
2336b5b76fecSGeorge Wilson 		if (rootpool) {
2337b5b76fecSGeorge Wilson 			/*
2338b5b76fecSGeorge Wilson 			 * XXX - This should be removed once we can
2339b5b76fecSGeorge Wilson 			 * automatically install the bootblocks on the
2340b5b76fecSGeorge Wilson 			 * newly attached disk.
2341b5b76fecSGeorge Wilson 			 */
2342b5b76fecSGeorge Wilson 			(void) fprintf(stderr, dgettext(TEXT_DOMAIN, "Please "
2343b5b76fecSGeorge Wilson 			    "be sure to invoke %s to make '%s' bootable.\n"),
2344b5b76fecSGeorge Wilson 			    BOOTCMD, new_disk);
234521ecdf64SLin Ling 
234621ecdf64SLin Ling 			/*
234721ecdf64SLin Ling 			 * XXX need a better way to prevent user from
234821ecdf64SLin Ling 			 * booting up a half-baked vdev.
234921ecdf64SLin Ling 			 */
235021ecdf64SLin Ling 			(void) fprintf(stderr, dgettext(TEXT_DOMAIN, "Make "
235121ecdf64SLin Ling 			    "sure to wait until resilver is done "
235221ecdf64SLin Ling 			    "before rebooting.\n"));
2353b5b76fecSGeorge Wilson 		}
2354fa9e4066Sahrens 		return (0);
2355b5b76fecSGeorge Wilson 	}
2356fa9e4066Sahrens 
2357fa9e4066Sahrens 	switch (errno) {
2358ea8dc4b6Seschrock 	case ENOTSUP:
2359fa9e4066Sahrens 		/*
2360fa9e4066Sahrens 		 * Can't attach to or replace this type of vdev.
2361fa9e4066Sahrens 		 */
23628654d025Sperrin 		if (replacing) {
2363ee0eb9f2SEric Schrock 			if (islog)
23648654d025Sperrin 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
23658654d025Sperrin 				    "cannot replace a log with a spare"));
23668654d025Sperrin 			else
23678654d025Sperrin 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
23688654d025Sperrin 				    "cannot replace a replacing device"));
23698654d025Sperrin 		} else {
237099653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
237199653d4eSeschrock 			    "can only attach to mirrors and top-level "
237299653d4eSeschrock 			    "disks"));
23738654d025Sperrin 		}
237499653d4eSeschrock 		(void) zfs_error(hdl, EZFS_BADTARGET, msg);
2375fa9e4066Sahrens 		break;
2376fa9e4066Sahrens 
2377ea8dc4b6Seschrock 	case EINVAL:
2378fa9e4066Sahrens 		/*
2379fa9e4066Sahrens 		 * The new device must be a single disk.
2380fa9e4066Sahrens 		 */
238199653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
238299653d4eSeschrock 		    "new device must be a single disk"));
238399653d4eSeschrock 		(void) zfs_error(hdl, EZFS_INVALCONFIG, msg);
2384fa9e4066Sahrens 		break;
2385fa9e4066Sahrens 
2386ea8dc4b6Seschrock 	case EBUSY:
238799653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "%s is busy"),
238899653d4eSeschrock 		    new_disk);
238999653d4eSeschrock 		(void) zfs_error(hdl, EZFS_BADDEV, msg);
2390fa9e4066Sahrens 		break;
2391fa9e4066Sahrens 
2392ea8dc4b6Seschrock 	case EOVERFLOW:
2393fa9e4066Sahrens 		/*
2394fa9e4066Sahrens 		 * The new device is too small.
2395fa9e4066Sahrens 		 */
239699653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
239799653d4eSeschrock 		    "device is too small"));
239899653d4eSeschrock 		(void) zfs_error(hdl, EZFS_BADDEV, msg);
2399fa9e4066Sahrens 		break;
2400fa9e4066Sahrens 
2401ea8dc4b6Seschrock 	case EDOM:
2402fa9e4066Sahrens 		/*
2403fa9e4066Sahrens 		 * The new device has a different alignment requirement.
2404fa9e4066Sahrens 		 */
240599653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
240699653d4eSeschrock 		    "devices have different sector alignment"));
240799653d4eSeschrock 		(void) zfs_error(hdl, EZFS_BADDEV, msg);
2408fa9e4066Sahrens 		break;
2409fa9e4066Sahrens 
2410ea8dc4b6Seschrock 	case ENAMETOOLONG:
2411fa9e4066Sahrens 		/*
2412fa9e4066Sahrens 		 * The resulting top-level vdev spec won't fit in the label.
2413fa9e4066Sahrens 		 */
241499653d4eSeschrock 		(void) zfs_error(hdl, EZFS_DEVOVERFLOW, msg);
2415fa9e4066Sahrens 		break;
2416fa9e4066Sahrens 
2417ea8dc4b6Seschrock 	default:
241899653d4eSeschrock 		(void) zpool_standard_error(hdl, errno, msg);
2419fa9e4066Sahrens 	}
2420fa9e4066Sahrens 
242199653d4eSeschrock 	return (-1);
2422fa9e4066Sahrens }
2423fa9e4066Sahrens 
2424fa9e4066Sahrens /*
2425fa9e4066Sahrens  * Detach the specified device.
2426fa9e4066Sahrens  */
2427fa9e4066Sahrens int
2428fa9e4066Sahrens zpool_vdev_detach(zpool_handle_t *zhp, const char *path)
2429fa9e4066Sahrens {
2430fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
2431fa9e4066Sahrens 	char msg[1024];
243299653d4eSeschrock 	nvlist_t *tgt;
2433fa94a07fSbrendan 	boolean_t avail_spare, l2cache;
243499653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
2435fa9e4066Sahrens 
2436ea8dc4b6Seschrock 	(void) snprintf(msg, sizeof (msg),
2437ea8dc4b6Seschrock 	    dgettext(TEXT_DOMAIN, "cannot detach %s"), path);
2438ea8dc4b6Seschrock 
2439fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
2440ee0eb9f2SEric Schrock 	if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache,
2441ee0eb9f2SEric Schrock 	    NULL)) == 0)
244299653d4eSeschrock 		return (zfs_error(hdl, EZFS_NODEVICE, msg));
2443fa9e4066Sahrens 
2444a43d325bSek 	if (avail_spare)
244599653d4eSeschrock 		return (zfs_error(hdl, EZFS_ISSPARE, msg));
244699653d4eSeschrock 
2447fa94a07fSbrendan 	if (l2cache)
2448fa94a07fSbrendan 		return (zfs_error(hdl, EZFS_ISL2CACHE, msg));
2449fa94a07fSbrendan 
245099653d4eSeschrock 	verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
245199653d4eSeschrock 
2452ecd6cf80Smarks 	if (zfs_ioctl(hdl, ZFS_IOC_VDEV_DETACH, &zc) == 0)
2453fa9e4066Sahrens 		return (0);
2454fa9e4066Sahrens 
2455fa9e4066Sahrens 	switch (errno) {
2456fa9e4066Sahrens 
2457ea8dc4b6Seschrock 	case ENOTSUP:
2458fa9e4066Sahrens 		/*
2459fa9e4066Sahrens 		 * Can't detach from this type of vdev.
2460fa9e4066Sahrens 		 */
246199653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "only "
246299653d4eSeschrock 		    "applicable to mirror and replacing vdevs"));
246399653d4eSeschrock 		(void) zfs_error(zhp->zpool_hdl, EZFS_BADTARGET, msg);
2464fa9e4066Sahrens 		break;
2465fa9e4066Sahrens 
2466ea8dc4b6Seschrock 	case EBUSY:
2467fa9e4066Sahrens 		/*
2468fa9e4066Sahrens 		 * There are no other replicas of this device.
2469fa9e4066Sahrens 		 */
247099653d4eSeschrock 		(void) zfs_error(hdl, EZFS_NOREPLICAS, msg);
2471fa9e4066Sahrens 		break;
2472fa9e4066Sahrens 
2473ea8dc4b6Seschrock 	default:
247499653d4eSeschrock 		(void) zpool_standard_error(hdl, errno, msg);
2475ea8dc4b6Seschrock 	}
2476ea8dc4b6Seschrock 
247799653d4eSeschrock 	return (-1);
247899653d4eSeschrock }
247999653d4eSeschrock 
2480*1195e687SMark J Musante /*
2481*1195e687SMark J Musante  * Find a mirror vdev in the source nvlist.
2482*1195e687SMark J Musante  *
2483*1195e687SMark J Musante  * The mchild array contains a list of disks in one of the top-level mirrors
2484*1195e687SMark J Musante  * of the source pool.  The schild array contains a list of disks that the
2485*1195e687SMark J Musante  * user specified on the command line.  We loop over the mchild array to
2486*1195e687SMark J Musante  * see if any entry in the schild array matches.
2487*1195e687SMark J Musante  *
2488*1195e687SMark J Musante  * If a disk in the mchild array is found in the schild array, we return
2489*1195e687SMark J Musante  * the index of that entry.  Otherwise we return -1.
2490*1195e687SMark J Musante  */
2491*1195e687SMark J Musante static int
2492*1195e687SMark J Musante find_vdev_entry(zpool_handle_t *zhp, nvlist_t **mchild, uint_t mchildren,
2493*1195e687SMark J Musante     nvlist_t **schild, uint_t schildren)
2494*1195e687SMark J Musante {
2495*1195e687SMark J Musante 	uint_t mc;
2496*1195e687SMark J Musante 
2497*1195e687SMark J Musante 	for (mc = 0; mc < mchildren; mc++) {
2498*1195e687SMark J Musante 		uint_t sc;
2499*1195e687SMark J Musante 		char *mpath = zpool_vdev_name(zhp->zpool_hdl, zhp,
2500*1195e687SMark J Musante 		    mchild[mc], B_FALSE);
2501*1195e687SMark J Musante 
2502*1195e687SMark J Musante 		for (sc = 0; sc < schildren; sc++) {
2503*1195e687SMark J Musante 			char *spath = zpool_vdev_name(zhp->zpool_hdl, zhp,
2504*1195e687SMark J Musante 			    schild[sc], B_FALSE);
2505*1195e687SMark J Musante 			boolean_t result = (strcmp(mpath, spath) == 0);
2506*1195e687SMark J Musante 
2507*1195e687SMark J Musante 			free(spath);
2508*1195e687SMark J Musante 			if (result) {
2509*1195e687SMark J Musante 				free(mpath);
2510*1195e687SMark J Musante 				return (mc);
2511*1195e687SMark J Musante 			}
2512*1195e687SMark J Musante 		}
2513*1195e687SMark J Musante 
2514*1195e687SMark J Musante 		free(mpath);
2515*1195e687SMark J Musante 	}
2516*1195e687SMark J Musante 
2517*1195e687SMark J Musante 	return (-1);
2518*1195e687SMark J Musante }
2519*1195e687SMark J Musante 
2520*1195e687SMark J Musante /*
2521*1195e687SMark J Musante  * Split a mirror pool.  If newroot points to null, then a new nvlist
2522*1195e687SMark J Musante  * is generated and it is the responsibility of the caller to free it.
2523*1195e687SMark J Musante  */
2524*1195e687SMark J Musante int
2525*1195e687SMark J Musante zpool_vdev_split(zpool_handle_t *zhp, char *newname, nvlist_t **newroot,
2526*1195e687SMark J Musante     nvlist_t *props, splitflags_t flags)
2527*1195e687SMark J Musante {
2528*1195e687SMark J Musante 	zfs_cmd_t zc = { 0 };
2529*1195e687SMark J Musante 	char msg[1024];
2530*1195e687SMark J Musante 	nvlist_t *tree, *config, **child, **newchild, *newconfig = NULL;
2531*1195e687SMark J Musante 	nvlist_t **varray = NULL, *zc_props = NULL;
2532*1195e687SMark J Musante 	uint_t c, children, newchildren, lastlog = 0, vcount, found = 0;
2533*1195e687SMark J Musante 	libzfs_handle_t *hdl = zhp->zpool_hdl;
2534*1195e687SMark J Musante 	uint64_t vers;
2535*1195e687SMark J Musante 	boolean_t freelist = B_FALSE, memory_err = B_TRUE;
2536*1195e687SMark J Musante 	int retval = 0;
2537*1195e687SMark J Musante 
2538*1195e687SMark J Musante 	(void) snprintf(msg, sizeof (msg),
2539*1195e687SMark J Musante 	    dgettext(TEXT_DOMAIN, "Unable to split %s"), zhp->zpool_name);
2540*1195e687SMark J Musante 
2541*1195e687SMark J Musante 	if (!zpool_name_valid(hdl, B_FALSE, newname))
2542*1195e687SMark J Musante 		return (zfs_error(hdl, EZFS_INVALIDNAME, msg));
2543*1195e687SMark J Musante 
2544*1195e687SMark J Musante 	if ((config = zpool_get_config(zhp, NULL)) == NULL) {
2545*1195e687SMark J Musante 		(void) fprintf(stderr, gettext("Internal error: unable to "
2546*1195e687SMark J Musante 		    "retrieve pool configuration\n"));
2547*1195e687SMark J Musante 		return (-1);
2548*1195e687SMark J Musante 	}
2549*1195e687SMark J Musante 
2550*1195e687SMark J Musante 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &tree)
2551*1195e687SMark J Musante 	    == 0);
2552*1195e687SMark J Musante 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, &vers) == 0);
2553*1195e687SMark J Musante 
2554*1195e687SMark J Musante 	if (props) {
2555*1195e687SMark J Musante 		if ((zc_props = zpool_valid_proplist(hdl, zhp->zpool_name,
2556*1195e687SMark J Musante 		    props, vers, B_TRUE, msg)) == NULL)
2557*1195e687SMark J Musante 			return (-1);
2558*1195e687SMark J Musante 	}
2559*1195e687SMark J Musante 
2560*1195e687SMark J Musante 	if (nvlist_lookup_nvlist_array(tree, ZPOOL_CONFIG_CHILDREN, &child,
2561*1195e687SMark J Musante 	    &children) != 0) {
2562*1195e687SMark J Musante 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2563*1195e687SMark J Musante 		    "Source pool is missing vdev tree"));
2564*1195e687SMark J Musante 		if (zc_props)
2565*1195e687SMark J Musante 			nvlist_free(zc_props);
2566*1195e687SMark J Musante 		return (-1);
2567*1195e687SMark J Musante 	}
2568*1195e687SMark J Musante 
2569*1195e687SMark J Musante 	varray = zfs_alloc(hdl, children * sizeof (nvlist_t *));
2570*1195e687SMark J Musante 	vcount = 0;
2571*1195e687SMark J Musante 
2572*1195e687SMark J Musante 	if (*newroot == NULL ||
2573*1195e687SMark J Musante 	    nvlist_lookup_nvlist_array(*newroot, ZPOOL_CONFIG_CHILDREN,
2574*1195e687SMark J Musante 	    &newchild, &newchildren) != 0)
2575*1195e687SMark J Musante 		newchildren = 0;
2576*1195e687SMark J Musante 
2577*1195e687SMark J Musante 	for (c = 0; c < children; c++) {
2578*1195e687SMark J Musante 		uint64_t is_log = B_FALSE, is_hole = B_FALSE;
2579*1195e687SMark J Musante 		char *type;
2580*1195e687SMark J Musante 		nvlist_t **mchild, *vdev;
2581*1195e687SMark J Musante 		uint_t mchildren;
2582*1195e687SMark J Musante 		int entry;
2583*1195e687SMark J Musante 
2584*1195e687SMark J Musante 		/*
2585*1195e687SMark J Musante 		 * Unlike cache & spares, slogs are stored in the
2586*1195e687SMark J Musante 		 * ZPOOL_CONFIG_CHILDREN array.  We filter them out here.
2587*1195e687SMark J Musante 		 */
2588*1195e687SMark J Musante 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
2589*1195e687SMark J Musante 		    &is_log);
2590*1195e687SMark J Musante 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_HOLE,
2591*1195e687SMark J Musante 		    &is_hole);
2592*1195e687SMark J Musante 		if (is_log || is_hole) {
2593*1195e687SMark J Musante 			/*
2594*1195e687SMark J Musante 			 * Create a hole vdev and put it in the config.
2595*1195e687SMark J Musante 			 */
2596*1195e687SMark J Musante 			if (nvlist_alloc(&vdev, NV_UNIQUE_NAME, 0) != 0)
2597*1195e687SMark J Musante 				goto out;
2598*1195e687SMark J Musante 			if (nvlist_add_string(vdev, ZPOOL_CONFIG_TYPE,
2599*1195e687SMark J Musante 			    VDEV_TYPE_HOLE) != 0)
2600*1195e687SMark J Musante 				goto out;
2601*1195e687SMark J Musante 			if (nvlist_add_uint64(vdev, ZPOOL_CONFIG_IS_HOLE,
2602*1195e687SMark J Musante 			    1) != 0)
2603*1195e687SMark J Musante 				goto out;
2604*1195e687SMark J Musante 			if (lastlog == 0)
2605*1195e687SMark J Musante 				lastlog = vcount;
2606*1195e687SMark J Musante 			varray[vcount++] = vdev;
2607*1195e687SMark J Musante 			continue;
2608*1195e687SMark J Musante 		}
2609*1195e687SMark J Musante 		lastlog = 0;
2610*1195e687SMark J Musante 		verify(nvlist_lookup_string(child[c], ZPOOL_CONFIG_TYPE, &type)
2611*1195e687SMark J Musante 		    == 0);
2612*1195e687SMark J Musante 		if (strcmp(type, VDEV_TYPE_MIRROR) != 0) {
2613*1195e687SMark J Musante 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2614*1195e687SMark J Musante 			    "Source pool must be composed only of mirrors\n"));
2615*1195e687SMark J Musante 			retval = zfs_error(hdl, EZFS_INVALCONFIG, msg);
2616*1195e687SMark J Musante 			goto out;
2617*1195e687SMark J Musante 		}
2618*1195e687SMark J Musante 
2619*1195e687SMark J Musante 		verify(nvlist_lookup_nvlist_array(child[c],
2620*1195e687SMark J Musante 		    ZPOOL_CONFIG_CHILDREN, &mchild, &mchildren) == 0);
2621*1195e687SMark J Musante 
2622*1195e687SMark J Musante 		/* find or add an entry for this top-level vdev */
2623*1195e687SMark J Musante 		if (newchildren > 0 &&
2624*1195e687SMark J Musante 		    (entry = find_vdev_entry(zhp, mchild, mchildren,
2625*1195e687SMark J Musante 		    newchild, newchildren)) >= 0) {
2626*1195e687SMark J Musante 			/* We found a disk that the user specified. */
2627*1195e687SMark J Musante 			vdev = mchild[entry];
2628*1195e687SMark J Musante 			++found;
2629*1195e687SMark J Musante 		} else {
2630*1195e687SMark J Musante 			/* User didn't specify a disk for this vdev. */
2631*1195e687SMark J Musante 			vdev = mchild[mchildren - 1];
2632*1195e687SMark J Musante 		}
2633*1195e687SMark J Musante 
2634*1195e687SMark J Musante 		if (nvlist_dup(vdev, &varray[vcount++], 0) != 0)
2635*1195e687SMark J Musante 			goto out;
2636*1195e687SMark J Musante 	}
2637*1195e687SMark J Musante 
2638*1195e687SMark J Musante 	/* did we find every disk the user specified? */
2639*1195e687SMark J Musante 	if (found != newchildren) {
2640*1195e687SMark J Musante 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "Device list must "
2641*1195e687SMark J Musante 		    "include at most one disk from each mirror"));
2642*1195e687SMark J Musante 		retval = zfs_error(hdl, EZFS_INVALCONFIG, msg);
2643*1195e687SMark J Musante 		goto out;
2644*1195e687SMark J Musante 	}
2645*1195e687SMark J Musante 
2646*1195e687SMark J Musante 	/* Prepare the nvlist for populating. */
2647*1195e687SMark J Musante 	if (*newroot == NULL) {
2648*1195e687SMark J Musante 		if (nvlist_alloc(newroot, NV_UNIQUE_NAME, 0) != 0)
2649*1195e687SMark J Musante 			goto out;
2650*1195e687SMark J Musante 		freelist = B_TRUE;
2651*1195e687SMark J Musante 		if (nvlist_add_string(*newroot, ZPOOL_CONFIG_TYPE,
2652*1195e687SMark J Musante 		    VDEV_TYPE_ROOT) != 0)
2653*1195e687SMark J Musante 			goto out;
2654*1195e687SMark J Musante 	} else {
2655*1195e687SMark J Musante 		verify(nvlist_remove_all(*newroot, ZPOOL_CONFIG_CHILDREN) == 0);
2656*1195e687SMark J Musante 	}
2657*1195e687SMark J Musante 
2658*1195e687SMark J Musante 	/* Add all the children we found */
2659*1195e687SMark J Musante 	if (nvlist_add_nvlist_array(*newroot, ZPOOL_CONFIG_CHILDREN, varray,
2660*1195e687SMark J Musante 	    lastlog == 0 ? vcount : lastlog) != 0)
2661*1195e687SMark J Musante 		goto out;
2662*1195e687SMark J Musante 
2663*1195e687SMark J Musante 	/*
2664*1195e687SMark J Musante 	 * If we're just doing a dry run, exit now with success.
2665*1195e687SMark J Musante 	 */
2666*1195e687SMark J Musante 	if (flags.dryrun) {
2667*1195e687SMark J Musante 		memory_err = B_FALSE;
2668*1195e687SMark J Musante 		freelist = B_FALSE;
2669*1195e687SMark J Musante 		goto out;
2670*1195e687SMark J Musante 	}
2671*1195e687SMark J Musante 
2672*1195e687SMark J Musante 	/* now build up the config list & call the ioctl */
2673*1195e687SMark J Musante 	if (nvlist_alloc(&newconfig, NV_UNIQUE_NAME, 0) != 0)
2674*1195e687SMark J Musante 		goto out;
2675*1195e687SMark J Musante 
2676*1195e687SMark J Musante 	if (nvlist_add_nvlist(newconfig,
2677*1195e687SMark J Musante 	    ZPOOL_CONFIG_VDEV_TREE, *newroot) != 0 ||
2678*1195e687SMark J Musante 	    nvlist_add_string(newconfig,
2679*1195e687SMark J Musante 	    ZPOOL_CONFIG_POOL_NAME, newname) != 0 ||
2680*1195e687SMark J Musante 	    nvlist_add_uint64(newconfig, ZPOOL_CONFIG_VERSION, vers) != 0)
2681*1195e687SMark J Musante 		goto out;
2682*1195e687SMark J Musante 
2683*1195e687SMark J Musante 	/*
2684*1195e687SMark J Musante 	 * The new pool is automatically part of the namespace unless we
2685*1195e687SMark J Musante 	 * explicitly export it.
2686*1195e687SMark J Musante 	 */
2687*1195e687SMark J Musante 	if (!flags.import)
2688*1195e687SMark J Musante 		zc.zc_cookie = ZPOOL_EXPORT_AFTER_SPLIT;
2689*1195e687SMark J Musante 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
2690*1195e687SMark J Musante 	(void) strlcpy(zc.zc_string, newname, sizeof (zc.zc_string));
2691*1195e687SMark J Musante 	if (zcmd_write_conf_nvlist(hdl, &zc, newconfig) != 0)
2692*1195e687SMark J Musante 		goto out;
2693*1195e687SMark J Musante 	if (zc_props != NULL && zcmd_write_src_nvlist(hdl, &zc, zc_props) != 0)
2694*1195e687SMark J Musante 		goto out;
2695*1195e687SMark J Musante 
2696*1195e687SMark J Musante 	if (zfs_ioctl(hdl, ZFS_IOC_VDEV_SPLIT, &zc) != 0) {
2697*1195e687SMark J Musante 		retval = zpool_standard_error(hdl, errno, msg);
2698*1195e687SMark J Musante 		goto out;
2699*1195e687SMark J Musante 	}
2700*1195e687SMark J Musante 
2701*1195e687SMark J Musante 	freelist = B_FALSE;
2702*1195e687SMark J Musante 	memory_err = B_FALSE;
2703*1195e687SMark J Musante 
2704*1195e687SMark J Musante out:
2705*1195e687SMark J Musante 	if (varray != NULL) {
2706*1195e687SMark J Musante 		int v;
2707*1195e687SMark J Musante 
2708*1195e687SMark J Musante 		for (v = 0; v < vcount; v++)
2709*1195e687SMark J Musante 			nvlist_free(varray[v]);
2710*1195e687SMark J Musante 		free(varray);
2711*1195e687SMark J Musante 	}
2712*1195e687SMark J Musante 	zcmd_free_nvlists(&zc);
2713*1195e687SMark J Musante 	if (zc_props)
2714*1195e687SMark J Musante 		nvlist_free(zc_props);
2715*1195e687SMark J Musante 	if (newconfig)
2716*1195e687SMark J Musante 		nvlist_free(newconfig);
2717*1195e687SMark J Musante 	if (freelist) {
2718*1195e687SMark J Musante 		nvlist_free(*newroot);
2719*1195e687SMark J Musante 		*newroot = NULL;
2720*1195e687SMark J Musante 	}
2721*1195e687SMark J Musante 
2722*1195e687SMark J Musante 	if (retval != 0)
2723*1195e687SMark J Musante 		return (retval);
2724*1195e687SMark J Musante 
2725*1195e687SMark J Musante 	if (memory_err)
2726*1195e687SMark J Musante 		return (no_memory(hdl));
2727*1195e687SMark J Musante 
2728*1195e687SMark J Musante 	return (0);
2729*1195e687SMark J Musante }
2730*1195e687SMark J Musante 
273199653d4eSeschrock /*
2732fa94a07fSbrendan  * Remove the given device.  Currently, this is supported only for hot spares
2733fa94a07fSbrendan  * and level 2 cache devices.
273499653d4eSeschrock  */
273599653d4eSeschrock int
273699653d4eSeschrock zpool_vdev_remove(zpool_handle_t *zhp, const char *path)
273799653d4eSeschrock {
273899653d4eSeschrock 	zfs_cmd_t zc = { 0 };
273999653d4eSeschrock 	char msg[1024];
274099653d4eSeschrock 	nvlist_t *tgt;
274188ecc943SGeorge Wilson 	boolean_t avail_spare, l2cache, islog;
274299653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
274388ecc943SGeorge Wilson 	uint64_t version;
274499653d4eSeschrock 
274599653d4eSeschrock 	(void) snprintf(msg, sizeof (msg),
274699653d4eSeschrock 	    dgettext(TEXT_DOMAIN, "cannot remove %s"), path);
274799653d4eSeschrock 
274899653d4eSeschrock 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
2749ee0eb9f2SEric Schrock 	if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache,
275088ecc943SGeorge Wilson 	    &islog)) == 0)
275199653d4eSeschrock 		return (zfs_error(hdl, EZFS_NODEVICE, msg));
275288ecc943SGeorge Wilson 	/*
275388ecc943SGeorge Wilson 	 * XXX - this should just go away.
275488ecc943SGeorge Wilson 	 */
275588ecc943SGeorge Wilson 	if (!avail_spare && !l2cache && !islog) {
275699653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
275788ecc943SGeorge Wilson 		    "only inactive hot spares, cache, top-level, "
275888ecc943SGeorge Wilson 		    "or log devices can be removed"));
275999653d4eSeschrock 		return (zfs_error(hdl, EZFS_NODEVICE, msg));
276099653d4eSeschrock 	}
276199653d4eSeschrock 
276288ecc943SGeorge Wilson 	version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
276388ecc943SGeorge Wilson 	if (islog && version < SPA_VERSION_HOLES) {
276488ecc943SGeorge Wilson 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
276588ecc943SGeorge Wilson 		    "pool must be upgrade to support log removal"));
276688ecc943SGeorge Wilson 		return (zfs_error(hdl, EZFS_BADVERSION, msg));
276788ecc943SGeorge Wilson 	}
276888ecc943SGeorge Wilson 
276999653d4eSeschrock 	verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
277099653d4eSeschrock 
2771ecd6cf80Smarks 	if (zfs_ioctl(hdl, ZFS_IOC_VDEV_REMOVE, &zc) == 0)
277299653d4eSeschrock 		return (0);
277399653d4eSeschrock 
277499653d4eSeschrock 	return (zpool_standard_error(hdl, errno, msg));
2775ea8dc4b6Seschrock }
2776ea8dc4b6Seschrock 
2777ea8dc4b6Seschrock /*
2778ea8dc4b6Seschrock  * Clear the errors for the pool, or the particular device if specified.
2779ea8dc4b6Seschrock  */
2780ea8dc4b6Seschrock int
2781468c413aSTim Haley zpool_clear(zpool_handle_t *zhp, const char *path, nvlist_t *rewindnvl)
2782ea8dc4b6Seschrock {
2783ea8dc4b6Seschrock 	zfs_cmd_t zc = { 0 };
2784ea8dc4b6Seschrock 	char msg[1024];
278599653d4eSeschrock 	nvlist_t *tgt;
2786468c413aSTim Haley 	zpool_rewind_policy_t policy;
2787fa94a07fSbrendan 	boolean_t avail_spare, l2cache;
278899653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
2789468c413aSTim Haley 	nvlist_t *nvi = NULL;
2790ea8dc4b6Seschrock 
2791ea8dc4b6Seschrock 	if (path)
2792ea8dc4b6Seschrock 		(void) snprintf(msg, sizeof (msg),
2793ea8dc4b6Seschrock 		    dgettext(TEXT_DOMAIN, "cannot clear errors for %s"),
2794e9dbad6fSeschrock 		    path);
2795ea8dc4b6Seschrock 	else
2796ea8dc4b6Seschrock 		(void) snprintf(msg, sizeof (msg),
2797ea8dc4b6Seschrock 		    dgettext(TEXT_DOMAIN, "cannot clear errors for %s"),
2798ea8dc4b6Seschrock 		    zhp->zpool_name);
2799ea8dc4b6Seschrock 
2800ea8dc4b6Seschrock 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
280199653d4eSeschrock 	if (path) {
2802fa94a07fSbrendan 		if ((tgt = zpool_find_vdev(zhp, path, &avail_spare,
2803ee0eb9f2SEric Schrock 		    &l2cache, NULL)) == 0)
280499653d4eSeschrock 			return (zfs_error(hdl, EZFS_NODEVICE, msg));
2805ea8dc4b6Seschrock 
2806fa94a07fSbrendan 		/*
2807fa94a07fSbrendan 		 * Don't allow error clearing for hot spares.  Do allow
2808fa94a07fSbrendan 		 * error clearing for l2cache devices.
2809fa94a07fSbrendan 		 */
2810a43d325bSek 		if (avail_spare)
281199653d4eSeschrock 			return (zfs_error(hdl, EZFS_ISSPARE, msg));
2812ea8dc4b6Seschrock 
281399653d4eSeschrock 		verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID,
281499653d4eSeschrock 		    &zc.zc_guid) == 0);
2815fa9e4066Sahrens 	}
2816fa9e4066Sahrens 
2817468c413aSTim Haley 	zpool_get_rewind_policy(rewindnvl, &policy);
2818468c413aSTim Haley 	zc.zc_cookie = policy.zrp_request;
2819468c413aSTim Haley 
2820468c413aSTim Haley 	if (zcmd_alloc_dst_nvlist(hdl, &zc, 8192) != 0)
2821468c413aSTim Haley 		return (-1);
2822468c413aSTim Haley 
2823468c413aSTim Haley 	if (zcmd_write_src_nvlist(zhp->zpool_hdl, &zc, rewindnvl) != 0)
2824468c413aSTim Haley 		return (-1);
2825468c413aSTim Haley 
2826468c413aSTim Haley 	if (zfs_ioctl(hdl, ZFS_IOC_CLEAR, &zc) == 0 ||
2827468c413aSTim Haley 	    ((policy.zrp_request & ZPOOL_TRY_REWIND) &&
2828468c413aSTim Haley 	    errno != EPERM && errno != EACCES)) {
2829468c413aSTim Haley 		if (policy.zrp_request &
2830468c413aSTim Haley 		    (ZPOOL_DO_REWIND | ZPOOL_TRY_REWIND)) {
2831468c413aSTim Haley 			(void) zcmd_read_dst_nvlist(hdl, &zc, &nvi);
2832468c413aSTim Haley 			zpool_rewind_exclaim(hdl, zc.zc_name,
2833468c413aSTim Haley 			    ((policy.zrp_request & ZPOOL_TRY_REWIND) != 0),
2834468c413aSTim Haley 			    nvi);
2835468c413aSTim Haley 			nvlist_free(nvi);
2836468c413aSTim Haley 		}
2837468c413aSTim Haley 		zcmd_free_nvlists(&zc);
283899653d4eSeschrock 		return (0);
2839468c413aSTim Haley 	}
284099653d4eSeschrock 
2841468c413aSTim Haley 	zcmd_free_nvlists(&zc);
284299653d4eSeschrock 	return (zpool_standard_error(hdl, errno, msg));
2843fa9e4066Sahrens }
2844fa9e4066Sahrens 
28453d7072f8Seschrock /*
28463d7072f8Seschrock  * Similar to zpool_clear(), but takes a GUID (used by fmd).
28473d7072f8Seschrock  */
28483d7072f8Seschrock int
28493d7072f8Seschrock zpool_vdev_clear(zpool_handle_t *zhp, uint64_t guid)
28503d7072f8Seschrock {
28513d7072f8Seschrock 	zfs_cmd_t zc = { 0 };
28523d7072f8Seschrock 	char msg[1024];
28533d7072f8Seschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
28543d7072f8Seschrock 
28553d7072f8Seschrock 	(void) snprintf(msg, sizeof (msg),
28563d7072f8Seschrock 	    dgettext(TEXT_DOMAIN, "cannot clear errors for %llx"),
28573d7072f8Seschrock 	    guid);
28583d7072f8Seschrock 
28593d7072f8Seschrock 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
28603d7072f8Seschrock 	zc.zc_guid = guid;
28613d7072f8Seschrock 
28623d7072f8Seschrock 	if (ioctl(hdl->libzfs_fd, ZFS_IOC_CLEAR, &zc) == 0)
28633d7072f8Seschrock 		return (0);
28643d7072f8Seschrock 
28653d7072f8Seschrock 	return (zpool_standard_error(hdl, errno, msg));
28663d7072f8Seschrock }
28673d7072f8Seschrock 
2868c67d9675Seschrock /*
2869c67d9675Seschrock  * Convert from a devid string to a path.
2870c67d9675Seschrock  */
2871c67d9675Seschrock static char *
2872c67d9675Seschrock devid_to_path(char *devid_str)
2873c67d9675Seschrock {
2874c67d9675Seschrock 	ddi_devid_t devid;
2875c67d9675Seschrock 	char *minor;
2876c67d9675Seschrock 	char *path;
2877c67d9675Seschrock 	devid_nmlist_t *list = NULL;
2878c67d9675Seschrock 	int ret;
2879c67d9675Seschrock 
2880c67d9675Seschrock 	if (devid_str_decode(devid_str, &devid, &minor) != 0)
2881c67d9675Seschrock 		return (NULL);
2882c67d9675Seschrock 
2883c67d9675Seschrock 	ret = devid_deviceid_to_nmlist("/dev", devid, minor, &list);
2884c67d9675Seschrock 
2885c67d9675Seschrock 	devid_str_free(minor);
2886c67d9675Seschrock 	devid_free(devid);
2887c67d9675Seschrock 
2888c67d9675Seschrock 	if (ret != 0)
2889c67d9675Seschrock 		return (NULL);
2890c67d9675Seschrock 
289199653d4eSeschrock 	if ((path = strdup(list[0].devname)) == NULL)
289299653d4eSeschrock 		return (NULL);
289399653d4eSeschrock 
2894c67d9675Seschrock 	devid_free_nmlist(list);
2895c67d9675Seschrock 
2896c67d9675Seschrock 	return (path);
2897c67d9675Seschrock }
2898c67d9675Seschrock 
2899c67d9675Seschrock /*
2900c67d9675Seschrock  * Convert from a path to a devid string.
2901c67d9675Seschrock  */
2902c67d9675Seschrock static char *
2903c67d9675Seschrock path_to_devid(const char *path)
2904c67d9675Seschrock {
2905c67d9675Seschrock 	int fd;
2906c67d9675Seschrock 	ddi_devid_t devid;
2907c67d9675Seschrock 	char *minor, *ret;
2908c67d9675Seschrock 
2909c67d9675Seschrock 	if ((fd = open(path, O_RDONLY)) < 0)
2910c67d9675Seschrock 		return (NULL);
2911c67d9675Seschrock 
2912c67d9675Seschrock 	minor = NULL;
2913c67d9675Seschrock 	ret = NULL;
2914c67d9675Seschrock 	if (devid_get(fd, &devid) == 0) {
2915c67d9675Seschrock 		if (devid_get_minor_name(fd, &minor) == 0)
2916c67d9675Seschrock 			ret = devid_str_encode(devid, minor);
2917c67d9675Seschrock 		if (minor != NULL)
2918c67d9675Seschrock 			devid_str_free(minor);
2919c67d9675Seschrock 		devid_free(devid);
2920c67d9675Seschrock 	}
2921c67d9675Seschrock 	(void) close(fd);
2922c67d9675Seschrock 
2923c67d9675Seschrock 	return (ret);
2924c67d9675Seschrock }
2925c67d9675Seschrock 
2926c67d9675Seschrock /*
2927c67d9675Seschrock  * Issue the necessary ioctl() to update the stored path value for the vdev.  We
2928c67d9675Seschrock  * ignore any failure here, since a common case is for an unprivileged user to
2929c67d9675Seschrock  * type 'zpool status', and we'll display the correct information anyway.
2930c67d9675Seschrock  */
2931c67d9675Seschrock static void
2932c67d9675Seschrock set_path(zpool_handle_t *zhp, nvlist_t *nv, const char *path)
2933c67d9675Seschrock {
2934c67d9675Seschrock 	zfs_cmd_t zc = { 0 };
2935c67d9675Seschrock 
2936c67d9675Seschrock 	(void) strncpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
2937e9dbad6fSeschrock 	(void) strncpy(zc.zc_value, path, sizeof (zc.zc_value));
2938c67d9675Seschrock 	verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
2939ea8dc4b6Seschrock 	    &zc.zc_guid) == 0);
2940c67d9675Seschrock 
294199653d4eSeschrock 	(void) ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SETPATH, &zc);
2942c67d9675Seschrock }
2943c67d9675Seschrock 
2944c67d9675Seschrock /*
2945c67d9675Seschrock  * Given a vdev, return the name to display in iostat.  If the vdev has a path,
2946c67d9675Seschrock  * we use that, stripping off any leading "/dev/dsk/"; if not, we use the type.
2947c67d9675Seschrock  * We also check if this is a whole disk, in which case we strip off the
2948c67d9675Seschrock  * trailing 's0' slice name.
2949c67d9675Seschrock  *
2950c67d9675Seschrock  * This routine is also responsible for identifying when disks have been
2951c67d9675Seschrock  * reconfigured in a new location.  The kernel will have opened the device by
2952c67d9675Seschrock  * devid, but the path will still refer to the old location.  To catch this, we
2953c67d9675Seschrock  * first do a path -> devid translation (which is fast for the common case).  If
2954c67d9675Seschrock  * the devid matches, we're done.  If not, we do a reverse devid -> path
2955c67d9675Seschrock  * translation and issue the appropriate ioctl() to update the path of the vdev.
2956c67d9675Seschrock  * If 'zhp' is NULL, then this is an exported pool, and we don't need to do any
2957c67d9675Seschrock  * of these checks.
2958c67d9675Seschrock  */
2959c67d9675Seschrock char *
296088ecc943SGeorge Wilson zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv,
296188ecc943SGeorge Wilson     boolean_t verbose)
2962c67d9675Seschrock {
2963c67d9675Seschrock 	char *path, *devid;
2964ea8dc4b6Seschrock 	uint64_t value;
2965ea8dc4b6Seschrock 	char buf[64];
29663d7072f8Seschrock 	vdev_stat_t *vs;
29673d7072f8Seschrock 	uint_t vsc;
2968c67d9675Seschrock 
2969ea8dc4b6Seschrock 	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT,
2970ea8dc4b6Seschrock 	    &value) == 0) {
2971ea8dc4b6Seschrock 		verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
2972ea8dc4b6Seschrock 		    &value) == 0);
29735ad82045Snd 		(void) snprintf(buf, sizeof (buf), "%llu",
29745ad82045Snd 		    (u_longlong_t)value);
2975ea8dc4b6Seschrock 		path = buf;
2976ea8dc4b6Seschrock 	} else if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) {
2977c67d9675Seschrock 
29783d7072f8Seschrock 		/*
29793d7072f8Seschrock 		 * If the device is dead (faulted, offline, etc) then don't
29803d7072f8Seschrock 		 * bother opening it.  Otherwise we may be forcing the user to
29813d7072f8Seschrock 		 * open a misbehaving device, which can have undesirable
29823d7072f8Seschrock 		 * effects.
29833d7072f8Seschrock 		 */
29843d7072f8Seschrock 		if ((nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_STATS,
29853d7072f8Seschrock 		    (uint64_t **)&vs, &vsc) != 0 ||
29863d7072f8Seschrock 		    vs->vs_state >= VDEV_STATE_DEGRADED) &&
29873d7072f8Seschrock 		    zhp != NULL &&
2988c67d9675Seschrock 		    nvlist_lookup_string(nv, ZPOOL_CONFIG_DEVID, &devid) == 0) {
2989c67d9675Seschrock 			/*
2990c67d9675Seschrock 			 * Determine if the current path is correct.
2991c67d9675Seschrock 			 */
2992c67d9675Seschrock 			char *newdevid = path_to_devid(path);
2993c67d9675Seschrock 
2994c67d9675Seschrock 			if (newdevid == NULL ||
2995c67d9675Seschrock 			    strcmp(devid, newdevid) != 0) {
2996c67d9675Seschrock 				char *newpath;
2997c67d9675Seschrock 
2998c67d9675Seschrock 				if ((newpath = devid_to_path(devid)) != NULL) {
2999c67d9675Seschrock 					/*
3000c67d9675Seschrock 					 * Update the path appropriately.
3001c67d9675Seschrock 					 */
3002c67d9675Seschrock 					set_path(zhp, nv, newpath);
300399653d4eSeschrock 					if (nvlist_add_string(nv,
300499653d4eSeschrock 					    ZPOOL_CONFIG_PATH, newpath) == 0)
300599653d4eSeschrock 						verify(nvlist_lookup_string(nv,
300699653d4eSeschrock 						    ZPOOL_CONFIG_PATH,
300799653d4eSeschrock 						    &path) == 0);
3008c67d9675Seschrock 					free(newpath);
3009c67d9675Seschrock 				}
3010c67d9675Seschrock 			}
3011c67d9675Seschrock 
301299653d4eSeschrock 			if (newdevid)
301399653d4eSeschrock 				devid_str_free(newdevid);
3014c67d9675Seschrock 		}
3015c67d9675Seschrock 
3016c67d9675Seschrock 		if (strncmp(path, "/dev/dsk/", 9) == 0)
3017c67d9675Seschrock 			path += 9;
3018c67d9675Seschrock 
3019c67d9675Seschrock 		if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK,
3020ea8dc4b6Seschrock 		    &value) == 0 && value) {
302199653d4eSeschrock 			char *tmp = zfs_strdup(hdl, path);
302299653d4eSeschrock 			if (tmp == NULL)
302399653d4eSeschrock 				return (NULL);
3024c67d9675Seschrock 			tmp[strlen(path) - 2] = '\0';
3025c67d9675Seschrock 			return (tmp);
3026c67d9675Seschrock 		}
3027c67d9675Seschrock 	} else {
3028c67d9675Seschrock 		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &path) == 0);
302999653d4eSeschrock 
303099653d4eSeschrock 		/*
303199653d4eSeschrock 		 * If it's a raidz device, we need to stick in the parity level.
303299653d4eSeschrock 		 */
303399653d4eSeschrock 		if (strcmp(path, VDEV_TYPE_RAIDZ) == 0) {
303499653d4eSeschrock 			verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NPARITY,
303599653d4eSeschrock 			    &value) == 0);
303699653d4eSeschrock 			(void) snprintf(buf, sizeof (buf), "%s%llu", path,
30375ad82045Snd 			    (u_longlong_t)value);
303899653d4eSeschrock 			path = buf;
303999653d4eSeschrock 		}
304088ecc943SGeorge Wilson 
304188ecc943SGeorge Wilson 		/*
304288ecc943SGeorge Wilson 		 * We identify each top-level vdev by using a <type-id>
304388ecc943SGeorge Wilson 		 * naming convention.
304488ecc943SGeorge Wilson 		 */
304588ecc943SGeorge Wilson 		if (verbose) {
304688ecc943SGeorge Wilson 			uint64_t id;
304788ecc943SGeorge Wilson 
304888ecc943SGeorge Wilson 			verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_ID,
304988ecc943SGeorge Wilson 			    &id) == 0);
305088ecc943SGeorge Wilson 			(void) snprintf(buf, sizeof (buf), "%s-%llu", path,
305188ecc943SGeorge Wilson 			    (u_longlong_t)id);
305288ecc943SGeorge Wilson 			path = buf;
305388ecc943SGeorge Wilson 		}
3054c67d9675Seschrock 	}
3055c67d9675Seschrock 
305699653d4eSeschrock 	return (zfs_strdup(hdl, path));
3057c67d9675Seschrock }
3058ea8dc4b6Seschrock 
3059ea8dc4b6Seschrock static int
3060ea8dc4b6Seschrock zbookmark_compare(const void *a, const void *b)
3061ea8dc4b6Seschrock {
3062ea8dc4b6Seschrock 	return (memcmp(a, b, sizeof (zbookmark_t)));
3063ea8dc4b6Seschrock }
3064ea8dc4b6Seschrock 
3065ea8dc4b6Seschrock /*
3066ea8dc4b6Seschrock  * Retrieve the persistent error log, uniquify the members, and return to the
3067ea8dc4b6Seschrock  * caller.
3068ea8dc4b6Seschrock  */
3069ea8dc4b6Seschrock int
307055434c77Sek zpool_get_errlog(zpool_handle_t *zhp, nvlist_t **nverrlistp)
3071ea8dc4b6Seschrock {
3072ea8dc4b6Seschrock 	zfs_cmd_t zc = { 0 };
3073ea8dc4b6Seschrock 	uint64_t count;
3074e9dbad6fSeschrock 	zbookmark_t *zb = NULL;
307555434c77Sek 	int i;
3076ea8dc4b6Seschrock 
3077ea8dc4b6Seschrock 	/*
3078ea8dc4b6Seschrock 	 * Retrieve the raw error list from the kernel.  If the number of errors
3079ea8dc4b6Seschrock 	 * has increased, allocate more space and continue until we get the
3080ea8dc4b6Seschrock 	 * entire list.
3081ea8dc4b6Seschrock 	 */
3082ea8dc4b6Seschrock 	verify(nvlist_lookup_uint64(zhp->zpool_config, ZPOOL_CONFIG_ERRCOUNT,
3083ea8dc4b6Seschrock 	    &count) == 0);
308475519f38Sek 	if (count == 0)
308575519f38Sek 		return (0);
3086e9dbad6fSeschrock 	if ((zc.zc_nvlist_dst = (uintptr_t)zfs_alloc(zhp->zpool_hdl,
30875ad82045Snd 	    count * sizeof (zbookmark_t))) == (uintptr_t)NULL)
308899653d4eSeschrock 		return (-1);
3089e9dbad6fSeschrock 	zc.zc_nvlist_dst_size = count;
3090ea8dc4b6Seschrock 	(void) strcpy(zc.zc_name, zhp->zpool_name);
3091ea8dc4b6Seschrock 	for (;;) {
309299653d4eSeschrock 		if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_ERROR_LOG,
309399653d4eSeschrock 		    &zc) != 0) {
3094e9dbad6fSeschrock 			free((void *)(uintptr_t)zc.zc_nvlist_dst);
3095ea8dc4b6Seschrock 			if (errno == ENOMEM) {
3096bf561db0Svb 				count = zc.zc_nvlist_dst_size;
3097e9dbad6fSeschrock 				if ((zc.zc_nvlist_dst = (uintptr_t)
3098bf561db0Svb 				    zfs_alloc(zhp->zpool_hdl, count *
3099bf561db0Svb 				    sizeof (zbookmark_t))) == (uintptr_t)NULL)
310099653d4eSeschrock 					return (-1);
3101ea8dc4b6Seschrock 			} else {
3102ea8dc4b6Seschrock 				return (-1);
3103ea8dc4b6Seschrock 			}
3104ea8dc4b6Seschrock 		} else {
3105ea8dc4b6Seschrock 			break;
3106ea8dc4b6Seschrock 		}
3107ea8dc4b6Seschrock 	}
3108ea8dc4b6Seschrock 
3109ea8dc4b6Seschrock 	/*
3110ea8dc4b6Seschrock 	 * Sort the resulting bookmarks.  This is a little confusing due to the
3111ea8dc4b6Seschrock 	 * implementation of ZFS_IOC_ERROR_LOG.  The bookmarks are copied last
3112e9dbad6fSeschrock 	 * to first, and 'zc_nvlist_dst_size' indicates the number of boomarks
3113ea8dc4b6Seschrock 	 * _not_ copied as part of the process.  So we point the start of our
3114ea8dc4b6Seschrock 	 * array appropriate and decrement the total number of elements.
3115ea8dc4b6Seschrock 	 */
3116e9dbad6fSeschrock 	zb = ((zbookmark_t *)(uintptr_t)zc.zc_nvlist_dst) +
3117e9dbad6fSeschrock 	    zc.zc_nvlist_dst_size;
3118e9dbad6fSeschrock 	count -= zc.zc_nvlist_dst_size;
3119ea8dc4b6Seschrock 
3120ea8dc4b6Seschrock 	qsort(zb, count, sizeof (zbookmark_t), zbookmark_compare);
3121ea8dc4b6Seschrock 
312255434c77Sek 	verify(nvlist_alloc(nverrlistp, 0, KM_SLEEP) == 0);
3123ea8dc4b6Seschrock 
3124ea8dc4b6Seschrock 	/*
312555434c77Sek 	 * Fill in the nverrlistp with nvlist's of dataset and object numbers.
3126ea8dc4b6Seschrock 	 */
3127ea8dc4b6Seschrock 	for (i = 0; i < count; i++) {
3128ea8dc4b6Seschrock 		nvlist_t *nv;
3129ea8dc4b6Seschrock 
3130c0a81264Sek 		/* ignoring zb_blkid and zb_level for now */
3131c0a81264Sek 		if (i > 0 && zb[i-1].zb_objset == zb[i].zb_objset &&
3132c0a81264Sek 		    zb[i-1].zb_object == zb[i].zb_object)
3133ea8dc4b6Seschrock 			continue;
3134ea8dc4b6Seschrock 
313555434c77Sek 		if (nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP) != 0)
313655434c77Sek 			goto nomem;
313755434c77Sek 		if (nvlist_add_uint64(nv, ZPOOL_ERR_DATASET,
313855434c77Sek 		    zb[i].zb_objset) != 0) {
313955434c77Sek 			nvlist_free(nv);
314099653d4eSeschrock 			goto nomem;
3141ea8dc4b6Seschrock 		}
314255434c77Sek 		if (nvlist_add_uint64(nv, ZPOOL_ERR_OBJECT,
314355434c77Sek 		    zb[i].zb_object) != 0) {
314455434c77Sek 			nvlist_free(nv);
314555434c77Sek 			goto nomem;
314655434c77Sek 		}
314755434c77Sek 		if (nvlist_add_nvlist(*nverrlistp, "ejk", nv) != 0) {
314855434c77Sek 			nvlist_free(nv);
314955434c77Sek 			goto nomem;
315055434c77Sek 		}
315155434c77Sek 		nvlist_free(nv);
3152ea8dc4b6Seschrock 	}
3153ea8dc4b6Seschrock 
31543ccfa83cSahrens 	free((void *)(uintptr_t)zc.zc_nvlist_dst);
3155ea8dc4b6Seschrock 	return (0);
315699653d4eSeschrock 
315799653d4eSeschrock nomem:
3158e9dbad6fSeschrock 	free((void *)(uintptr_t)zc.zc_nvlist_dst);
315999653d4eSeschrock 	return (no_memory(zhp->zpool_hdl));
3160ea8dc4b6Seschrock }
3161eaca9bbdSeschrock 
3162eaca9bbdSeschrock /*
3163eaca9bbdSeschrock  * Upgrade a ZFS pool to the latest on-disk version.
3164eaca9bbdSeschrock  */
3165eaca9bbdSeschrock int
3166990b4856Slling zpool_upgrade(zpool_handle_t *zhp, uint64_t new_version)
3167eaca9bbdSeschrock {
3168eaca9bbdSeschrock 	zfs_cmd_t zc = { 0 };
316999653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
3170eaca9bbdSeschrock 
3171eaca9bbdSeschrock 	(void) strcpy(zc.zc_name, zhp->zpool_name);
3172990b4856Slling 	zc.zc_cookie = new_version;
3173990b4856Slling 
3174ecd6cf80Smarks 	if (zfs_ioctl(hdl, ZFS_IOC_POOL_UPGRADE, &zc) != 0)
3175ece3d9b3Slling 		return (zpool_standard_error_fmt(hdl, errno,
317699653d4eSeschrock 		    dgettext(TEXT_DOMAIN, "cannot upgrade '%s'"),
317799653d4eSeschrock 		    zhp->zpool_name));
3178eaca9bbdSeschrock 	return (0);
3179eaca9bbdSeschrock }
318006eeb2adSek 
318106eeb2adSek void
31822a6b87f0Sek zpool_set_history_str(const char *subcommand, int argc, char **argv,
31832a6b87f0Sek     char *history_str)
318406eeb2adSek {
318506eeb2adSek 	int i;
318606eeb2adSek 
31872a6b87f0Sek 	(void) strlcpy(history_str, subcommand, HIS_MAX_RECORD_LEN);
31882a6b87f0Sek 	for (i = 1; i < argc; i++) {
31892a6b87f0Sek 		if (strlen(history_str) + 1 + strlen(argv[i]) >
31902a6b87f0Sek 		    HIS_MAX_RECORD_LEN)
31912a6b87f0Sek 			break;
31922a6b87f0Sek 		(void) strlcat(history_str, " ", HIS_MAX_RECORD_LEN);
31932a6b87f0Sek 		(void) strlcat(history_str, argv[i], HIS_MAX_RECORD_LEN);
31942a6b87f0Sek 	}
31952a6b87f0Sek }
31962a6b87f0Sek 
31972a6b87f0Sek /*
31982a6b87f0Sek  * Stage command history for logging.
31992a6b87f0Sek  */
32002a6b87f0Sek int
32012a6b87f0Sek zpool_stage_history(libzfs_handle_t *hdl, const char *history_str)
32022a6b87f0Sek {
32032a6b87f0Sek 	if (history_str == NULL)
32042a6b87f0Sek 		return (EINVAL);
32052a6b87f0Sek 
32062a6b87f0Sek 	if (strlen(history_str) > HIS_MAX_RECORD_LEN)
32072a6b87f0Sek 		return (EINVAL);
32082a6b87f0Sek 
3209228975ccSek 	if (hdl->libzfs_log_str != NULL)
3210ecd6cf80Smarks 		free(hdl->libzfs_log_str);
321106eeb2adSek 
32122a6b87f0Sek 	if ((hdl->libzfs_log_str = strdup(history_str)) == NULL)
32132a6b87f0Sek 		return (no_memory(hdl));
321406eeb2adSek 
32152a6b87f0Sek 	return (0);
321606eeb2adSek }
321706eeb2adSek 
321806eeb2adSek /*
321906eeb2adSek  * Perform ioctl to get some command history of a pool.
322006eeb2adSek  *
322106eeb2adSek  * 'buf' is the buffer to fill up to 'len' bytes.  'off' is the
322206eeb2adSek  * logical offset of the history buffer to start reading from.
322306eeb2adSek  *
322406eeb2adSek  * Upon return, 'off' is the next logical offset to read from and
322506eeb2adSek  * 'len' is the actual amount of bytes read into 'buf'.
322606eeb2adSek  */
322706eeb2adSek static int
322806eeb2adSek get_history(zpool_handle_t *zhp, char *buf, uint64_t *off, uint64_t *len)
322906eeb2adSek {
323006eeb2adSek 	zfs_cmd_t zc = { 0 };
323106eeb2adSek 	libzfs_handle_t *hdl = zhp->zpool_hdl;
323206eeb2adSek 
323306eeb2adSek 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
323406eeb2adSek 
323506eeb2adSek 	zc.zc_history = (uint64_t)(uintptr_t)buf;
323606eeb2adSek 	zc.zc_history_len = *len;
323706eeb2adSek 	zc.zc_history_offset = *off;
323806eeb2adSek 
323906eeb2adSek 	if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_HISTORY, &zc) != 0) {
324006eeb2adSek 		switch (errno) {
324106eeb2adSek 		case EPERM:
3242ece3d9b3Slling 			return (zfs_error_fmt(hdl, EZFS_PERM,
3243ece3d9b3Slling 			    dgettext(TEXT_DOMAIN,
324406eeb2adSek 			    "cannot show history for pool '%s'"),
324506eeb2adSek 			    zhp->zpool_name));
324606eeb2adSek 		case ENOENT:
3247ece3d9b3Slling 			return (zfs_error_fmt(hdl, EZFS_NOHISTORY,
324806eeb2adSek 			    dgettext(TEXT_DOMAIN, "cannot get history for pool "
324906eeb2adSek 			    "'%s'"), zhp->zpool_name));
3250d7306b64Sek 		case ENOTSUP:
3251d7306b64Sek 			return (zfs_error_fmt(hdl, EZFS_BADVERSION,
3252d7306b64Sek 			    dgettext(TEXT_DOMAIN, "cannot get history for pool "
3253d7306b64Sek 			    "'%s', pool must be upgraded"), zhp->zpool_name));
325406eeb2adSek 		default:
3255ece3d9b3Slling 			return (zpool_standard_error_fmt(hdl, errno,
325606eeb2adSek 			    dgettext(TEXT_DOMAIN,
325706eeb2adSek 			    "cannot get history for '%s'"), zhp->zpool_name));
325806eeb2adSek 		}
325906eeb2adSek 	}
326006eeb2adSek 
326106eeb2adSek 	*len = zc.zc_history_len;
326206eeb2adSek 	*off = zc.zc_history_offset;
326306eeb2adSek 
326406eeb2adSek 	return (0);
326506eeb2adSek }
326606eeb2adSek 
326706eeb2adSek /*
326806eeb2adSek  * Process the buffer of nvlists, unpacking and storing each nvlist record
326906eeb2adSek  * into 'records'.  'leftover' is set to the number of bytes that weren't
327006eeb2adSek  * processed as there wasn't a complete record.
327106eeb2adSek  */
32728f18d1faSGeorge Wilson int
327306eeb2adSek zpool_history_unpack(char *buf, uint64_t bytes_read, uint64_t *leftover,
327406eeb2adSek     nvlist_t ***records, uint_t *numrecords)
327506eeb2adSek {
327606eeb2adSek 	uint64_t reclen;
327706eeb2adSek 	nvlist_t *nv;
327806eeb2adSek 	int i;
327906eeb2adSek 
328006eeb2adSek 	while (bytes_read > sizeof (reclen)) {
328106eeb2adSek 
328206eeb2adSek 		/* get length of packed record (stored as little endian) */
328306eeb2adSek 		for (i = 0, reclen = 0; i < sizeof (reclen); i++)
328406eeb2adSek 			reclen += (uint64_t)(((uchar_t *)buf)[i]) << (8*i);
328506eeb2adSek 
328606eeb2adSek 		if (bytes_read < sizeof (reclen) + reclen)
328706eeb2adSek 			break;
328806eeb2adSek 
328906eeb2adSek 		/* unpack record */
329006eeb2adSek 		if (nvlist_unpack(buf + sizeof (reclen), reclen, &nv, 0) != 0)
329106eeb2adSek 			return (ENOMEM);
329206eeb2adSek 		bytes_read -= sizeof (reclen) + reclen;
329306eeb2adSek 		buf += sizeof (reclen) + reclen;
329406eeb2adSek 
329506eeb2adSek 		/* add record to nvlist array */
329606eeb2adSek 		(*numrecords)++;
329706eeb2adSek 		if (ISP2(*numrecords + 1)) {
329806eeb2adSek 			*records = realloc(*records,
329906eeb2adSek 			    *numrecords * 2 * sizeof (nvlist_t *));
330006eeb2adSek 		}
330106eeb2adSek 		(*records)[*numrecords - 1] = nv;
330206eeb2adSek 	}
330306eeb2adSek 
330406eeb2adSek 	*leftover = bytes_read;
330506eeb2adSek 	return (0);
330606eeb2adSek }
330706eeb2adSek 
330806eeb2adSek #define	HIS_BUF_LEN	(128*1024)
330906eeb2adSek 
331006eeb2adSek /*
331106eeb2adSek  * Retrieve the command history of a pool.
331206eeb2adSek  */
331306eeb2adSek int
331406eeb2adSek zpool_get_history(zpool_handle_t *zhp, nvlist_t **nvhisp)
331506eeb2adSek {
331606eeb2adSek 	char buf[HIS_BUF_LEN];
331706eeb2adSek 	uint64_t off = 0;
331806eeb2adSek 	nvlist_t **records = NULL;
331906eeb2adSek 	uint_t numrecords = 0;
332006eeb2adSek 	int err, i;
332106eeb2adSek 
332206eeb2adSek 	do {
332306eeb2adSek 		uint64_t bytes_read = sizeof (buf);
332406eeb2adSek 		uint64_t leftover;
332506eeb2adSek 
332606eeb2adSek 		if ((err = get_history(zhp, buf, &off, &bytes_read)) != 0)
332706eeb2adSek 			break;
332806eeb2adSek 
332906eeb2adSek 		/* if nothing else was read in, we're at EOF, just return */
333006eeb2adSek 		if (!bytes_read)
333106eeb2adSek 			break;
333206eeb2adSek 
333306eeb2adSek 		if ((err = zpool_history_unpack(buf, bytes_read,
333406eeb2adSek 		    &leftover, &records, &numrecords)) != 0)
333506eeb2adSek 			break;
333606eeb2adSek 		off -= leftover;
333706eeb2adSek 
333806eeb2adSek 		/* CONSTCOND */
333906eeb2adSek 	} while (1);
334006eeb2adSek 
334106eeb2adSek 	if (!err) {
334206eeb2adSek 		verify(nvlist_alloc(nvhisp, NV_UNIQUE_NAME, 0) == 0);
334306eeb2adSek 		verify(nvlist_add_nvlist_array(*nvhisp, ZPOOL_HIST_RECORD,
334406eeb2adSek 		    records, numrecords) == 0);
334506eeb2adSek 	}
334606eeb2adSek 	for (i = 0; i < numrecords; i++)
334706eeb2adSek 		nvlist_free(records[i]);
334806eeb2adSek 	free(records);
334906eeb2adSek 
335006eeb2adSek 	return (err);
335106eeb2adSek }
335255434c77Sek 
335355434c77Sek void
335455434c77Sek zpool_obj_to_path(zpool_handle_t *zhp, uint64_t dsobj, uint64_t obj,
335555434c77Sek     char *pathname, size_t len)
335655434c77Sek {
335755434c77Sek 	zfs_cmd_t zc = { 0 };
335855434c77Sek 	boolean_t mounted = B_FALSE;
335955434c77Sek 	char *mntpnt = NULL;
336055434c77Sek 	char dsname[MAXNAMELEN];
336155434c77Sek 
336255434c77Sek 	if (dsobj == 0) {
336355434c77Sek 		/* special case for the MOS */
336455434c77Sek 		(void) snprintf(pathname, len, "<metadata>:<0x%llx>", obj);
336555434c77Sek 		return;
336655434c77Sek 	}
336755434c77Sek 
336855434c77Sek 	/* get the dataset's name */
336955434c77Sek 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
337055434c77Sek 	zc.zc_obj = dsobj;
337155434c77Sek 	if (ioctl(zhp->zpool_hdl->libzfs_fd,
337255434c77Sek 	    ZFS_IOC_DSOBJ_TO_DSNAME, &zc) != 0) {
337355434c77Sek 		/* just write out a path of two object numbers */
337455434c77Sek 		(void) snprintf(pathname, len, "<0x%llx>:<0x%llx>",
337555434c77Sek 		    dsobj, obj);
337655434c77Sek 		return;
337755434c77Sek 	}
337855434c77Sek 	(void) strlcpy(dsname, zc.zc_value, sizeof (dsname));
337955434c77Sek 
338055434c77Sek 	/* find out if the dataset is mounted */
338155434c77Sek 	mounted = is_mounted(zhp->zpool_hdl, dsname, &mntpnt);
338255434c77Sek 
338355434c77Sek 	/* get the corrupted object's path */
338455434c77Sek 	(void) strlcpy(zc.zc_name, dsname, sizeof (zc.zc_name));
338555434c77Sek 	zc.zc_obj = obj;
338655434c77Sek 	if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_OBJ_TO_PATH,
338755434c77Sek 	    &zc) == 0) {
338855434c77Sek 		if (mounted) {
338955434c77Sek 			(void) snprintf(pathname, len, "%s%s", mntpnt,
339055434c77Sek 			    zc.zc_value);
339155434c77Sek 		} else {
339255434c77Sek 			(void) snprintf(pathname, len, "%s:%s",
339355434c77Sek 			    dsname, zc.zc_value);
339455434c77Sek 		}
339555434c77Sek 	} else {
339655434c77Sek 		(void) snprintf(pathname, len, "%s:<0x%llx>", dsname, obj);
339755434c77Sek 	}
339855434c77Sek 	free(mntpnt);
339955434c77Sek }
3400b1b8ab34Slling 
340115e6edf1Sgw /*
340215e6edf1Sgw  * Read the EFI label from the config, if a label does not exist then
340315e6edf1Sgw  * pass back the error to the caller. If the caller has passed a non-NULL
340415e6edf1Sgw  * diskaddr argument then we set it to the starting address of the EFI
340515e6edf1Sgw  * partition.
340615e6edf1Sgw  */
340715e6edf1Sgw static int
340815e6edf1Sgw read_efi_label(nvlist_t *config, diskaddr_t *sb)
340915e6edf1Sgw {
341015e6edf1Sgw 	char *path;
341115e6edf1Sgw 	int fd;
341215e6edf1Sgw 	char diskname[MAXPATHLEN];
341315e6edf1Sgw 	int err = -1;
341415e6edf1Sgw 
341515e6edf1Sgw 	if (nvlist_lookup_string(config, ZPOOL_CONFIG_PATH, &path) != 0)
341615e6edf1Sgw 		return (err);
341715e6edf1Sgw 
341815e6edf1Sgw 	(void) snprintf(diskname, sizeof (diskname), "%s%s", RDISK_ROOT,
341915e6edf1Sgw 	    strrchr(path, '/'));
342015e6edf1Sgw 	if ((fd = open(diskname, O_RDONLY|O_NDELAY)) >= 0) {
342115e6edf1Sgw 		struct dk_gpt *vtoc;
342215e6edf1Sgw 
342315e6edf1Sgw 		if ((err = efi_alloc_and_read(fd, &vtoc)) >= 0) {
342415e6edf1Sgw 			if (sb != NULL)
342515e6edf1Sgw 				*sb = vtoc->efi_parts[0].p_start;
342615e6edf1Sgw 			efi_free(vtoc);
342715e6edf1Sgw 		}
342815e6edf1Sgw 		(void) close(fd);
342915e6edf1Sgw 	}
343015e6edf1Sgw 	return (err);
343115e6edf1Sgw }
343215e6edf1Sgw 
34338488aeb5Staylor /*
34348488aeb5Staylor  * determine where a partition starts on a disk in the current
34358488aeb5Staylor  * configuration
34368488aeb5Staylor  */
34378488aeb5Staylor static diskaddr_t
34388488aeb5Staylor find_start_block(nvlist_t *config)
34398488aeb5Staylor {
34408488aeb5Staylor 	nvlist_t **child;
34418488aeb5Staylor 	uint_t c, children;
34428488aeb5Staylor 	diskaddr_t sb = MAXOFFSET_T;
34438488aeb5Staylor 	uint64_t wholedisk;
34448488aeb5Staylor 
34458488aeb5Staylor 	if (nvlist_lookup_nvlist_array(config,
34468488aeb5Staylor 	    ZPOOL_CONFIG_CHILDREN, &child, &children) != 0) {
34478488aeb5Staylor 		if (nvlist_lookup_uint64(config,
34488488aeb5Staylor 		    ZPOOL_CONFIG_WHOLE_DISK,
34498488aeb5Staylor 		    &wholedisk) != 0 || !wholedisk) {
34508488aeb5Staylor 			return (MAXOFFSET_T);
34518488aeb5Staylor 		}
345215e6edf1Sgw 		if (read_efi_label(config, &sb) < 0)
345315e6edf1Sgw 			sb = MAXOFFSET_T;
34548488aeb5Staylor 		return (sb);
34558488aeb5Staylor 	}
34568488aeb5Staylor 
34578488aeb5Staylor 	for (c = 0; c < children; c++) {
34588488aeb5Staylor 		sb = find_start_block(child[c]);
34598488aeb5Staylor 		if (sb != MAXOFFSET_T) {
34608488aeb5Staylor 			return (sb);
34618488aeb5Staylor 		}
34628488aeb5Staylor 	}
34638488aeb5Staylor 	return (MAXOFFSET_T);
34648488aeb5Staylor }
34658488aeb5Staylor 
34668488aeb5Staylor /*
34678488aeb5Staylor  * Label an individual disk.  The name provided is the short name,
34688488aeb5Staylor  * stripped of any leading /dev path.
34698488aeb5Staylor  */
34708488aeb5Staylor int
34718488aeb5Staylor zpool_label_disk(libzfs_handle_t *hdl, zpool_handle_t *zhp, char *name)
34728488aeb5Staylor {
34738488aeb5Staylor 	char path[MAXPATHLEN];
34748488aeb5Staylor 	struct dk_gpt *vtoc;
34758488aeb5Staylor 	int fd;
34768488aeb5Staylor 	size_t resv = EFI_MIN_RESV_SIZE;
34778488aeb5Staylor 	uint64_t slice_size;
34788488aeb5Staylor 	diskaddr_t start_block;
34798488aeb5Staylor 	char errbuf[1024];
34808488aeb5Staylor 
3481c6ef114fSmmusante 	/* prepare an error message just in case */
3482c6ef114fSmmusante 	(void) snprintf(errbuf, sizeof (errbuf),
3483c6ef114fSmmusante 	    dgettext(TEXT_DOMAIN, "cannot label '%s'"), name);
3484c6ef114fSmmusante 
34858488aeb5Staylor 	if (zhp) {
34868488aeb5Staylor 		nvlist_t *nvroot;
34878488aeb5Staylor 
3488b5b76fecSGeorge Wilson 		if (pool_is_bootable(zhp)) {
3489b5b76fecSGeorge Wilson 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3490b5b76fecSGeorge Wilson 			    "EFI labeled devices are not supported on root "
3491b5b76fecSGeorge Wilson 			    "pools."));
3492b5b76fecSGeorge Wilson 			return (zfs_error(hdl, EZFS_POOL_NOTSUP, errbuf));
3493b5b76fecSGeorge Wilson 		}
3494b5b76fecSGeorge Wilson 
34958488aeb5Staylor 		verify(nvlist_lookup_nvlist(zhp->zpool_config,
34968488aeb5Staylor 		    ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
34978488aeb5Staylor 
34988488aeb5Staylor 		if (zhp->zpool_start_block == 0)
34998488aeb5Staylor 			start_block = find_start_block(nvroot);
35008488aeb5Staylor 		else
35018488aeb5Staylor 			start_block = zhp->zpool_start_block;
35028488aeb5Staylor 		zhp->zpool_start_block = start_block;
35038488aeb5Staylor 	} else {
35048488aeb5Staylor 		/* new pool */
35058488aeb5Staylor 		start_block = NEW_START_BLOCK;
35068488aeb5Staylor 	}
35078488aeb5Staylor 
35088488aeb5Staylor 	(void) snprintf(path, sizeof (path), "%s/%s%s", RDISK_ROOT, name,
35098488aeb5Staylor 	    BACKUP_SLICE);
35108488aeb5Staylor 
35118488aeb5Staylor 	if ((fd = open(path, O_RDWR | O_NDELAY)) < 0) {
35128488aeb5Staylor 		/*
35138488aeb5Staylor 		 * This shouldn't happen.  We've long since verified that this
35148488aeb5Staylor 		 * is a valid device.
35158488aeb5Staylor 		 */
3516c6ef114fSmmusante 		zfs_error_aux(hdl,
3517c6ef114fSmmusante 		    dgettext(TEXT_DOMAIN, "unable to open device"));
35188488aeb5Staylor 		return (zfs_error(hdl, EZFS_OPENFAILED, errbuf));
35198488aeb5Staylor 	}
35208488aeb5Staylor 
35218488aeb5Staylor 	if (efi_alloc_and_init(fd, EFI_NUMPAR, &vtoc) != 0) {
35228488aeb5Staylor 		/*
35238488aeb5Staylor 		 * The only way this can fail is if we run out of memory, or we
35248488aeb5Staylor 		 * were unable to read the disk's capacity
35258488aeb5Staylor 		 */
35268488aeb5Staylor 		if (errno == ENOMEM)
35278488aeb5Staylor 			(void) no_memory(hdl);
35288488aeb5Staylor 
35298488aeb5Staylor 		(void) close(fd);
3530c6ef114fSmmusante 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3531c6ef114fSmmusante 		    "unable to read disk capacity"), name);
35328488aeb5Staylor 
35338488aeb5Staylor 		return (zfs_error(hdl, EZFS_NOCAP, errbuf));
35348488aeb5Staylor 	}
35358488aeb5Staylor 
35368488aeb5Staylor 	slice_size = vtoc->efi_last_u_lba + 1;
35378488aeb5Staylor 	slice_size -= EFI_MIN_RESV_SIZE;
35388488aeb5Staylor 	if (start_block == MAXOFFSET_T)
35398488aeb5Staylor 		start_block = NEW_START_BLOCK;
35408488aeb5Staylor 	slice_size -= start_block;
35418488aeb5Staylor 
35428488aeb5Staylor 	vtoc->efi_parts[0].p_start = start_block;
35438488aeb5Staylor 	vtoc->efi_parts[0].p_size = slice_size;
35448488aeb5Staylor 
35458488aeb5Staylor 	/*
35468488aeb5Staylor 	 * Why we use V_USR: V_BACKUP confuses users, and is considered
35478488aeb5Staylor 	 * disposable by some EFI utilities (since EFI doesn't have a backup
35488488aeb5Staylor 	 * slice).  V_UNASSIGNED is supposed to be used only for zero size
35498488aeb5Staylor 	 * partitions, and efi_write() will fail if we use it.  V_ROOT, V_BOOT,
35508488aeb5Staylor 	 * etc. were all pretty specific.  V_USR is as close to reality as we
35518488aeb5Staylor 	 * can get, in the absence of V_OTHER.
35528488aeb5Staylor 	 */
35538488aeb5Staylor 	vtoc->efi_parts[0].p_tag = V_USR;
35548488aeb5Staylor 	(void) strcpy(vtoc->efi_parts[0].p_name, "zfs");
35558488aeb5Staylor 
35568488aeb5Staylor 	vtoc->efi_parts[8].p_start = slice_size + start_block;
35578488aeb5Staylor 	vtoc->efi_parts[8].p_size = resv;
35588488aeb5Staylor 	vtoc->efi_parts[8].p_tag = V_RESERVED;
35598488aeb5Staylor 
35608488aeb5Staylor 	if (efi_write(fd, vtoc) != 0) {
35618488aeb5Staylor 		/*
35628488aeb5Staylor 		 * Some block drivers (like pcata) may not support EFI
35638488aeb5Staylor 		 * GPT labels.  Print out a helpful error message dir-
35648488aeb5Staylor 		 * ecting the user to manually label the disk and give
35658488aeb5Staylor 		 * a specific slice.
35668488aeb5Staylor 		 */
35678488aeb5Staylor 		(void) close(fd);
35688488aeb5Staylor 		efi_free(vtoc);
35698488aeb5Staylor 
35708488aeb5Staylor 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3571c6ef114fSmmusante 		    "try using fdisk(1M) and then provide a specific slice"));
35728488aeb5Staylor 		return (zfs_error(hdl, EZFS_LABELFAILED, errbuf));
35738488aeb5Staylor 	}
35748488aeb5Staylor 
35758488aeb5Staylor 	(void) close(fd);
35768488aeb5Staylor 	efi_free(vtoc);
35778488aeb5Staylor 	return (0);
35788488aeb5Staylor }
3579e7cbe64fSgw 
3580e7cbe64fSgw static boolean_t
3581e7cbe64fSgw supported_dump_vdev_type(libzfs_handle_t *hdl, nvlist_t *config, char *errbuf)
3582e7cbe64fSgw {
3583e7cbe64fSgw 	char *type;
3584e7cbe64fSgw 	nvlist_t **child;
3585e7cbe64fSgw 	uint_t children, c;
3586e7cbe64fSgw 
3587e7cbe64fSgw 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_TYPE, &type) == 0);
3588e7cbe64fSgw 	if (strcmp(type, VDEV_TYPE_RAIDZ) == 0 ||
3589e7cbe64fSgw 	    strcmp(type, VDEV_TYPE_FILE) == 0 ||
3590e7cbe64fSgw 	    strcmp(type, VDEV_TYPE_LOG) == 0 ||
359188ecc943SGeorge Wilson 	    strcmp(type, VDEV_TYPE_HOLE) == 0 ||
3592e7cbe64fSgw 	    strcmp(type, VDEV_TYPE_MISSING) == 0) {
3593e7cbe64fSgw 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3594e7cbe64fSgw 		    "vdev type '%s' is not supported"), type);
3595e7cbe64fSgw 		(void) zfs_error(hdl, EZFS_VDEVNOTSUP, errbuf);
3596e7cbe64fSgw 		return (B_FALSE);
3597e7cbe64fSgw 	}
3598e7cbe64fSgw 	if (nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_CHILDREN,
3599e7cbe64fSgw 	    &child, &children) == 0) {
3600e7cbe64fSgw 		for (c = 0; c < children; c++) {
3601e7cbe64fSgw 			if (!supported_dump_vdev_type(hdl, child[c], errbuf))
3602e7cbe64fSgw 				return (B_FALSE);
3603e7cbe64fSgw 		}
3604e7cbe64fSgw 	}
3605e7cbe64fSgw 	return (B_TRUE);
3606e7cbe64fSgw }
3607e7cbe64fSgw 
3608e7cbe64fSgw /*
3609e7cbe64fSgw  * check if this zvol is allowable for use as a dump device; zero if
3610e7cbe64fSgw  * it is, > 0 if it isn't, < 0 if it isn't a zvol
3611e7cbe64fSgw  */
3612e7cbe64fSgw int
3613e7cbe64fSgw zvol_check_dump_config(char *arg)
3614e7cbe64fSgw {
3615e7cbe64fSgw 	zpool_handle_t *zhp = NULL;
3616e7cbe64fSgw 	nvlist_t *config, *nvroot;
3617e7cbe64fSgw 	char *p, *volname;
3618e7cbe64fSgw 	nvlist_t **top;
3619e7cbe64fSgw 	uint_t toplevels;
3620e7cbe64fSgw 	libzfs_handle_t *hdl;
3621e7cbe64fSgw 	char errbuf[1024];
3622e7cbe64fSgw 	char poolname[ZPOOL_MAXNAMELEN];
3623e7cbe64fSgw 	int pathlen = strlen(ZVOL_FULL_DEV_DIR);
3624e7cbe64fSgw 	int ret = 1;
3625e7cbe64fSgw 
3626e7cbe64fSgw 	if (strncmp(arg, ZVOL_FULL_DEV_DIR, pathlen)) {
3627e7cbe64fSgw 		return (-1);
3628e7cbe64fSgw 	}
3629e7cbe64fSgw 
3630e7cbe64fSgw 	(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
3631e7cbe64fSgw 	    "dump is not supported on device '%s'"), arg);
3632e7cbe64fSgw 
3633e7cbe64fSgw 	if ((hdl = libzfs_init()) == NULL)
3634e7cbe64fSgw 		return (1);
3635e7cbe64fSgw 	libzfs_print_on_error(hdl, B_TRUE);
3636e7cbe64fSgw 
3637e7cbe64fSgw 	volname = arg + pathlen;
3638e7cbe64fSgw 
3639e7cbe64fSgw 	/* check the configuration of the pool */
3640e7cbe64fSgw 	if ((p = strchr(volname, '/')) == NULL) {
3641e7cbe64fSgw 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3642e7cbe64fSgw 		    "malformed dataset name"));
3643e7cbe64fSgw 		(void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf);
3644e7cbe64fSgw 		return (1);
3645e7cbe64fSgw 	} else if (p - volname >= ZFS_MAXNAMELEN) {
3646e7cbe64fSgw 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3647e7cbe64fSgw 		    "dataset name is too long"));
3648e7cbe64fSgw 		(void) zfs_error(hdl, EZFS_NAMETOOLONG, errbuf);
3649e7cbe64fSgw 		return (1);
3650e7cbe64fSgw 	} else {
3651e7cbe64fSgw 		(void) strncpy(poolname, volname, p - volname);
3652e7cbe64fSgw 		poolname[p - volname] = '\0';
3653e7cbe64fSgw 	}
3654e7cbe64fSgw 
3655e7cbe64fSgw 	if ((zhp = zpool_open(hdl, poolname)) == NULL) {
3656e7cbe64fSgw 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3657e7cbe64fSgw 		    "could not open pool '%s'"), poolname);
3658e7cbe64fSgw 		(void) zfs_error(hdl, EZFS_OPENFAILED, errbuf);
3659e7cbe64fSgw 		goto out;
3660e7cbe64fSgw 	}
3661e7cbe64fSgw 	config = zpool_get_config(zhp, NULL);
3662e7cbe64fSgw 	if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
3663e7cbe64fSgw 	    &nvroot) != 0) {
3664e7cbe64fSgw 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3665e7cbe64fSgw 		    "could not obtain vdev configuration for  '%s'"), poolname);
3666e7cbe64fSgw 		(void) zfs_error(hdl, EZFS_INVALCONFIG, errbuf);
3667e7cbe64fSgw 		goto out;
3668e7cbe64fSgw 	}
3669e7cbe64fSgw 
3670e7cbe64fSgw 	verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
3671e7cbe64fSgw 	    &top, &toplevels) == 0);
3672e7cbe64fSgw 	if (toplevels != 1) {
3673e7cbe64fSgw 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3674e7cbe64fSgw 		    "'%s' has multiple top level vdevs"), poolname);
3675e7cbe64fSgw 		(void) zfs_error(hdl, EZFS_DEVOVERFLOW, errbuf);
3676e7cbe64fSgw 		goto out;
3677e7cbe64fSgw 	}
3678e7cbe64fSgw 
3679e7cbe64fSgw 	if (!supported_dump_vdev_type(hdl, top[0], errbuf)) {
3680e7cbe64fSgw 		goto out;
3681e7cbe64fSgw 	}
3682e7cbe64fSgw 	ret = 0;
3683e7cbe64fSgw 
3684e7cbe64fSgw out:
3685e7cbe64fSgw 	if (zhp)
3686e7cbe64fSgw 		zpool_close(zhp);
3687e7cbe64fSgw 	libzfs_fini(hdl);
3688e7cbe64fSgw 	return (ret);
3689e7cbe64fSgw }
3690