xref: /illumos-gate/usr/src/lib/libzfs/common/libzfs_pool.c (revision 04e56356520b98d5a93c496b10f02530bb6647e0)
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 /*
233f9d6ad7SLin Ling  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
245cabbc6bSPrashanth Sreenivasa  * Copyright (c) 2011, 2017 by Delphix. All rights reserved.
25810e43b2SBill Pijewski  * Copyright (c) 2013, Joyent, Inc. All rights reserved.
266401734dSWill Andrews  * Copyright 2016 Nexenta Systems, Inc.
2788f61deeSIgor Kozhukhov  * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
281702cce7SAlek Pinchuk  * Copyright (c) 2017 Datto Inc.
29fa9e4066Sahrens  */
30fa9e4066Sahrens 
31fa9e4066Sahrens #include <ctype.h>
32fa9e4066Sahrens #include <errno.h>
33fa9e4066Sahrens #include <devid.h>
34fa9e4066Sahrens #include <fcntl.h>
35fa9e4066Sahrens #include <libintl.h>
36fa9e4066Sahrens #include <stdio.h>
37fa9e4066Sahrens #include <stdlib.h>
38f3861e1aSahl #include <strings.h>
39fa9e4066Sahrens #include <unistd.h>
404445fffbSMatthew Ahrens #include <libgen.h>
418488aeb5Staylor #include <sys/efi_partition.h>
428488aeb5Staylor #include <sys/vtoc.h>
43fa9e4066Sahrens #include <sys/zfs_ioctl.h>
44573ca77eSGeorge Wilson #include <dlfcn.h>
45fa9e4066Sahrens 
46fa9e4066Sahrens #include "zfs_namecheck.h"
47b1b8ab34Slling #include "zfs_prop.h"
48fa9e4066Sahrens #include "libzfs_impl.h"
49468c413aSTim Haley #include "zfs_comutil.h"
50ad135b5dSChristopher Siden #include "zfeature_common.h"
51fa9e4066Sahrens 
527855d95bSToomas Soome static int read_efi_label(nvlist_t *, diskaddr_t *, boolean_t *);
532ba5f978SAlan Somers static boolean_t zpool_vdev_is_interior(const char *name);
54990b4856Slling 
55573ca77eSGeorge Wilson #define	BACKUP_SLICE	"s2"
56573ca77eSGeorge Wilson 
57f9af39baSGeorge Wilson typedef struct prop_flags {
58f9af39baSGeorge Wilson 	int create:1;	/* Validate property on creation */
59f9af39baSGeorge Wilson 	int import:1;	/* Validate property on import */
60f9af39baSGeorge Wilson } prop_flags_t;
61f9af39baSGeorge Wilson 
62990b4856Slling /*
63990b4856Slling  * ====================================================================
64990b4856Slling  *   zpool property functions
65990b4856Slling  * ====================================================================
66990b4856Slling  */
67990b4856Slling 
68990b4856Slling static int
69990b4856Slling zpool_get_all_props(zpool_handle_t *zhp)
70990b4856Slling {
71990b4856Slling 	zfs_cmd_t zc = { 0 };
72990b4856Slling 	libzfs_handle_t *hdl = zhp->zpool_hdl;
73990b4856Slling 
74990b4856Slling 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
75990b4856Slling 
76990b4856Slling 	if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0)
77990b4856Slling 		return (-1);
78990b4856Slling 
79990b4856Slling 	while (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_PROPS, &zc) != 0) {
80990b4856Slling 		if (errno == ENOMEM) {
81990b4856Slling 			if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
82990b4856Slling 				zcmd_free_nvlists(&zc);
83990b4856Slling 				return (-1);
84990b4856Slling 			}
85990b4856Slling 		} else {
86990b4856Slling 			zcmd_free_nvlists(&zc);
87990b4856Slling 			return (-1);
88990b4856Slling 		}
89990b4856Slling 	}
90990b4856Slling 
91990b4856Slling 	if (zcmd_read_dst_nvlist(hdl, &zc, &zhp->zpool_props) != 0) {
92990b4856Slling 		zcmd_free_nvlists(&zc);
93990b4856Slling 		return (-1);
94990b4856Slling 	}
95990b4856Slling 
96990b4856Slling 	zcmd_free_nvlists(&zc);
97990b4856Slling 
98990b4856Slling 	return (0);
99990b4856Slling }
100990b4856Slling 
101990b4856Slling static int
102990b4856Slling zpool_props_refresh(zpool_handle_t *zhp)
103990b4856Slling {
104990b4856Slling 	nvlist_t *old_props;
105990b4856Slling 
106990b4856Slling 	old_props = zhp->zpool_props;
107990b4856Slling 
108990b4856Slling 	if (zpool_get_all_props(zhp) != 0)
109990b4856Slling 		return (-1);
110990b4856Slling 
111990b4856Slling 	nvlist_free(old_props);
112990b4856Slling 	return (0);
113990b4856Slling }
114990b4856Slling 
115990b4856Slling static char *
116990b4856Slling zpool_get_prop_string(zpool_handle_t *zhp, zpool_prop_t prop,
117990b4856Slling     zprop_source_t *src)
118990b4856Slling {
119990b4856Slling 	nvlist_t *nv, *nvl;
120990b4856Slling 	uint64_t ival;
121990b4856Slling 	char *value;
122990b4856Slling 	zprop_source_t source;
123990b4856Slling 
124990b4856Slling 	nvl = zhp->zpool_props;
125990b4856Slling 	if (nvlist_lookup_nvlist(nvl, zpool_prop_to_name(prop), &nv) == 0) {
126990b4856Slling 		verify(nvlist_lookup_uint64(nv, ZPROP_SOURCE, &ival) == 0);
127990b4856Slling 		source = ival;
128990b4856Slling 		verify(nvlist_lookup_string(nv, ZPROP_VALUE, &value) == 0);
129990b4856Slling 	} else {
130990b4856Slling 		source = ZPROP_SRC_DEFAULT;
131990b4856Slling 		if ((value = (char *)zpool_prop_default_string(prop)) == NULL)
132990b4856Slling 			value = "-";
133990b4856Slling 	}
134990b4856Slling 
135990b4856Slling 	if (src)
136990b4856Slling 		*src = source;
137990b4856Slling 
138990b4856Slling 	return (value);
139990b4856Slling }
140990b4856Slling 
141990b4856Slling uint64_t
142990b4856Slling zpool_get_prop_int(zpool_handle_t *zhp, zpool_prop_t prop, zprop_source_t *src)
143990b4856Slling {
144990b4856Slling 	nvlist_t *nv, *nvl;
145990b4856Slling 	uint64_t value;
146990b4856Slling 	zprop_source_t source;
147990b4856Slling 
148b87f3af3Sperrin 	if (zhp->zpool_props == NULL && zpool_get_all_props(zhp)) {
149b87f3af3Sperrin 		/*
150b87f3af3Sperrin 		 * zpool_get_all_props() has most likely failed because
151b87f3af3Sperrin 		 * the pool is faulted, but if all we need is the top level
152b87f3af3Sperrin 		 * vdev's guid then get it from the zhp config nvlist.
153b87f3af3Sperrin 		 */
154b87f3af3Sperrin 		if ((prop == ZPOOL_PROP_GUID) &&
155b87f3af3Sperrin 		    (nvlist_lookup_nvlist(zhp->zpool_config,
156b87f3af3Sperrin 		    ZPOOL_CONFIG_VDEV_TREE, &nv) == 0) &&
157b87f3af3Sperrin 		    (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &value)
158b87f3af3Sperrin 		    == 0)) {
159b87f3af3Sperrin 			return (value);
160b87f3af3Sperrin 		}
161990b4856Slling 		return (zpool_prop_default_numeric(prop));
162b87f3af3Sperrin 	}
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, &value) == 0);
167990b4856Slling 		source = value;
168990b4856Slling 		verify(nvlist_lookup_uint64(nv, ZPROP_VALUE, &value) == 0);
169990b4856Slling 	} else {
170990b4856Slling 		source = ZPROP_SRC_DEFAULT;
171990b4856Slling 		value = zpool_prop_default_numeric(prop);
172990b4856Slling 	}
173990b4856Slling 
174990b4856Slling 	if (src)
175990b4856Slling 		*src = source;
176990b4856Slling 
177990b4856Slling 	return (value);
178990b4856Slling }
179990b4856Slling 
180990b4856Slling /*
181990b4856Slling  * Map VDEV STATE to printed strings.
182990b4856Slling  */
1836401734dSWill Andrews const char *
184990b4856Slling zpool_state_to_name(vdev_state_t state, vdev_aux_t aux)
185990b4856Slling {
186990b4856Slling 	switch (state) {
187990b4856Slling 	case VDEV_STATE_CLOSED:
188990b4856Slling 	case VDEV_STATE_OFFLINE:
189990b4856Slling 		return (gettext("OFFLINE"));
190990b4856Slling 	case VDEV_STATE_REMOVED:
191990b4856Slling 		return (gettext("REMOVED"));
192990b4856Slling 	case VDEV_STATE_CANT_OPEN:
193b87f3af3Sperrin 		if (aux == VDEV_AUX_CORRUPT_DATA || aux == VDEV_AUX_BAD_LOG)
194990b4856Slling 			return (gettext("FAULTED"));
1951195e687SMark J Musante 		else if (aux == VDEV_AUX_SPLIT_POOL)
1961195e687SMark J Musante 			return (gettext("SPLIT"));
197990b4856Slling 		else
198990b4856Slling 			return (gettext("UNAVAIL"));
199990b4856Slling 	case VDEV_STATE_FAULTED:
200990b4856Slling 		return (gettext("FAULTED"));
201990b4856Slling 	case VDEV_STATE_DEGRADED:
202990b4856Slling 		return (gettext("DEGRADED"));
203990b4856Slling 	case VDEV_STATE_HEALTHY:
204990b4856Slling 		return (gettext("ONLINE"));
20588f61deeSIgor Kozhukhov 
20688f61deeSIgor Kozhukhov 	default:
20788f61deeSIgor Kozhukhov 		break;
208990b4856Slling 	}
209990b4856Slling 
210990b4856Slling 	return (gettext("UNKNOWN"));
211990b4856Slling }
212990b4856Slling 
2136401734dSWill Andrews /*
2146401734dSWill Andrews  * Map POOL STATE to printed strings.
2156401734dSWill Andrews  */
2166401734dSWill Andrews const char *
2176401734dSWill Andrews zpool_pool_state_to_name(pool_state_t state)
2186401734dSWill Andrews {
2196401734dSWill Andrews 	switch (state) {
2206401734dSWill Andrews 	case POOL_STATE_ACTIVE:
2216401734dSWill Andrews 		return (gettext("ACTIVE"));
2226401734dSWill Andrews 	case POOL_STATE_EXPORTED:
2236401734dSWill Andrews 		return (gettext("EXPORTED"));
2246401734dSWill Andrews 	case POOL_STATE_DESTROYED:
2256401734dSWill Andrews 		return (gettext("DESTROYED"));
2266401734dSWill Andrews 	case POOL_STATE_SPARE:
2276401734dSWill Andrews 		return (gettext("SPARE"));
2286401734dSWill Andrews 	case POOL_STATE_L2CACHE:
2296401734dSWill Andrews 		return (gettext("L2CACHE"));
2306401734dSWill Andrews 	case POOL_STATE_UNINITIALIZED:
2316401734dSWill Andrews 		return (gettext("UNINITIALIZED"));
2326401734dSWill Andrews 	case POOL_STATE_UNAVAIL:
2336401734dSWill Andrews 		return (gettext("UNAVAIL"));
2346401734dSWill Andrews 	case POOL_STATE_POTENTIALLY_ACTIVE:
2356401734dSWill Andrews 		return (gettext("POTENTIALLY_ACTIVE"));
2366401734dSWill Andrews 	}
2376401734dSWill Andrews 
2386401734dSWill Andrews 	return (gettext("UNKNOWN"));
2396401734dSWill Andrews }
2406401734dSWill Andrews 
241990b4856Slling /*
242990b4856Slling  * Get a zpool property value for 'prop' and return the value in
243990b4856Slling  * a pre-allocated buffer.
244990b4856Slling  */
245990b4856Slling int
246990b4856Slling zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, size_t len,
247c58b3526SAdam Stevko     zprop_source_t *srctype, boolean_t literal)
248990b4856Slling {
249990b4856Slling 	uint64_t intval;
250990b4856Slling 	const char *strval;
251990b4856Slling 	zprop_source_t src = ZPROP_SRC_NONE;
252990b4856Slling 	nvlist_t *nvroot;
253990b4856Slling 	vdev_stat_t *vs;
254990b4856Slling 	uint_t vsc;
255990b4856Slling 
256990b4856Slling 	if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
257379c004dSEric Schrock 		switch (prop) {
258379c004dSEric Schrock 		case ZPOOL_PROP_NAME:
259990b4856Slling 			(void) strlcpy(buf, zpool_get_name(zhp), len);
260379c004dSEric Schrock 			break;
261379c004dSEric Schrock 
262379c004dSEric Schrock 		case ZPOOL_PROP_HEALTH:
263990b4856Slling 			(void) strlcpy(buf, "FAULTED", len);
264379c004dSEric Schrock 			break;
265379c004dSEric Schrock 
266379c004dSEric Schrock 		case ZPOOL_PROP_GUID:
267379c004dSEric Schrock 			intval = zpool_get_prop_int(zhp, prop, &src);
268379c004dSEric Schrock 			(void) snprintf(buf, len, "%llu", intval);
269379c004dSEric Schrock 			break;
270379c004dSEric Schrock 
271379c004dSEric Schrock 		case ZPOOL_PROP_ALTROOT:
272379c004dSEric Schrock 		case ZPOOL_PROP_CACHEFILE:
2738704186eSDan McDonald 		case ZPOOL_PROP_COMMENT:
274379c004dSEric Schrock 			if (zhp->zpool_props != NULL ||
275379c004dSEric Schrock 			    zpool_get_all_props(zhp) == 0) {
276379c004dSEric Schrock 				(void) strlcpy(buf,
277379c004dSEric Schrock 				    zpool_get_prop_string(zhp, prop, &src),
278379c004dSEric Schrock 				    len);
279c58b3526SAdam Stevko 				break;
280379c004dSEric Schrock 			}
281379c004dSEric Schrock 			/* FALLTHROUGH */
282379c004dSEric Schrock 		default:
283990b4856Slling 			(void) strlcpy(buf, "-", len);
284379c004dSEric Schrock 			break;
285379c004dSEric Schrock 		}
286379c004dSEric Schrock 
287379c004dSEric Schrock 		if (srctype != NULL)
288379c004dSEric Schrock 			*srctype = src;
289990b4856Slling 		return (0);
290990b4856Slling 	}
291990b4856Slling 
292990b4856Slling 	if (zhp->zpool_props == NULL && zpool_get_all_props(zhp) &&
293990b4856Slling 	    prop != ZPOOL_PROP_NAME)
294990b4856Slling 		return (-1);
295990b4856Slling 
296990b4856Slling 	switch (zpool_prop_get_type(prop)) {
297990b4856Slling 	case PROP_TYPE_STRING:
298990b4856Slling 		(void) strlcpy(buf, zpool_get_prop_string(zhp, prop, &src),
299990b4856Slling 		    len);
300990b4856Slling 		break;
301990b4856Slling 
302990b4856Slling 	case PROP_TYPE_NUMBER:
303990b4856Slling 		intval = zpool_get_prop_int(zhp, prop, &src);
304990b4856Slling 
305990b4856Slling 		switch (prop) {
306990b4856Slling 		case ZPOOL_PROP_SIZE:
307485bbbf5SGeorge Wilson 		case ZPOOL_PROP_ALLOCATED:
308485bbbf5SGeorge Wilson 		case ZPOOL_PROP_FREE:
309ad135b5dSChristopher Siden 		case ZPOOL_PROP_FREEING:
3107fd05ac4SMatthew Ahrens 		case ZPOOL_PROP_LEAKED:
311c58b3526SAdam Stevko 			if (literal) {
312c58b3526SAdam Stevko 				(void) snprintf(buf, len, "%llu",
313c58b3526SAdam Stevko 				    (u_longlong_t)intval);
314c58b3526SAdam Stevko 			} else {
315c58b3526SAdam Stevko 				(void) zfs_nicenum(intval, buf, len);
316c58b3526SAdam Stevko 			}
317990b4856Slling 			break;
3187855d95bSToomas Soome 		case ZPOOL_PROP_BOOTSIZE:
3197a09f97bSGeorge Wilson 		case ZPOOL_PROP_EXPANDSZ:
32086714001SSerapheim Dimitropoulos 		case ZPOOL_PROP_CHECKPOINT:
3217a09f97bSGeorge Wilson 			if (intval == 0) {
3227a09f97bSGeorge Wilson 				(void) strlcpy(buf, "-", len);
3237a09f97bSGeorge Wilson 			} else if (literal) {
3247a09f97bSGeorge Wilson 				(void) snprintf(buf, len, "%llu",
3257a09f97bSGeorge Wilson 				    (u_longlong_t)intval);
3267a09f97bSGeorge Wilson 			} else {
3277a09f97bSGeorge Wilson 				(void) zfs_nicenum(intval, buf, len);
3287a09f97bSGeorge Wilson 			}
3297a09f97bSGeorge Wilson 			break;
330990b4856Slling 		case ZPOOL_PROP_CAPACITY:
331c58b3526SAdam Stevko 			if (literal) {
332c58b3526SAdam Stevko 				(void) snprintf(buf, len, "%llu",
333c58b3526SAdam Stevko 				    (u_longlong_t)intval);
334c58b3526SAdam Stevko 			} else {
335c58b3526SAdam Stevko 				(void) snprintf(buf, len, "%llu%%",
336c58b3526SAdam Stevko 				    (u_longlong_t)intval);
337c58b3526SAdam Stevko 			}
338990b4856Slling 			break;
3392e4c9986SGeorge Wilson 		case ZPOOL_PROP_FRAGMENTATION:
3402e4c9986SGeorge Wilson 			if (intval == UINT64_MAX) {
3412e4c9986SGeorge Wilson 				(void) strlcpy(buf, "-", len);
3422e4c9986SGeorge Wilson 			} else {
3432e4c9986SGeorge Wilson 				(void) snprintf(buf, len, "%llu%%",
3442e4c9986SGeorge Wilson 				    (u_longlong_t)intval);
3452e4c9986SGeorge Wilson 			}
3462e4c9986SGeorge Wilson 			break;
347b24ab676SJeff Bonwick 		case ZPOOL_PROP_DEDUPRATIO:
348b24ab676SJeff Bonwick 			(void) snprintf(buf, len, "%llu.%02llux",
349b24ab676SJeff Bonwick 			    (u_longlong_t)(intval / 100),
350b24ab676SJeff Bonwick 			    (u_longlong_t)(intval % 100));
351b24ab676SJeff Bonwick 			break;
352990b4856Slling 		case ZPOOL_PROP_HEALTH:
353990b4856Slling 			verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL),
354990b4856Slling 			    ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
355990b4856Slling 			verify(nvlist_lookup_uint64_array(nvroot,
3563f9d6ad7SLin Ling 			    ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&vs, &vsc)
3573f9d6ad7SLin Ling 			    == 0);
358990b4856Slling 
359990b4856Slling 			(void) strlcpy(buf, zpool_state_to_name(intval,
360990b4856Slling 			    vs->vs_aux), len);
361990b4856Slling 			break;
362ad135b5dSChristopher Siden 		case ZPOOL_PROP_VERSION:
363ad135b5dSChristopher Siden 			if (intval >= SPA_VERSION_FEATURES) {
364ad135b5dSChristopher Siden 				(void) snprintf(buf, len, "-");
365ad135b5dSChristopher Siden 				break;
366ad135b5dSChristopher Siden 			}
367ad135b5dSChristopher Siden 			/* FALLTHROUGH */
368990b4856Slling 		default:
369990b4856Slling 			(void) snprintf(buf, len, "%llu", intval);
370990b4856Slling 		}
371990b4856Slling 		break;
372990b4856Slling 
373990b4856Slling 	case PROP_TYPE_INDEX:
374990b4856Slling 		intval = zpool_get_prop_int(zhp, prop, &src);
375990b4856Slling 		if (zpool_prop_index_to_string(prop, intval, &strval)
376990b4856Slling 		    != 0)
377990b4856Slling 			return (-1);
378990b4856Slling 		(void) strlcpy(buf, strval, len);
379990b4856Slling 		break;
380990b4856Slling 
381990b4856Slling 	default:
382990b4856Slling 		abort();
383990b4856Slling 	}
384990b4856Slling 
385990b4856Slling 	if (srctype)
386990b4856Slling 		*srctype = src;
387990b4856Slling 
388990b4856Slling 	return (0);
389990b4856Slling }
390990b4856Slling 
391990b4856Slling /*
392990b4856Slling  * Check if the bootfs name has the same pool name as it is set to.
393990b4856Slling  * Assuming bootfs is a valid dataset name.
394990b4856Slling  */
395990b4856Slling static boolean_t
396990b4856Slling bootfs_name_valid(const char *pool, char *bootfs)
397990b4856Slling {
398990b4856Slling 	int len = strlen(pool);
399015f38bbSPaul Dagnelie 	if (bootfs[0] == '\0')
400015f38bbSPaul Dagnelie 		return (B_TRUE);
401990b4856Slling 
402fe3e2633SEric Taylor 	if (!zfs_name_valid(bootfs, ZFS_TYPE_FILESYSTEM|ZFS_TYPE_SNAPSHOT))
403990b4856Slling 		return (B_FALSE);
404990b4856Slling 
405990b4856Slling 	if (strncmp(pool, bootfs, len) == 0 &&
406990b4856Slling 	    (bootfs[len] == '/' || bootfs[len] == '\0'))
407990b4856Slling 		return (B_TRUE);
408990b4856Slling 
409990b4856Slling 	return (B_FALSE);
410990b4856Slling }
411990b4856Slling 
4124263d13fSGeorge Wilson boolean_t
4134263d13fSGeorge Wilson zpool_is_bootable(zpool_handle_t *zhp)
414b5b76fecSGeorge Wilson {
4159adfa60dSMatthew Ahrens 	char bootfs[ZFS_MAX_DATASET_NAME_LEN];
416b5b76fecSGeorge Wilson 
417b5b76fecSGeorge Wilson 	return (zpool_get_prop(zhp, ZPOOL_PROP_BOOTFS, bootfs,
418c58b3526SAdam Stevko 	    sizeof (bootfs), NULL, B_FALSE) == 0 && strncmp(bootfs, "-",
419b5b76fecSGeorge Wilson 	    sizeof (bootfs)) != 0);
420b5b76fecSGeorge Wilson }
421b5b76fecSGeorge Wilson 
422b5b76fecSGeorge Wilson 
423990b4856Slling /*
424990b4856Slling  * Given an nvlist of zpool properties to be set, validate that they are
425990b4856Slling  * correct, and parse any numeric properties (index, boolean, etc) if they are
426990b4856Slling  * specified as strings.
427990b4856Slling  */
428990b4856Slling static nvlist_t *
4290a48a24eStimh zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname,
430f9af39baSGeorge Wilson     nvlist_t *props, uint64_t version, prop_flags_t flags, char *errbuf)
431990b4856Slling {
432990b4856Slling 	nvpair_t *elem;
433990b4856Slling 	nvlist_t *retprops;
434990b4856Slling 	zpool_prop_t prop;
435990b4856Slling 	char *strval;
436990b4856Slling 	uint64_t intval;
4378704186eSDan McDonald 	char *slash, *check;
4382f8aaab3Seschrock 	struct stat64 statbuf;
43915e6edf1Sgw 	zpool_handle_t *zhp;
440990b4856Slling 
441990b4856Slling 	if (nvlist_alloc(&retprops, NV_UNIQUE_NAME, 0) != 0) {
442990b4856Slling 		(void) no_memory(hdl);
443990b4856Slling 		return (NULL);
444990b4856Slling 	}
445990b4856Slling 
446990b4856Slling 	elem = NULL;
447990b4856Slling 	while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
448990b4856Slling 		const char *propname = nvpair_name(elem);
449990b4856Slling 
450ad135b5dSChristopher Siden 		prop = zpool_name_to_prop(propname);
4514ae5f5f0SAlan Somers 		if (prop == ZPOOL_PROP_INVAL && zpool_prop_feature(propname)) {
452ad135b5dSChristopher Siden 			int err;
453ad135b5dSChristopher Siden 			char *fname = strchr(propname, '@') + 1;
454ad135b5dSChristopher Siden 
4552acef22dSMatthew Ahrens 			err = zfeature_lookup_name(fname, NULL);
456ad135b5dSChristopher Siden 			if (err != 0) {
457ad135b5dSChristopher Siden 				ASSERT3U(err, ==, ENOENT);
458ad135b5dSChristopher Siden 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
459ad135b5dSChristopher Siden 				    "invalid feature '%s'"), fname);
460ad135b5dSChristopher Siden 				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
461ad135b5dSChristopher Siden 				goto error;
462ad135b5dSChristopher Siden 			}
463ad135b5dSChristopher Siden 
464ad135b5dSChristopher Siden 			if (nvpair_type(elem) != DATA_TYPE_STRING) {
465ad135b5dSChristopher Siden 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
466ad135b5dSChristopher Siden 				    "'%s' must be a string"), propname);
467ad135b5dSChristopher Siden 				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
468ad135b5dSChristopher Siden 				goto error;
469ad135b5dSChristopher Siden 			}
470ad135b5dSChristopher Siden 
471ad135b5dSChristopher Siden 			(void) nvpair_value_string(elem, &strval);
472ad135b5dSChristopher Siden 			if (strcmp(strval, ZFS_FEATURE_ENABLED) != 0) {
473ad135b5dSChristopher Siden 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
474ad135b5dSChristopher Siden 				    "property '%s' can only be set to "
475ad135b5dSChristopher Siden 				    "'enabled'"), propname);
476ad135b5dSChristopher Siden 				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
477ad135b5dSChristopher Siden 				goto error;
478ad135b5dSChristopher Siden 			}
479ad135b5dSChristopher Siden 
480ad135b5dSChristopher Siden 			if (nvlist_add_uint64(retprops, propname, 0) != 0) {
481ad135b5dSChristopher Siden 				(void) no_memory(hdl);
482ad135b5dSChristopher Siden 				goto error;
483ad135b5dSChristopher Siden 			}
484ad135b5dSChristopher Siden 			continue;
485ad135b5dSChristopher Siden 		}
486ad135b5dSChristopher Siden 
487990b4856Slling 		/*
488990b4856Slling 		 * Make sure this property is valid and applies to this type.
489990b4856Slling 		 */
4904ae5f5f0SAlan Somers 		if (prop == ZPOOL_PROP_INVAL) {
491990b4856Slling 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
492990b4856Slling 			    "invalid property '%s'"), propname);
493990b4856Slling 			(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
494990b4856Slling 			goto error;
495990b4856Slling 		}
496990b4856Slling 
497990b4856Slling 		if (zpool_prop_readonly(prop)) {
498990b4856Slling 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' "
499990b4856Slling 			    "is readonly"), propname);
500990b4856Slling 			(void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf);
501990b4856Slling 			goto error;
502990b4856Slling 		}
503990b4856Slling 
504990b4856Slling 		if (zprop_parse_value(hdl, elem, prop, ZFS_TYPE_POOL, retprops,
505990b4856Slling 		    &strval, &intval, errbuf) != 0)
506990b4856Slling 			goto error;
507990b4856Slling 
508990b4856Slling 		/*
509990b4856Slling 		 * Perform additional checking for specific properties.
510990b4856Slling 		 */
511990b4856Slling 		switch (prop) {
512990b4856Slling 		case ZPOOL_PROP_VERSION:
513ad135b5dSChristopher Siden 			if (intval < version ||
514ad135b5dSChristopher Siden 			    !SPA_VERSION_IS_SUPPORTED(intval)) {
515990b4856Slling 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
516990b4856Slling 				    "property '%s' number %d is invalid."),
517990b4856Slling 				    propname, intval);
518990b4856Slling 				(void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
519990b4856Slling 				goto error;
520990b4856Slling 			}
521990b4856Slling 			break;
522990b4856Slling 
5237855d95bSToomas Soome 		case ZPOOL_PROP_BOOTSIZE:
5247855d95bSToomas Soome 			if (!flags.create) {
5257855d95bSToomas Soome 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
5267855d95bSToomas Soome 				    "property '%s' can only be set during pool "
5277855d95bSToomas Soome 				    "creation"), propname);
5287855d95bSToomas Soome 				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
5297855d95bSToomas Soome 				goto error;
5307855d95bSToomas Soome 			}
5317855d95bSToomas Soome 			break;
5327855d95bSToomas Soome 
533990b4856Slling 		case ZPOOL_PROP_BOOTFS:
534f9af39baSGeorge Wilson 			if (flags.create || flags.import) {
535990b4856Slling 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
536990b4856Slling 				    "property '%s' cannot be set at creation "
537990b4856Slling 				    "or import time"), propname);
538990b4856Slling 				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
539990b4856Slling 				goto error;
540990b4856Slling 			}
541990b4856Slling 
542990b4856Slling 			if (version < SPA_VERSION_BOOTFS) {
543990b4856Slling 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
544990b4856Slling 				    "pool must be upgraded to support "
545990b4856Slling 				    "'%s' property"), propname);
546990b4856Slling 				(void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
547990b4856Slling 				goto error;
548990b4856Slling 			}
549990b4856Slling 
550990b4856Slling 			/*
551990b4856Slling 			 * bootfs property value has to be a dataset name and
552990b4856Slling 			 * the dataset has to be in the same pool as it sets to.
553990b4856Slling 			 */
554015f38bbSPaul Dagnelie 			if (!bootfs_name_valid(poolname, strval)) {
555990b4856Slling 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' "
556990b4856Slling 				    "is an invalid name"), strval);
557990b4856Slling 				(void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf);
558990b4856Slling 				goto error;
559990b4856Slling 			}
56015e6edf1Sgw 
56115e6edf1Sgw 			if ((zhp = zpool_open_canfail(hdl, poolname)) == NULL) {
56215e6edf1Sgw 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
56315e6edf1Sgw 				    "could not open pool '%s'"), poolname);
56415e6edf1Sgw 				(void) zfs_error(hdl, EZFS_OPENFAILED, errbuf);
56515e6edf1Sgw 				goto error;
56615e6edf1Sgw 			}
56715e6edf1Sgw 			zpool_close(zhp);
568990b4856Slling 			break;
569990b4856Slling 
5702f8aaab3Seschrock 		case ZPOOL_PROP_ALTROOT:
571f9af39baSGeorge Wilson 			if (!flags.create && !flags.import) {
572990b4856Slling 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
573990b4856Slling 				    "property '%s' can only be set during pool "
574990b4856Slling 				    "creation or import"), propname);
575990b4856Slling 				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
576990b4856Slling 				goto error;
577990b4856Slling 			}
578990b4856Slling 
5792f8aaab3Seschrock 			if (strval[0] != '/') {
580990b4856Slling 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
5812f8aaab3Seschrock 				    "bad alternate root '%s'"), strval);
5822f8aaab3Seschrock 				(void) zfs_error(hdl, EZFS_BADPATH, errbuf);
583990b4856Slling 				goto error;
584990b4856Slling 			}
5852f8aaab3Seschrock 			break;
5862f8aaab3Seschrock 
5872f8aaab3Seschrock 		case ZPOOL_PROP_CACHEFILE:
5882f8aaab3Seschrock 			if (strval[0] == '\0')
5892f8aaab3Seschrock 				break;
5902f8aaab3Seschrock 
5912f8aaab3Seschrock 			if (strcmp(strval, "none") == 0)
5922f8aaab3Seschrock 				break;
593990b4856Slling 
594990b4856Slling 			if (strval[0] != '/') {
595990b4856Slling 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
5962f8aaab3Seschrock 				    "property '%s' must be empty, an "
5972f8aaab3Seschrock 				    "absolute path, or 'none'"), propname);
598990b4856Slling 				(void) zfs_error(hdl, EZFS_BADPATH, errbuf);
599990b4856Slling 				goto error;
600990b4856Slling 			}
601990b4856Slling 
6022f8aaab3Seschrock 			slash = strrchr(strval, '/');
603990b4856Slling 
6042f8aaab3Seschrock 			if (slash[1] == '\0' || strcmp(slash, "/.") == 0 ||
6052f8aaab3Seschrock 			    strcmp(slash, "/..") == 0) {
6062f8aaab3Seschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
6072f8aaab3Seschrock 				    "'%s' is not a valid file"), strval);
6082f8aaab3Seschrock 				(void) zfs_error(hdl, EZFS_BADPATH, errbuf);
6092f8aaab3Seschrock 				goto error;
6102f8aaab3Seschrock 			}
611990b4856Slling 
6122f8aaab3Seschrock 			*slash = '\0';
6132f8aaab3Seschrock 
6142c32020fSeschrock 			if (strval[0] != '\0' &&
6152c32020fSeschrock 			    (stat64(strval, &statbuf) != 0 ||
6162c32020fSeschrock 			    !S_ISDIR(statbuf.st_mode))) {
6172f8aaab3Seschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
6182f8aaab3Seschrock 				    "'%s' is not a valid directory"),
6192f8aaab3Seschrock 				    strval);
6202f8aaab3Seschrock 				(void) zfs_error(hdl, EZFS_BADPATH, errbuf);
6212f8aaab3Seschrock 				goto error;
6222f8aaab3Seschrock 			}
6232f8aaab3Seschrock 
6242f8aaab3Seschrock 			*slash = '/';
6252f8aaab3Seschrock 			break;
626f9af39baSGeorge Wilson 
6278704186eSDan McDonald 		case ZPOOL_PROP_COMMENT:
6288704186eSDan McDonald 			for (check = strval; *check != '\0'; check++) {
6298704186eSDan McDonald 				if (!isprint(*check)) {
6308704186eSDan McDonald 					zfs_error_aux(hdl,
6318704186eSDan McDonald 					    dgettext(TEXT_DOMAIN,
6328704186eSDan McDonald 					    "comment may only have printable "
6338704186eSDan McDonald 					    "characters"));
6348704186eSDan McDonald 					(void) zfs_error(hdl, EZFS_BADPROP,
6358704186eSDan McDonald 					    errbuf);
6368704186eSDan McDonald 					goto error;
6378704186eSDan McDonald 				}
6388704186eSDan McDonald 			}
6398704186eSDan McDonald 			if (strlen(strval) > ZPROP_MAX_COMMENT) {
6408704186eSDan McDonald 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
6418704186eSDan McDonald 				    "comment must not exceed %d characters"),
6428704186eSDan McDonald 				    ZPROP_MAX_COMMENT);
6438704186eSDan McDonald 				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
6448704186eSDan McDonald 				goto error;
6458704186eSDan McDonald 			}
6468704186eSDan McDonald 			break;
647*04e56356SAndriy Gapon 
648f9af39baSGeorge Wilson 		case ZPOOL_PROP_READONLY:
649f9af39baSGeorge Wilson 			if (!flags.import) {
650f9af39baSGeorge Wilson 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
651f9af39baSGeorge Wilson 				    "property '%s' can only be set at "
652f9af39baSGeorge Wilson 				    "import time"), propname);
653f9af39baSGeorge Wilson 				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
654f9af39baSGeorge Wilson 				goto error;
655f9af39baSGeorge Wilson 			}
656f9af39baSGeorge Wilson 			break;
65788f61deeSIgor Kozhukhov 
658*04e56356SAndriy Gapon 		case ZPOOL_PROP_TNAME:
659*04e56356SAndriy Gapon 			if (!flags.create) {
660*04e56356SAndriy Gapon 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
661*04e56356SAndriy Gapon 				    "property '%s' can only be set at "
662*04e56356SAndriy Gapon 				    "creation time"), propname);
663*04e56356SAndriy Gapon 				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
664*04e56356SAndriy Gapon 				goto error;
665*04e56356SAndriy Gapon 			}
666*04e56356SAndriy Gapon 			break;
667*04e56356SAndriy Gapon 
66888f61deeSIgor Kozhukhov 		default:
66988f61deeSIgor Kozhukhov 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
67088f61deeSIgor Kozhukhov 			    "property '%s'(%d) not defined"), propname, prop);
67188f61deeSIgor Kozhukhov 			break;
672990b4856Slling 		}
673990b4856Slling 	}
674990b4856Slling 
675990b4856Slling 	return (retprops);
676990b4856Slling error:
677990b4856Slling 	nvlist_free(retprops);
678990b4856Slling 	return (NULL);
679990b4856Slling }
680990b4856Slling 
681990b4856Slling /*
682990b4856Slling  * Set zpool property : propname=propval.
683990b4856Slling  */
684990b4856Slling int
685990b4856Slling zpool_set_prop(zpool_handle_t *zhp, const char *propname, const char *propval)
686990b4856Slling {
687990b4856Slling 	zfs_cmd_t zc = { 0 };
688990b4856Slling 	int ret = -1;
689990b4856Slling 	char errbuf[1024];
690990b4856Slling 	nvlist_t *nvl = NULL;
691990b4856Slling 	nvlist_t *realprops;
692990b4856Slling 	uint64_t version;
693f9af39baSGeorge Wilson 	prop_flags_t flags = { 0 };
694990b4856Slling 
695990b4856Slling 	(void) snprintf(errbuf, sizeof (errbuf),
696990b4856Slling 	    dgettext(TEXT_DOMAIN, "cannot set property for '%s'"),
697990b4856Slling 	    zhp->zpool_name);
698990b4856Slling 
699990b4856Slling 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
700990b4856Slling 		return (no_memory(zhp->zpool_hdl));
701990b4856Slling 
702990b4856Slling 	if (nvlist_add_string(nvl, propname, propval) != 0) {
703990b4856Slling 		nvlist_free(nvl);
704990b4856Slling 		return (no_memory(zhp->zpool_hdl));
705990b4856Slling 	}
706990b4856Slling 
707990b4856Slling 	version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
7080a48a24eStimh 	if ((realprops = zpool_valid_proplist(zhp->zpool_hdl,
709f9af39baSGeorge Wilson 	    zhp->zpool_name, nvl, version, flags, errbuf)) == NULL) {
710990b4856Slling 		nvlist_free(nvl);
711990b4856Slling 		return (-1);
712990b4856Slling 	}
713990b4856Slling 
714990b4856Slling 	nvlist_free(nvl);
715990b4856Slling 	nvl = realprops;
716990b4856Slling 
717990b4856Slling 	/*
718990b4856Slling 	 * Execute the corresponding ioctl() to set this property.
719990b4856Slling 	 */
720990b4856Slling 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
721990b4856Slling 
722990b4856Slling 	if (zcmd_write_src_nvlist(zhp->zpool_hdl, &zc, nvl) != 0) {
723990b4856Slling 		nvlist_free(nvl);
724990b4856Slling 		return (-1);
725990b4856Slling 	}
726990b4856Slling 
727990b4856Slling 	ret = zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_SET_PROPS, &zc);
728990b4856Slling 
729990b4856Slling 	zcmd_free_nvlists(&zc);
730990b4856Slling 	nvlist_free(nvl);
731990b4856Slling 
732990b4856Slling 	if (ret)
733990b4856Slling 		(void) zpool_standard_error(zhp->zpool_hdl, errno, errbuf);
734990b4856Slling 	else
735990b4856Slling 		(void) zpool_props_refresh(zhp);
736990b4856Slling 
737990b4856Slling 	return (ret);
738990b4856Slling }
739990b4856Slling 
740990b4856Slling int
741990b4856Slling zpool_expand_proplist(zpool_handle_t *zhp, zprop_list_t **plp)
742990b4856Slling {
743990b4856Slling 	libzfs_handle_t *hdl = zhp->zpool_hdl;
744990b4856Slling 	zprop_list_t *entry;
745990b4856Slling 	char buf[ZFS_MAXPROPLEN];
746ad135b5dSChristopher Siden 	nvlist_t *features = NULL;
747ad135b5dSChristopher Siden 	zprop_list_t **last;
748ad135b5dSChristopher Siden 	boolean_t firstexpand = (NULL == *plp);
749990b4856Slling 
750990b4856Slling 	if (zprop_expand_list(hdl, plp, ZFS_TYPE_POOL) != 0)
751990b4856Slling 		return (-1);
752990b4856Slling 
753ad135b5dSChristopher Siden 	last = plp;
754ad135b5dSChristopher Siden 	while (*last != NULL)
755ad135b5dSChristopher Siden 		last = &(*last)->pl_next;
756ad135b5dSChristopher Siden 
757ad135b5dSChristopher Siden 	if ((*plp)->pl_all)
758ad135b5dSChristopher Siden 		features = zpool_get_features(zhp);
759ad135b5dSChristopher Siden 
760ad135b5dSChristopher Siden 	if ((*plp)->pl_all && firstexpand) {
761ad135b5dSChristopher Siden 		for (int i = 0; i < SPA_FEATURES; i++) {
762ad135b5dSChristopher Siden 			zprop_list_t *entry = zfs_alloc(hdl,
763ad135b5dSChristopher Siden 			    sizeof (zprop_list_t));
764ad135b5dSChristopher Siden 			entry->pl_prop = ZPROP_INVAL;
765ad135b5dSChristopher Siden 			entry->pl_user_prop = zfs_asprintf(hdl, "feature@%s",
766ad135b5dSChristopher Siden 			    spa_feature_table[i].fi_uname);
767ad135b5dSChristopher Siden 			entry->pl_width = strlen(entry->pl_user_prop);
768ad135b5dSChristopher Siden 			entry->pl_all = B_TRUE;
769ad135b5dSChristopher Siden 
770ad135b5dSChristopher Siden 			*last = entry;
771ad135b5dSChristopher Siden 			last = &entry->pl_next;
772ad135b5dSChristopher Siden 		}
773ad135b5dSChristopher Siden 	}
774ad135b5dSChristopher Siden 
775ad135b5dSChristopher Siden 	/* add any unsupported features */
776ad135b5dSChristopher Siden 	for (nvpair_t *nvp = nvlist_next_nvpair(features, NULL);
777ad135b5dSChristopher Siden 	    nvp != NULL; nvp = nvlist_next_nvpair(features, nvp)) {
778ad135b5dSChristopher Siden 		char *propname;
779ad135b5dSChristopher Siden 		boolean_t found;
780ad135b5dSChristopher Siden 		zprop_list_t *entry;
781ad135b5dSChristopher Siden 
782ad135b5dSChristopher Siden 		if (zfeature_is_supported(nvpair_name(nvp)))
783ad135b5dSChristopher Siden 			continue;
784ad135b5dSChristopher Siden 
785ad135b5dSChristopher Siden 		propname = zfs_asprintf(hdl, "unsupported@%s",
786ad135b5dSChristopher Siden 		    nvpair_name(nvp));
787ad135b5dSChristopher Siden 
788ad135b5dSChristopher Siden 		/*
789ad135b5dSChristopher Siden 		 * Before adding the property to the list make sure that no
790ad135b5dSChristopher Siden 		 * other pool already added the same property.
791ad135b5dSChristopher Siden 		 */
792ad135b5dSChristopher Siden 		found = B_FALSE;
793ad135b5dSChristopher Siden 		entry = *plp;
794ad135b5dSChristopher Siden 		while (entry != NULL) {
795ad135b5dSChristopher Siden 			if (entry->pl_user_prop != NULL &&
796ad135b5dSChristopher Siden 			    strcmp(propname, entry->pl_user_prop) == 0) {
797ad135b5dSChristopher Siden 				found = B_TRUE;
798ad135b5dSChristopher Siden 				break;
799ad135b5dSChristopher Siden 			}
800ad135b5dSChristopher Siden 			entry = entry->pl_next;
801ad135b5dSChristopher Siden 		}
802ad135b5dSChristopher Siden 		if (found) {
803ad135b5dSChristopher Siden 			free(propname);
804ad135b5dSChristopher Siden 			continue;
805ad135b5dSChristopher Siden 		}
806ad135b5dSChristopher Siden 
807ad135b5dSChristopher Siden 		entry = zfs_alloc(hdl, sizeof (zprop_list_t));
808ad135b5dSChristopher Siden 		entry->pl_prop = ZPROP_INVAL;
809ad135b5dSChristopher Siden 		entry->pl_user_prop = propname;
810ad135b5dSChristopher Siden 		entry->pl_width = strlen(entry->pl_user_prop);
811ad135b5dSChristopher Siden 		entry->pl_all = B_TRUE;
812ad135b5dSChristopher Siden 
813ad135b5dSChristopher Siden 		*last = entry;
814ad135b5dSChristopher Siden 		last = &entry->pl_next;
815ad135b5dSChristopher Siden 	}
816ad135b5dSChristopher Siden 
817990b4856Slling 	for (entry = *plp; entry != NULL; entry = entry->pl_next) {
818990b4856Slling 
819990b4856Slling 		if (entry->pl_fixed)
820990b4856Slling 			continue;
821990b4856Slling 
822990b4856Slling 		if (entry->pl_prop != ZPROP_INVAL &&
823990b4856Slling 		    zpool_get_prop(zhp, entry->pl_prop, buf, sizeof (buf),
824c58b3526SAdam Stevko 		    NULL, B_FALSE) == 0) {
825990b4856Slling 			if (strlen(buf) > entry->pl_width)
826990b4856Slling 				entry->pl_width = strlen(buf);
827990b4856Slling 		}
828990b4856Slling 	}
829990b4856Slling 
830990b4856Slling 	return (0);
831990b4856Slling }
832990b4856Slling 
833ad135b5dSChristopher Siden /*
834ad135b5dSChristopher Siden  * Get the state for the given feature on the given ZFS pool.
835ad135b5dSChristopher Siden  */
836ad135b5dSChristopher Siden int
837ad135b5dSChristopher Siden zpool_prop_get_feature(zpool_handle_t *zhp, const char *propname, char *buf,
838ad135b5dSChristopher Siden     size_t len)
839ad135b5dSChristopher Siden {
840ad135b5dSChristopher Siden 	uint64_t refcount;
841ad135b5dSChristopher Siden 	boolean_t found = B_FALSE;
842ad135b5dSChristopher Siden 	nvlist_t *features = zpool_get_features(zhp);
843ad135b5dSChristopher Siden 	boolean_t supported;
844ad135b5dSChristopher Siden 	const char *feature = strchr(propname, '@') + 1;
845ad135b5dSChristopher Siden 
846ad135b5dSChristopher Siden 	supported = zpool_prop_feature(propname);
8477c13517fSSerapheim Dimitropoulos 	ASSERT(supported || zpool_prop_unsupported(propname));
848ad135b5dSChristopher Siden 
849ad135b5dSChristopher Siden 	/*
850ad135b5dSChristopher Siden 	 * Convert from feature name to feature guid. This conversion is
851ad135b5dSChristopher Siden 	 * unecessary for unsupported@... properties because they already
852ad135b5dSChristopher Siden 	 * use guids.
853ad135b5dSChristopher Siden 	 */
854ad135b5dSChristopher Siden 	if (supported) {
855ad135b5dSChristopher Siden 		int ret;
8562acef22dSMatthew Ahrens 		spa_feature_t fid;
857ad135b5dSChristopher Siden 
8582acef22dSMatthew Ahrens 		ret = zfeature_lookup_name(feature, &fid);
859ad135b5dSChristopher Siden 		if (ret != 0) {
860ad135b5dSChristopher Siden 			(void) strlcpy(buf, "-", len);
861ad135b5dSChristopher Siden 			return (ENOTSUP);
862ad135b5dSChristopher Siden 		}
8632acef22dSMatthew Ahrens 		feature = spa_feature_table[fid].fi_guid;
864ad135b5dSChristopher Siden 	}
865ad135b5dSChristopher Siden 
866ad135b5dSChristopher Siden 	if (nvlist_lookup_uint64(features, feature, &refcount) == 0)
867ad135b5dSChristopher Siden 		found = B_TRUE;
868ad135b5dSChristopher Siden 
869ad135b5dSChristopher Siden 	if (supported) {
870ad135b5dSChristopher Siden 		if (!found) {
871ad135b5dSChristopher Siden 			(void) strlcpy(buf, ZFS_FEATURE_DISABLED, len);
872ad135b5dSChristopher Siden 		} else  {
873ad135b5dSChristopher Siden 			if (refcount == 0)
874ad135b5dSChristopher Siden 				(void) strlcpy(buf, ZFS_FEATURE_ENABLED, len);
875ad135b5dSChristopher Siden 			else
876ad135b5dSChristopher Siden 				(void) strlcpy(buf, ZFS_FEATURE_ACTIVE, len);
877ad135b5dSChristopher Siden 		}
878ad135b5dSChristopher Siden 	} else {
879ad135b5dSChristopher Siden 		if (found) {
880ad135b5dSChristopher Siden 			if (refcount == 0) {
881ad135b5dSChristopher Siden 				(void) strcpy(buf, ZFS_UNSUPPORTED_INACTIVE);
882ad135b5dSChristopher Siden 			} else {
883ad135b5dSChristopher Siden 				(void) strcpy(buf, ZFS_UNSUPPORTED_READONLY);
884ad135b5dSChristopher Siden 			}
885ad135b5dSChristopher Siden 		} else {
886ad135b5dSChristopher Siden 			(void) strlcpy(buf, "-", len);
887ad135b5dSChristopher Siden 			return (ENOTSUP);
888ad135b5dSChristopher Siden 		}
889ad135b5dSChristopher Siden 	}
890ad135b5dSChristopher Siden 
891ad135b5dSChristopher Siden 	return (0);
892ad135b5dSChristopher Siden }
893990b4856Slling 
894573ca77eSGeorge Wilson /*
895573ca77eSGeorge Wilson  * Don't start the slice at the default block of 34; many storage
896573ca77eSGeorge Wilson  * devices will use a stripe width of 128k, so start there instead.
897573ca77eSGeorge Wilson  */
898573ca77eSGeorge Wilson #define	NEW_START_BLOCK	256
899573ca77eSGeorge Wilson 
900fa9e4066Sahrens /*
901fa9e4066Sahrens  * Validate the given pool name, optionally putting an extended error message in
902fa9e4066Sahrens  * 'buf'.
903fa9e4066Sahrens  */
904e7cbe64fSgw boolean_t
90599653d4eSeschrock zpool_name_valid(libzfs_handle_t *hdl, boolean_t isopen, const char *pool)
906fa9e4066Sahrens {
907fa9e4066Sahrens 	namecheck_err_t why;
908fa9e4066Sahrens 	char what;
909b468a217Seschrock 	int ret;
910b468a217Seschrock 
911b468a217Seschrock 	ret = pool_namecheck(pool, &why, &what);
912b468a217Seschrock 
913b468a217Seschrock 	/*
914b468a217Seschrock 	 * The rules for reserved pool names were extended at a later point.
915b468a217Seschrock 	 * But we need to support users with existing pools that may now be
916b468a217Seschrock 	 * invalid.  So we only check for this expanded set of names during a
917b468a217Seschrock 	 * create (or import), and only in userland.
918b468a217Seschrock 	 */
919b468a217Seschrock 	if (ret == 0 && !isopen &&
920b468a217Seschrock 	    (strncmp(pool, "mirror", 6) == 0 ||
921b468a217Seschrock 	    strncmp(pool, "raidz", 5) == 0 ||
9228654d025Sperrin 	    strncmp(pool, "spare", 5) == 0 ||
9238654d025Sperrin 	    strcmp(pool, "log") == 0)) {
924e7cbe64fSgw 		if (hdl != NULL)
925e7cbe64fSgw 			zfs_error_aux(hdl,
926e7cbe64fSgw 			    dgettext(TEXT_DOMAIN, "name is reserved"));
92799653d4eSeschrock 		return (B_FALSE);
928b468a217Seschrock 	}
929b468a217Seschrock 
930fa9e4066Sahrens 
931b468a217Seschrock 	if (ret != 0) {
93299653d4eSeschrock 		if (hdl != NULL) {
933fa9e4066Sahrens 			switch (why) {
934b81d61a6Slling 			case NAME_ERR_TOOLONG:
93599653d4eSeschrock 				zfs_error_aux(hdl,
936b81d61a6Slling 				    dgettext(TEXT_DOMAIN, "name is too long"));
937b81d61a6Slling 				break;
938b81d61a6Slling 
939fa9e4066Sahrens 			case NAME_ERR_INVALCHAR:
94099653d4eSeschrock 				zfs_error_aux(hdl,
941fa9e4066Sahrens 				    dgettext(TEXT_DOMAIN, "invalid character "
942fa9e4066Sahrens 				    "'%c' in pool name"), what);
943fa9e4066Sahrens 				break;
944fa9e4066Sahrens 
945fa9e4066Sahrens 			case NAME_ERR_NOLETTER:
94699653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
94799653d4eSeschrock 				    "name must begin with a letter"));
948fa9e4066Sahrens 				break;
949fa9e4066Sahrens 
950fa9e4066Sahrens 			case NAME_ERR_RESERVED:
95199653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
95299653d4eSeschrock 				    "name is reserved"));
953fa9e4066Sahrens 				break;
954fa9e4066Sahrens 
955fa9e4066Sahrens 			case NAME_ERR_DISKLIKE:
95699653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
95799653d4eSeschrock 				    "pool name is reserved"));
958fa9e4066Sahrens 				break;
9595ad82045Snd 
9605ad82045Snd 			case NAME_ERR_LEADING_SLASH:
9615ad82045Snd 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
9625ad82045Snd 				    "leading slash in name"));
9635ad82045Snd 				break;
9645ad82045Snd 
9655ad82045Snd 			case NAME_ERR_EMPTY_COMPONENT:
9665ad82045Snd 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
9675ad82045Snd 				    "empty component in name"));
9685ad82045Snd 				break;
9695ad82045Snd 
9705ad82045Snd 			case NAME_ERR_TRAILING_SLASH:
9715ad82045Snd 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
9725ad82045Snd 				    "trailing slash in name"));
9735ad82045Snd 				break;
9745ad82045Snd 
975edb901aaSMarcel Telka 			case NAME_ERR_MULTIPLE_DELIMITERS:
9765ad82045Snd 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
977edb901aaSMarcel Telka 				    "multiple '@' and/or '#' delimiters in "
978edb901aaSMarcel Telka 				    "name"));
9795ad82045Snd 				break;
9805ad82045Snd 
98188f61deeSIgor Kozhukhov 			default:
98288f61deeSIgor Kozhukhov 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
98388f61deeSIgor Kozhukhov 				    "(%d) not defined"), why);
98488f61deeSIgor Kozhukhov 				break;
985fa9e4066Sahrens 			}
986fa9e4066Sahrens 		}
98799653d4eSeschrock 		return (B_FALSE);
988fa9e4066Sahrens 	}
989fa9e4066Sahrens 
99099653d4eSeschrock 	return (B_TRUE);
991fa9e4066Sahrens }
992fa9e4066Sahrens 
993fa9e4066Sahrens /*
994fa9e4066Sahrens  * Open a handle to the given pool, even if the pool is currently in the FAULTED
995fa9e4066Sahrens  * state.
996fa9e4066Sahrens  */
997fa9e4066Sahrens zpool_handle_t *
99899653d4eSeschrock zpool_open_canfail(libzfs_handle_t *hdl, const char *pool)
999fa9e4066Sahrens {
1000fa9e4066Sahrens 	zpool_handle_t *zhp;
100194de1d4cSeschrock 	boolean_t missing;
1002fa9e4066Sahrens 
1003fa9e4066Sahrens 	/*
1004fa9e4066Sahrens 	 * Make sure the pool name is valid.
1005fa9e4066Sahrens 	 */
100699653d4eSeschrock 	if (!zpool_name_valid(hdl, B_TRUE, pool)) {
1007ece3d9b3Slling 		(void) zfs_error_fmt(hdl, EZFS_INVALIDNAME,
100899653d4eSeschrock 		    dgettext(TEXT_DOMAIN, "cannot open '%s'"),
100999653d4eSeschrock 		    pool);
1010fa9e4066Sahrens 		return (NULL);
1011fa9e4066Sahrens 	}
1012fa9e4066Sahrens 
101399653d4eSeschrock 	if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL)
101499653d4eSeschrock 		return (NULL);
1015fa9e4066Sahrens 
101699653d4eSeschrock 	zhp->zpool_hdl = hdl;
1017fa9e4066Sahrens 	(void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name));
1018fa9e4066Sahrens 
101994de1d4cSeschrock 	if (zpool_refresh_stats(zhp, &missing) != 0) {
102094de1d4cSeschrock 		zpool_close(zhp);
102194de1d4cSeschrock 		return (NULL);
102294de1d4cSeschrock 	}
102394de1d4cSeschrock 
102494de1d4cSeschrock 	if (missing) {
1025990b4856Slling 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "no such pool"));
1026ece3d9b3Slling 		(void) zfs_error_fmt(hdl, EZFS_NOENT,
1027990b4856Slling 		    dgettext(TEXT_DOMAIN, "cannot open '%s'"), pool);
102894de1d4cSeschrock 		zpool_close(zhp);
102994de1d4cSeschrock 		return (NULL);
1030fa9e4066Sahrens 	}
1031fa9e4066Sahrens 
1032fa9e4066Sahrens 	return (zhp);
1033fa9e4066Sahrens }
1034fa9e4066Sahrens 
1035fa9e4066Sahrens /*
1036fa9e4066Sahrens  * Like the above, but silent on error.  Used when iterating over pools (because
1037fa9e4066Sahrens  * the configuration cache may be out of date).
1038fa9e4066Sahrens  */
103994de1d4cSeschrock int
104094de1d4cSeschrock zpool_open_silent(libzfs_handle_t *hdl, const char *pool, zpool_handle_t **ret)
1041fa9e4066Sahrens {
1042fa9e4066Sahrens 	zpool_handle_t *zhp;
104394de1d4cSeschrock 	boolean_t missing;
1044fa9e4066Sahrens 
104594de1d4cSeschrock 	if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL)
104694de1d4cSeschrock 		return (-1);
1047fa9e4066Sahrens 
104899653d4eSeschrock 	zhp->zpool_hdl = hdl;
1049fa9e4066Sahrens 	(void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name));
1050fa9e4066Sahrens 
105194de1d4cSeschrock 	if (zpool_refresh_stats(zhp, &missing) != 0) {
105294de1d4cSeschrock 		zpool_close(zhp);
105394de1d4cSeschrock 		return (-1);
1054fa9e4066Sahrens 	}
1055fa9e4066Sahrens 
105694de1d4cSeschrock 	if (missing) {
105794de1d4cSeschrock 		zpool_close(zhp);
105894de1d4cSeschrock 		*ret = NULL;
105994de1d4cSeschrock 		return (0);
106094de1d4cSeschrock 	}
106194de1d4cSeschrock 
106294de1d4cSeschrock 	*ret = zhp;
106394de1d4cSeschrock 	return (0);
1064fa9e4066Sahrens }
1065fa9e4066Sahrens 
1066fa9e4066Sahrens /*
1067fa9e4066Sahrens  * Similar to zpool_open_canfail(), but refuses to open pools in the faulted
1068fa9e4066Sahrens  * state.
1069fa9e4066Sahrens  */
1070fa9e4066Sahrens zpool_handle_t *
107199653d4eSeschrock zpool_open(libzfs_handle_t *hdl, const char *pool)
1072fa9e4066Sahrens {
1073fa9e4066Sahrens 	zpool_handle_t *zhp;
1074fa9e4066Sahrens 
107599653d4eSeschrock 	if ((zhp = zpool_open_canfail(hdl, pool)) == NULL)
1076fa9e4066Sahrens 		return (NULL);
1077fa9e4066Sahrens 
1078fa9e4066Sahrens 	if (zhp->zpool_state == POOL_STATE_UNAVAIL) {
1079ece3d9b3Slling 		(void) zfs_error_fmt(hdl, EZFS_POOLUNAVAIL,
108099653d4eSeschrock 		    dgettext(TEXT_DOMAIN, "cannot open '%s'"), zhp->zpool_name);
1081fa9e4066Sahrens 		zpool_close(zhp);
1082fa9e4066Sahrens 		return (NULL);
1083fa9e4066Sahrens 	}
1084fa9e4066Sahrens 
1085fa9e4066Sahrens 	return (zhp);
1086fa9e4066Sahrens }
1087fa9e4066Sahrens 
1088fa9e4066Sahrens /*
1089fa9e4066Sahrens  * Close the handle.  Simply frees the memory associated with the handle.
1090fa9e4066Sahrens  */
1091fa9e4066Sahrens void
1092fa9e4066Sahrens zpool_close(zpool_handle_t *zhp)
1093fa9e4066Sahrens {
1094aab83bb8SJosef 'Jeff' Sipek 	nvlist_free(zhp->zpool_config);
1095aab83bb8SJosef 'Jeff' Sipek 	nvlist_free(zhp->zpool_old_config);
1096aab83bb8SJosef 'Jeff' Sipek 	nvlist_free(zhp->zpool_props);
1097fa9e4066Sahrens 	free(zhp);
1098fa9e4066Sahrens }
1099fa9e4066Sahrens 
1100fa9e4066Sahrens /*
1101fa9e4066Sahrens  * Return the name of the pool.
1102fa9e4066Sahrens  */
1103fa9e4066Sahrens const char *
1104fa9e4066Sahrens zpool_get_name(zpool_handle_t *zhp)
1105fa9e4066Sahrens {
1106fa9e4066Sahrens 	return (zhp->zpool_name);
1107fa9e4066Sahrens }
1108fa9e4066Sahrens 
1109fa9e4066Sahrens 
1110fa9e4066Sahrens /*
1111fa9e4066Sahrens  * Return the state of the pool (ACTIVE or UNAVAILABLE)
1112fa9e4066Sahrens  */
1113fa9e4066Sahrens int
1114fa9e4066Sahrens zpool_get_state(zpool_handle_t *zhp)
1115fa9e4066Sahrens {
1116fa9e4066Sahrens 	return (zhp->zpool_state);
1117fa9e4066Sahrens }
1118fa9e4066Sahrens 
1119fa9e4066Sahrens /*
1120fa9e4066Sahrens  * Create the named pool, using the provided vdev list.  It is assumed
1121fa9e4066Sahrens  * that the consumer has already validated the contents of the nvlist, so we
1122fa9e4066Sahrens  * don't have to worry about error semantics.
1123fa9e4066Sahrens  */
1124fa9e4066Sahrens int
112599653d4eSeschrock zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot,
11260a48a24eStimh     nvlist_t *props, nvlist_t *fsprops)
1127fa9e4066Sahrens {
1128fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
11290a48a24eStimh 	nvlist_t *zc_fsprops = NULL;
11300a48a24eStimh 	nvlist_t *zc_props = NULL;
113199653d4eSeschrock 	char msg[1024];
11320a48a24eStimh 	int ret = -1;
1133fa9e4066Sahrens 
113499653d4eSeschrock 	(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
113599653d4eSeschrock 	    "cannot create '%s'"), pool);
1136fa9e4066Sahrens 
113799653d4eSeschrock 	if (!zpool_name_valid(hdl, B_FALSE, pool))
113899653d4eSeschrock 		return (zfs_error(hdl, EZFS_INVALIDNAME, msg));
1139fa9e4066Sahrens 
1140351420b3Slling 	if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0)
1141990b4856Slling 		return (-1);
1142fa9e4066Sahrens 
11430a48a24eStimh 	if (props) {
1144f9af39baSGeorge Wilson 		prop_flags_t flags = { .create = B_TRUE, .import = B_FALSE };
1145f9af39baSGeorge Wilson 
11460a48a24eStimh 		if ((zc_props = zpool_valid_proplist(hdl, pool, props,
1147f9af39baSGeorge Wilson 		    SPA_VERSION_1, flags, msg)) == NULL) {
11480a48a24eStimh 			goto create_failed;
11490a48a24eStimh 		}
11500a48a24eStimh 	}
115199653d4eSeschrock 
11520a48a24eStimh 	if (fsprops) {
11530a48a24eStimh 		uint64_t zoned;
11540a48a24eStimh 		char *zonestr;
11550a48a24eStimh 
11560a48a24eStimh 		zoned = ((nvlist_lookup_string(fsprops,
11570a48a24eStimh 		    zfs_prop_to_name(ZFS_PROP_ZONED), &zonestr) == 0) &&
11580a48a24eStimh 		    strcmp(zonestr, "on") == 0);
11590a48a24eStimh 
1160e9316f76SJoe Stein 		if ((zc_fsprops = zfs_valid_proplist(hdl, ZFS_TYPE_FILESYSTEM,
1161e9316f76SJoe Stein 		    fsprops, zoned, NULL, NULL, msg)) == NULL) {
11620a48a24eStimh 			goto create_failed;
11630a48a24eStimh 		}
11640a48a24eStimh 		if (!zc_props &&
11650a48a24eStimh 		    (nvlist_alloc(&zc_props, NV_UNIQUE_NAME, 0) != 0)) {
11660a48a24eStimh 			goto create_failed;
11670a48a24eStimh 		}
11680a48a24eStimh 		if (nvlist_add_nvlist(zc_props,
11690a48a24eStimh 		    ZPOOL_ROOTFS_PROPS, zc_fsprops) != 0) {
11700a48a24eStimh 			goto create_failed;
11710a48a24eStimh 		}
1172351420b3Slling 	}
1173fa9e4066Sahrens 
11740a48a24eStimh 	if (zc_props && zcmd_write_src_nvlist(hdl, &zc, zc_props) != 0)
11750a48a24eStimh 		goto create_failed;
11760a48a24eStimh 
1177990b4856Slling 	(void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name));
1178fa9e4066Sahrens 
11790a48a24eStimh 	if ((ret = zfs_ioctl(hdl, ZFS_IOC_POOL_CREATE, &zc)) != 0) {
1180351420b3Slling 
1181e9dbad6fSeschrock 		zcmd_free_nvlists(&zc);
11820a48a24eStimh 		nvlist_free(zc_props);
11830a48a24eStimh 		nvlist_free(zc_fsprops);
1184fa9e4066Sahrens 
118599653d4eSeschrock 		switch (errno) {
1186fa9e4066Sahrens 		case EBUSY:
1187fa9e4066Sahrens 			/*
1188fa9e4066Sahrens 			 * This can happen if the user has specified the same
1189fa9e4066Sahrens 			 * device multiple times.  We can't reliably detect this
1190fa9e4066Sahrens 			 * until we try to add it and see we already have a
1191fa9e4066Sahrens 			 * label.
1192fa9e4066Sahrens 			 */
119399653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
119499653d4eSeschrock 			    "one or more vdevs refer to the same device"));
119599653d4eSeschrock 			return (zfs_error(hdl, EZFS_BADDEV, msg));
1196fa9e4066Sahrens 
1197e9316f76SJoe Stein 		case ERANGE:
1198e9316f76SJoe Stein 			/*
1199e9316f76SJoe Stein 			 * This happens if the record size is smaller or larger
1200e9316f76SJoe Stein 			 * than the allowed size range, or not a power of 2.
1201e9316f76SJoe Stein 			 *
1202e9316f76SJoe Stein 			 * NOTE: although zfs_valid_proplist is called earlier,
1203e9316f76SJoe Stein 			 * this case may have slipped through since the
1204e9316f76SJoe Stein 			 * pool does not exist yet and it is therefore
1205e9316f76SJoe Stein 			 * impossible to read properties e.g. max blocksize
1206e9316f76SJoe Stein 			 * from the pool.
1207e9316f76SJoe Stein 			 */
1208e9316f76SJoe Stein 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1209e9316f76SJoe Stein 			    "record size invalid"));
1210e9316f76SJoe Stein 			return (zfs_error(hdl, EZFS_BADPROP, msg));
1211e9316f76SJoe Stein 
1212fa9e4066Sahrens 		case EOVERFLOW:
1213fa9e4066Sahrens 			/*
121499653d4eSeschrock 			 * This occurs when one of the devices is below
1215fa9e4066Sahrens 			 * SPA_MINDEVSIZE.  Unfortunately, we can't detect which
1216fa9e4066Sahrens 			 * device was the problem device since there's no
1217fa9e4066Sahrens 			 * reliable way to determine device size from userland.
1218fa9e4066Sahrens 			 */
1219fa9e4066Sahrens 			{
1220fa9e4066Sahrens 				char buf[64];
1221fa9e4066Sahrens 
1222fa9e4066Sahrens 				zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf));
1223fa9e4066Sahrens 
122499653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
122599653d4eSeschrock 				    "one or more devices is less than the "
122699653d4eSeschrock 				    "minimum size (%s)"), buf);
1227fa9e4066Sahrens 			}
122899653d4eSeschrock 			return (zfs_error(hdl, EZFS_BADDEV, msg));
1229fa9e4066Sahrens 
1230fa9e4066Sahrens 		case ENOSPC:
123199653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
123299653d4eSeschrock 			    "one or more devices is out of space"));
123399653d4eSeschrock 			return (zfs_error(hdl, EZFS_BADDEV, msg));
1234fa9e4066Sahrens 
1235fa94a07fSbrendan 		case ENOTBLK:
1236fa94a07fSbrendan 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1237fa94a07fSbrendan 			    "cache device must be a disk or disk slice"));
1238fa94a07fSbrendan 			return (zfs_error(hdl, EZFS_BADDEV, msg));
1239fa94a07fSbrendan 
1240fa9e4066Sahrens 		default:
124199653d4eSeschrock 			return (zpool_standard_error(hdl, errno, msg));
1242fa9e4066Sahrens 		}
1243fa9e4066Sahrens 	}
1244fa9e4066Sahrens 
12450a48a24eStimh create_failed:
1246351420b3Slling 	zcmd_free_nvlists(&zc);
12470a48a24eStimh 	nvlist_free(zc_props);
12480a48a24eStimh 	nvlist_free(zc_fsprops);
12490a48a24eStimh 	return (ret);
1250fa9e4066Sahrens }
1251fa9e4066Sahrens 
1252fa9e4066Sahrens /*
1253fa9e4066Sahrens  * Destroy the given pool.  It is up to the caller to ensure that there are no
1254fa9e4066Sahrens  * datasets left in the pool.
1255fa9e4066Sahrens  */
1256fa9e4066Sahrens int
12574445fffbSMatthew Ahrens zpool_destroy(zpool_handle_t *zhp, const char *log_str)
1258fa9e4066Sahrens {
1259fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
1260fa9e4066Sahrens 	zfs_handle_t *zfp = NULL;
126199653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
126299653d4eSeschrock 	char msg[1024];
1263fa9e4066Sahrens 
1264fa9e4066Sahrens 	if (zhp->zpool_state == POOL_STATE_ACTIVE &&
1265cb04b873SMark J Musante 	    (zfp = zfs_open(hdl, zhp->zpool_name, ZFS_TYPE_FILESYSTEM)) == NULL)
1266fa9e4066Sahrens 		return (-1);
1267fa9e4066Sahrens 
1268fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
12694445fffbSMatthew Ahrens 	zc.zc_history = (uint64_t)(uintptr_t)log_str;
1270fa9e4066Sahrens 
1271cb04b873SMark J Musante 	if (zfs_ioctl(hdl, ZFS_IOC_POOL_DESTROY, &zc) != 0) {
127299653d4eSeschrock 		(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
127399653d4eSeschrock 		    "cannot destroy '%s'"), zhp->zpool_name);
1274fa9e4066Sahrens 
127599653d4eSeschrock 		if (errno == EROFS) {
127699653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
127799653d4eSeschrock 			    "one or more devices is read only"));
127899653d4eSeschrock 			(void) zfs_error(hdl, EZFS_BADDEV, msg);
127999653d4eSeschrock 		} else {
128099653d4eSeschrock 			(void) zpool_standard_error(hdl, errno, msg);
1281fa9e4066Sahrens 		}
1282fa9e4066Sahrens 
1283fa9e4066Sahrens 		if (zfp)
1284fa9e4066Sahrens 			zfs_close(zfp);
1285fa9e4066Sahrens 		return (-1);
1286fa9e4066Sahrens 	}
1287fa9e4066Sahrens 
1288fa9e4066Sahrens 	if (zfp) {
1289fa9e4066Sahrens 		remove_mountpoint(zfp);
1290fa9e4066Sahrens 		zfs_close(zfp);
1291fa9e4066Sahrens 	}
1292fa9e4066Sahrens 
1293fa9e4066Sahrens 	return (0);
1294fa9e4066Sahrens }
1295fa9e4066Sahrens 
129686714001SSerapheim Dimitropoulos /*
129786714001SSerapheim Dimitropoulos  * Create a checkpoint in the given pool.
129886714001SSerapheim Dimitropoulos  */
129986714001SSerapheim Dimitropoulos int
130086714001SSerapheim Dimitropoulos zpool_checkpoint(zpool_handle_t *zhp)
130186714001SSerapheim Dimitropoulos {
130286714001SSerapheim Dimitropoulos 	libzfs_handle_t *hdl = zhp->zpool_hdl;
130386714001SSerapheim Dimitropoulos 	char msg[1024];
130486714001SSerapheim Dimitropoulos 	int error;
130586714001SSerapheim Dimitropoulos 
130686714001SSerapheim Dimitropoulos 	error = lzc_pool_checkpoint(zhp->zpool_name);
130786714001SSerapheim Dimitropoulos 	if (error != 0) {
130886714001SSerapheim Dimitropoulos 		(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
130986714001SSerapheim Dimitropoulos 		    "cannot checkpoint '%s'"), zhp->zpool_name);
131086714001SSerapheim Dimitropoulos 		(void) zpool_standard_error(hdl, error, msg);
131186714001SSerapheim Dimitropoulos 		return (-1);
131286714001SSerapheim Dimitropoulos 	}
131386714001SSerapheim Dimitropoulos 
131486714001SSerapheim Dimitropoulos 	return (0);
131586714001SSerapheim Dimitropoulos }
131686714001SSerapheim Dimitropoulos 
131786714001SSerapheim Dimitropoulos /*
131886714001SSerapheim Dimitropoulos  * Discard the checkpoint from the given pool.
131986714001SSerapheim Dimitropoulos  */
132086714001SSerapheim Dimitropoulos int
132186714001SSerapheim Dimitropoulos zpool_discard_checkpoint(zpool_handle_t *zhp)
132286714001SSerapheim Dimitropoulos {
132386714001SSerapheim Dimitropoulos 	libzfs_handle_t *hdl = zhp->zpool_hdl;
132486714001SSerapheim Dimitropoulos 	char msg[1024];
132586714001SSerapheim Dimitropoulos 	int error;
132686714001SSerapheim Dimitropoulos 
132786714001SSerapheim Dimitropoulos 	error = lzc_pool_checkpoint_discard(zhp->zpool_name);
132886714001SSerapheim Dimitropoulos 	if (error != 0) {
132986714001SSerapheim Dimitropoulos 		(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
133086714001SSerapheim Dimitropoulos 		    "cannot discard checkpoint in '%s'"), zhp->zpool_name);
133186714001SSerapheim Dimitropoulos 		(void) zpool_standard_error(hdl, error, msg);
133286714001SSerapheim Dimitropoulos 		return (-1);
133386714001SSerapheim Dimitropoulos 	}
133486714001SSerapheim Dimitropoulos 
133586714001SSerapheim Dimitropoulos 	return (0);
133686714001SSerapheim Dimitropoulos }
133786714001SSerapheim Dimitropoulos 
1338fa9e4066Sahrens /*
1339fa9e4066Sahrens  * Add the given vdevs to the pool.  The caller must have already performed the
1340fa9e4066Sahrens  * necessary verification to ensure that the vdev specification is well-formed.
1341fa9e4066Sahrens  */
1342fa9e4066Sahrens int
1343fa9e4066Sahrens zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot)
1344fa9e4066Sahrens {
1345e9dbad6fSeschrock 	zfs_cmd_t zc = { 0 };
134699653d4eSeschrock 	int ret;
134799653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
134899653d4eSeschrock 	char msg[1024];
1349fa94a07fSbrendan 	nvlist_t **spares, **l2cache;
1350fa94a07fSbrendan 	uint_t nspares, nl2cache;
135199653d4eSeschrock 
135299653d4eSeschrock 	(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
135399653d4eSeschrock 	    "cannot add to '%s'"), zhp->zpool_name);
135499653d4eSeschrock 
1355fa94a07fSbrendan 	if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) <
1356fa94a07fSbrendan 	    SPA_VERSION_SPARES &&
135799653d4eSeschrock 	    nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
135899653d4eSeschrock 	    &spares, &nspares) == 0) {
135999653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be "
136099653d4eSeschrock 		    "upgraded to add hot spares"));
136199653d4eSeschrock 		return (zfs_error(hdl, EZFS_BADVERSION, msg));
136299653d4eSeschrock 	}
1363fa9e4066Sahrens 
1364fa94a07fSbrendan 	if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) <
1365fa94a07fSbrendan 	    SPA_VERSION_L2CACHE &&
1366fa94a07fSbrendan 	    nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
1367fa94a07fSbrendan 	    &l2cache, &nl2cache) == 0) {
1368fa94a07fSbrendan 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be "
1369fa94a07fSbrendan 		    "upgraded to add cache devices"));
1370fa94a07fSbrendan 		return (zfs_error(hdl, EZFS_BADVERSION, msg));
1371fa94a07fSbrendan 	}
1372fa94a07fSbrendan 
1373990b4856Slling 	if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0)
137499653d4eSeschrock 		return (-1);
1375fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
1376fa9e4066Sahrens 
1377cb04b873SMark J Musante 	if (zfs_ioctl(hdl, ZFS_IOC_VDEV_ADD, &zc) != 0) {
1378fa9e4066Sahrens 		switch (errno) {
1379fa9e4066Sahrens 		case EBUSY:
1380fa9e4066Sahrens 			/*
1381fa9e4066Sahrens 			 * This can happen if the user has specified the same
1382fa9e4066Sahrens 			 * device multiple times.  We can't reliably detect this
1383fa9e4066Sahrens 			 * until we try to add it and see we already have a
1384fa9e4066Sahrens 			 * label.
1385fa9e4066Sahrens 			 */
138699653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
138799653d4eSeschrock 			    "one or more vdevs refer to the same device"));
138899653d4eSeschrock 			(void) zfs_error(hdl, EZFS_BADDEV, msg);
1389fa9e4066Sahrens 			break;
1390fa9e4066Sahrens 
13915cabbc6bSPrashanth Sreenivasa 		case EINVAL:
13925cabbc6bSPrashanth Sreenivasa 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
13935cabbc6bSPrashanth Sreenivasa 			    "invalid config; a pool with removing/removed "
13945cabbc6bSPrashanth Sreenivasa 			    "vdevs does not support adding raidz vdevs"));
13955cabbc6bSPrashanth Sreenivasa 			(void) zfs_error(hdl, EZFS_BADDEV, msg);
13965cabbc6bSPrashanth Sreenivasa 			break;
13975cabbc6bSPrashanth Sreenivasa 
1398fa9e4066Sahrens 		case EOVERFLOW:
1399fa9e4066Sahrens 			/*
1400fa9e4066Sahrens 			 * This occurrs when one of the devices is below
1401fa9e4066Sahrens 			 * SPA_MINDEVSIZE.  Unfortunately, we can't detect which
1402fa9e4066Sahrens 			 * device was the problem device since there's no
1403fa9e4066Sahrens 			 * reliable way to determine device size from userland.
1404fa9e4066Sahrens 			 */
1405fa9e4066Sahrens 			{
1406fa9e4066Sahrens 				char buf[64];
1407fa9e4066Sahrens 
1408fa9e4066Sahrens 				zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf));
1409fa9e4066Sahrens 
141099653d4eSeschrock 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
141199653d4eSeschrock 				    "device is less than the minimum "
141299653d4eSeschrock 				    "size (%s)"), buf);
1413fa9e4066Sahrens 			}
141499653d4eSeschrock 			(void) zfs_error(hdl, EZFS_BADDEV, msg);
141599653d4eSeschrock 			break;
141699653d4eSeschrock 
141799653d4eSeschrock 		case ENOTSUP:
141899653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
14198654d025Sperrin 			    "pool must be upgraded to add these vdevs"));
142099653d4eSeschrock 			(void) zfs_error(hdl, EZFS_BADVERSION, msg);
1421fa9e4066Sahrens 			break;
1422fa9e4066Sahrens 
1423b1b8ab34Slling 		case EDOM:
1424b1b8ab34Slling 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
14258654d025Sperrin 			    "root pool can not have multiple vdevs"
14268654d025Sperrin 			    " or separate logs"));
1427b1b8ab34Slling 			(void) zfs_error(hdl, EZFS_POOL_NOTSUP, msg);
1428b1b8ab34Slling 			break;
1429b1b8ab34Slling 
1430fa94a07fSbrendan 		case ENOTBLK:
1431fa94a07fSbrendan 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1432fa94a07fSbrendan 			    "cache device must be a disk or disk slice"));
1433fa94a07fSbrendan 			(void) zfs_error(hdl, EZFS_BADDEV, msg);
1434fa94a07fSbrendan 			break;
1435fa94a07fSbrendan 
1436fa9e4066Sahrens 		default:
143799653d4eSeschrock 			(void) zpool_standard_error(hdl, errno, msg);
1438fa9e4066Sahrens 		}
1439fa9e4066Sahrens 
144099653d4eSeschrock 		ret = -1;
144199653d4eSeschrock 	} else {
144299653d4eSeschrock 		ret = 0;
1443fa9e4066Sahrens 	}
1444fa9e4066Sahrens 
1445e9dbad6fSeschrock 	zcmd_free_nvlists(&zc);
1446fa9e4066Sahrens 
144799653d4eSeschrock 	return (ret);
1448fa9e4066Sahrens }
1449fa9e4066Sahrens 
1450fa9e4066Sahrens /*
1451fa9e4066Sahrens  * Exports the pool from the system.  The caller must ensure that there are no
1452fa9e4066Sahrens  * mounted datasets in the pool.
1453fa9e4066Sahrens  */
14544445fffbSMatthew Ahrens static int
14554445fffbSMatthew Ahrens zpool_export_common(zpool_handle_t *zhp, boolean_t force, boolean_t hardforce,
14564445fffbSMatthew Ahrens     const char *log_str)
1457fa9e4066Sahrens {
1458fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
145989a89ebfSlling 	char msg[1024];
1460fa9e4066Sahrens 
146189a89ebfSlling 	(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
146289a89ebfSlling 	    "cannot export '%s'"), zhp->zpool_name);
146389a89ebfSlling 
1464fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
146589a89ebfSlling 	zc.zc_cookie = force;
1466394ab0cbSGeorge Wilson 	zc.zc_guid = hardforce;
14674445fffbSMatthew Ahrens 	zc.zc_history = (uint64_t)(uintptr_t)log_str;
146889a89ebfSlling 
146989a89ebfSlling 	if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_EXPORT, &zc) != 0) {
147089a89ebfSlling 		switch (errno) {
147189a89ebfSlling 		case EXDEV:
147289a89ebfSlling 			zfs_error_aux(zhp->zpool_hdl, dgettext(TEXT_DOMAIN,
147389a89ebfSlling 			    "use '-f' to override the following errors:\n"
147489a89ebfSlling 			    "'%s' has an active shared spare which could be"
147589a89ebfSlling 			    " used by other pools once '%s' is exported."),
147689a89ebfSlling 			    zhp->zpool_name, zhp->zpool_name);
147789a89ebfSlling 			return (zfs_error(zhp->zpool_hdl, EZFS_ACTIVE_SPARE,
147889a89ebfSlling 			    msg));
147989a89ebfSlling 		default:
148089a89ebfSlling 			return (zpool_standard_error_fmt(zhp->zpool_hdl, errno,
148189a89ebfSlling 			    msg));
148289a89ebfSlling 		}
148389a89ebfSlling 	}
1484fa9e4066Sahrens 
1485fa9e4066Sahrens 	return (0);
1486fa9e4066Sahrens }
1487fa9e4066Sahrens 
1488394ab0cbSGeorge Wilson int
14894445fffbSMatthew Ahrens zpool_export(zpool_handle_t *zhp, boolean_t force, const char *log_str)
1490394ab0cbSGeorge Wilson {
14914445fffbSMatthew Ahrens 	return (zpool_export_common(zhp, force, B_FALSE, log_str));
1492394ab0cbSGeorge Wilson }
1493394ab0cbSGeorge Wilson 
1494394ab0cbSGeorge Wilson int
14954445fffbSMatthew Ahrens zpool_export_force(zpool_handle_t *zhp, const char *log_str)
1496394ab0cbSGeorge Wilson {
14974445fffbSMatthew Ahrens 	return (zpool_export_common(zhp, B_TRUE, B_TRUE, log_str));
1498394ab0cbSGeorge Wilson }
1499394ab0cbSGeorge Wilson 
1500468c413aSTim Haley static void
1501468c413aSTim Haley zpool_rewind_exclaim(libzfs_handle_t *hdl, const char *name, boolean_t dryrun,
15024b964adaSGeorge Wilson     nvlist_t *config)
1503468c413aSTim Haley {
15044b964adaSGeorge Wilson 	nvlist_t *nv = NULL;
1505468c413aSTim Haley 	uint64_t rewindto;
1506468c413aSTim Haley 	int64_t loss = -1;
1507468c413aSTim Haley 	struct tm t;
1508468c413aSTim Haley 	char timestr[128];
1509468c413aSTim Haley 
15104b964adaSGeorge Wilson 	if (!hdl->libzfs_printerr || config == NULL)
15114b964adaSGeorge Wilson 		return;
15124b964adaSGeorge Wilson 
1513ad135b5dSChristopher Siden 	if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO, &nv) != 0 ||
1514ad135b5dSChristopher Siden 	    nvlist_lookup_nvlist(nv, ZPOOL_CONFIG_REWIND_INFO, &nv) != 0) {
1515468c413aSTim Haley 		return;
1516ad135b5dSChristopher Siden 	}
1517468c413aSTim Haley 
15184b964adaSGeorge Wilson 	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_LOAD_TIME, &rewindto) != 0)
1519468c413aSTim Haley 		return;
15204b964adaSGeorge Wilson 	(void) nvlist_lookup_int64(nv, ZPOOL_CONFIG_REWIND_TIME, &loss);
1521468c413aSTim Haley 
1522468c413aSTim Haley 	if (localtime_r((time_t *)&rewindto, &t) != NULL &&
1523468c413aSTim Haley 	    strftime(timestr, 128, 0, &t) != 0) {
1524468c413aSTim Haley 		if (dryrun) {
1525468c413aSTim Haley 			(void) printf(dgettext(TEXT_DOMAIN,
1526468c413aSTim Haley 			    "Would be able to return %s "
1527468c413aSTim Haley 			    "to its state as of %s.\n"),
1528468c413aSTim Haley 			    name, timestr);
1529468c413aSTim Haley 		} else {
1530468c413aSTim Haley 			(void) printf(dgettext(TEXT_DOMAIN,
1531468c413aSTim Haley 			    "Pool %s returned to its state as of %s.\n"),
1532468c413aSTim Haley 			    name, timestr);
1533468c413aSTim Haley 		}
1534468c413aSTim Haley 		if (loss > 120) {
1535468c413aSTim Haley 			(void) printf(dgettext(TEXT_DOMAIN,
1536468c413aSTim Haley 			    "%s approximately %lld "),
1537468c413aSTim Haley 			    dryrun ? "Would discard" : "Discarded",
1538468c413aSTim Haley 			    (loss + 30) / 60);
1539468c413aSTim Haley 			(void) printf(dgettext(TEXT_DOMAIN,
1540468c413aSTim Haley 			    "minutes of transactions.\n"));
1541468c413aSTim Haley 		} else if (loss > 0) {
1542468c413aSTim Haley 			(void) printf(dgettext(TEXT_DOMAIN,
1543468c413aSTim Haley 			    "%s approximately %lld "),
1544468c413aSTim Haley 			    dryrun ? "Would discard" : "Discarded", loss);
1545468c413aSTim Haley 			(void) printf(dgettext(TEXT_DOMAIN,
1546468c413aSTim Haley 			    "seconds of transactions.\n"));
1547468c413aSTim Haley 		}
1548468c413aSTim Haley 	}
1549468c413aSTim Haley }
1550468c413aSTim Haley 
1551468c413aSTim Haley void
1552468c413aSTim Haley zpool_explain_recover(libzfs_handle_t *hdl, const char *name, int reason,
1553468c413aSTim Haley     nvlist_t *config)
1554468c413aSTim Haley {
15554b964adaSGeorge Wilson 	nvlist_t *nv = NULL;
1556468c413aSTim Haley 	int64_t loss = -1;
1557468c413aSTim Haley 	uint64_t edata = UINT64_MAX;
1558468c413aSTim Haley 	uint64_t rewindto;
1559468c413aSTim Haley 	struct tm t;
1560468c413aSTim Haley 	char timestr[128];
1561468c413aSTim Haley 
1562468c413aSTim Haley 	if (!hdl->libzfs_printerr)
1563468c413aSTim Haley 		return;
1564468c413aSTim Haley 
1565468c413aSTim Haley 	if (reason >= 0)
1566468c413aSTim Haley 		(void) printf(dgettext(TEXT_DOMAIN, "action: "));
1567468c413aSTim Haley 	else
1568468c413aSTim Haley 		(void) printf(dgettext(TEXT_DOMAIN, "\t"));
1569468c413aSTim Haley 
1570468c413aSTim Haley 	/* All attempted rewinds failed if ZPOOL_CONFIG_LOAD_TIME missing */
15714b964adaSGeorge Wilson 	if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO, &nv) != 0 ||
1572ad135b5dSChristopher Siden 	    nvlist_lookup_nvlist(nv, ZPOOL_CONFIG_REWIND_INFO, &nv) != 0 ||
15734b964adaSGeorge Wilson 	    nvlist_lookup_uint64(nv, ZPOOL_CONFIG_LOAD_TIME, &rewindto) != 0)
1574468c413aSTim Haley 		goto no_info;
1575468c413aSTim Haley 
15764b964adaSGeorge Wilson 	(void) nvlist_lookup_int64(nv, ZPOOL_CONFIG_REWIND_TIME, &loss);
15774b964adaSGeorge Wilson 	(void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_LOAD_DATA_ERRORS,
1578468c413aSTim Haley 	    &edata);
1579468c413aSTim Haley 
1580468c413aSTim Haley 	(void) printf(dgettext(TEXT_DOMAIN,
1581468c413aSTim Haley 	    "Recovery is possible, but will result in some data loss.\n"));
1582468c413aSTim Haley 
1583468c413aSTim Haley 	if (localtime_r((time_t *)&rewindto, &t) != NULL &&
1584468c413aSTim Haley 	    strftime(timestr, 128, 0, &t) != 0) {
1585468c413aSTim Haley 		(void) printf(dgettext(TEXT_DOMAIN,
1586468c413aSTim Haley 		    "\tReturning the pool to its state as of %s\n"
1587468c413aSTim Haley 		    "\tshould correct the problem.  "),
1588468c413aSTim Haley 		    timestr);
1589468c413aSTim Haley 	} else {
1590468c413aSTim Haley 		(void) printf(dgettext(TEXT_DOMAIN,
1591468c413aSTim Haley 		    "\tReverting the pool to an earlier state "
1592468c413aSTim Haley 		    "should correct the problem.\n\t"));
1593468c413aSTim Haley 	}
1594468c413aSTim Haley 
1595468c413aSTim Haley 	if (loss > 120) {
1596468c413aSTim Haley 		(void) printf(dgettext(TEXT_DOMAIN,
1597468c413aSTim Haley 		    "Approximately %lld minutes of data\n"
1598468c413aSTim Haley 		    "\tmust be discarded, irreversibly.  "), (loss + 30) / 60);
1599468c413aSTim Haley 	} else if (loss > 0) {
1600468c413aSTim Haley 		(void) printf(dgettext(TEXT_DOMAIN,
1601468c413aSTim Haley 		    "Approximately %lld seconds of data\n"
1602468c413aSTim Haley 		    "\tmust be discarded, irreversibly.  "), loss);
1603468c413aSTim Haley 	}
1604468c413aSTim Haley 	if (edata != 0 && edata != UINT64_MAX) {
1605468c413aSTim Haley 		if (edata == 1) {
1606468c413aSTim Haley 			(void) printf(dgettext(TEXT_DOMAIN,
1607468c413aSTim Haley 			    "After rewind, at least\n"
1608468c413aSTim Haley 			    "\tone persistent user-data error will remain.  "));
1609468c413aSTim Haley 		} else {
1610468c413aSTim Haley 			(void) printf(dgettext(TEXT_DOMAIN,
1611468c413aSTim Haley 			    "After rewind, several\n"
1612468c413aSTim Haley 			    "\tpersistent user-data errors will remain.  "));
1613468c413aSTim Haley 		}
1614468c413aSTim Haley 	}
1615468c413aSTim Haley 	(void) printf(dgettext(TEXT_DOMAIN,
1616a33cae98STim Haley 	    "Recovery can be attempted\n\tby executing 'zpool %s -F %s'.  "),
1617a33cae98STim Haley 	    reason >= 0 ? "clear" : "import", name);
1618468c413aSTim Haley 
1619468c413aSTim Haley 	(void) printf(dgettext(TEXT_DOMAIN,
1620468c413aSTim Haley 	    "A scrub of the pool\n"
1621468c413aSTim Haley 	    "\tis strongly recommended after recovery.\n"));
1622468c413aSTim Haley 	return;
1623468c413aSTim Haley 
1624468c413aSTim Haley no_info:
1625468c413aSTim Haley 	(void) printf(dgettext(TEXT_DOMAIN,
1626468c413aSTim Haley 	    "Destroy and re-create the pool from\n\ta backup source.\n"));
1627468c413aSTim Haley }
1628468c413aSTim Haley 
1629fa9e4066Sahrens /*
1630990b4856Slling  * zpool_import() is a contracted interface. Should be kept the same
1631990b4856Slling  * if possible.
1632990b4856Slling  *
1633990b4856Slling  * Applications should use zpool_import_props() to import a pool with
1634990b4856Slling  * new properties value to be set.
1635fa9e4066Sahrens  */
1636fa9e4066Sahrens int
163799653d4eSeschrock zpool_import(libzfs_handle_t *hdl, nvlist_t *config, const char *newname,
1638990b4856Slling     char *altroot)
1639990b4856Slling {
1640990b4856Slling 	nvlist_t *props = NULL;
1641990b4856Slling 	int ret;
1642990b4856Slling 
1643990b4856Slling 	if (altroot != NULL) {
1644990b4856Slling 		if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) {
1645990b4856Slling 			return (zfs_error_fmt(hdl, EZFS_NOMEM,
1646990b4856Slling 			    dgettext(TEXT_DOMAIN, "cannot import '%s'"),
1647990b4856Slling 			    newname));
1648990b4856Slling 		}
1649990b4856Slling 
1650990b4856Slling 		if (nvlist_add_string(props,
1651352d8027SGeorge Wilson 		    zpool_prop_to_name(ZPOOL_PROP_ALTROOT), altroot) != 0 ||
1652352d8027SGeorge Wilson 		    nvlist_add_string(props,
1653352d8027SGeorge Wilson 		    zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), "none") != 0) {
1654990b4856Slling 			nvlist_free(props);
1655990b4856Slling 			return (zfs_error_fmt(hdl, EZFS_NOMEM,
1656990b4856Slling 			    dgettext(TEXT_DOMAIN, "cannot import '%s'"),
1657990b4856Slling 			    newname));
1658990b4856Slling 		}
1659990b4856Slling 	}
1660990b4856Slling 
16614b964adaSGeorge Wilson 	ret = zpool_import_props(hdl, config, newname, props,
16624b964adaSGeorge Wilson 	    ZFS_IMPORT_NORMAL);
1663aab83bb8SJosef 'Jeff' Sipek 	nvlist_free(props);
1664990b4856Slling 	return (ret);
1665990b4856Slling }
1666990b4856Slling 
16674b964adaSGeorge Wilson static void
16684b964adaSGeorge Wilson print_vdev_tree(libzfs_handle_t *hdl, const char *name, nvlist_t *nv,
16694b964adaSGeorge Wilson     int indent)
16704b964adaSGeorge Wilson {
16714b964adaSGeorge Wilson 	nvlist_t **child;
16724b964adaSGeorge Wilson 	uint_t c, children;
16734b964adaSGeorge Wilson 	char *vname;
16744b964adaSGeorge Wilson 	uint64_t is_log = 0;
16754b964adaSGeorge Wilson 
16764b964adaSGeorge Wilson 	(void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_IS_LOG,
16774b964adaSGeorge Wilson 	    &is_log);
16784b964adaSGeorge Wilson 
16794b964adaSGeorge Wilson 	if (name != NULL)
16804b964adaSGeorge Wilson 		(void) printf("\t%*s%s%s\n", indent, "", name,
16814b964adaSGeorge Wilson 		    is_log ? " [log]" : "");
16824b964adaSGeorge Wilson 
16834b964adaSGeorge Wilson 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
16844b964adaSGeorge Wilson 	    &child, &children) != 0)
16854b964adaSGeorge Wilson 		return;
16864b964adaSGeorge Wilson 
16874b964adaSGeorge Wilson 	for (c = 0; c < children; c++) {
16884b964adaSGeorge Wilson 		vname = zpool_vdev_name(hdl, NULL, child[c], B_TRUE);
16894b964adaSGeorge Wilson 		print_vdev_tree(hdl, vname, child[c], indent + 2);
16904b964adaSGeorge Wilson 		free(vname);
16914b964adaSGeorge Wilson 	}
16924b964adaSGeorge Wilson }
16934b964adaSGeorge Wilson 
1694ad135b5dSChristopher Siden void
1695ad135b5dSChristopher Siden zpool_print_unsup_feat(nvlist_t *config)
1696ad135b5dSChristopher Siden {
1697ad135b5dSChristopher Siden 	nvlist_t *nvinfo, *unsup_feat;
1698ad135b5dSChristopher Siden 
1699ad135b5dSChristopher Siden 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO, &nvinfo) ==
1700ad135b5dSChristopher Siden 	    0);
1701ad135b5dSChristopher Siden 	verify(nvlist_lookup_nvlist(nvinfo, ZPOOL_CONFIG_UNSUP_FEAT,
1702ad135b5dSChristopher Siden 	    &unsup_feat) == 0);
1703ad135b5dSChristopher Siden 
1704ad135b5dSChristopher Siden 	for (nvpair_t *nvp = nvlist_next_nvpair(unsup_feat, NULL); nvp != NULL;
1705ad135b5dSChristopher Siden 	    nvp = nvlist_next_nvpair(unsup_feat, nvp)) {
1706ad135b5dSChristopher Siden 		char *desc;
1707ad135b5dSChristopher Siden 
1708ad135b5dSChristopher Siden 		verify(nvpair_type(nvp) == DATA_TYPE_STRING);
1709ad135b5dSChristopher Siden 		verify(nvpair_value_string(nvp, &desc) == 0);
1710ad135b5dSChristopher Siden 
1711ad135b5dSChristopher Siden 		if (strlen(desc) > 0)
1712ad135b5dSChristopher Siden 			(void) printf("\t%s (%s)\n", nvpair_name(nvp), desc);
1713ad135b5dSChristopher Siden 		else
1714ad135b5dSChristopher Siden 			(void) printf("\t%s\n", nvpair_name(nvp));
1715ad135b5dSChristopher Siden 	}
1716ad135b5dSChristopher Siden }
1717ad135b5dSChristopher Siden 
1718990b4856Slling /*
1719990b4856Slling  * Import the given pool using the known configuration and a list of
1720990b4856Slling  * properties to be set. The configuration should have come from
1721990b4856Slling  * zpool_find_import(). The 'newname' parameters control whether the pool
1722990b4856Slling  * is imported with a different name.
1723990b4856Slling  */
1724990b4856Slling int
1725990b4856Slling zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname,
17264b964adaSGeorge Wilson     nvlist_t *props, int flags)
1727fa9e4066Sahrens {
1728e9dbad6fSeschrock 	zfs_cmd_t zc = { 0 };
17295dafeea3SPavel Zakharov 	zpool_load_policy_t policy;
17304b964adaSGeorge Wilson 	nvlist_t *nv = NULL;
17314b964adaSGeorge Wilson 	nvlist_t *nvinfo = NULL;
17324b964adaSGeorge Wilson 	nvlist_t *missing = NULL;
1733fa9e4066Sahrens 	char *thename;
1734fa9e4066Sahrens 	char *origname;
1735fa9e4066Sahrens 	int ret;
17364b964adaSGeorge Wilson 	int error = 0;
1737990b4856Slling 	char errbuf[1024];
1738fa9e4066Sahrens 
1739fa9e4066Sahrens 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
1740fa9e4066Sahrens 	    &origname) == 0);
1741fa9e4066Sahrens 
1742990b4856Slling 	(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
1743990b4856Slling 	    "cannot import pool '%s'"), origname);
1744990b4856Slling 
1745fa9e4066Sahrens 	if (newname != NULL) {
174699653d4eSeschrock 		if (!zpool_name_valid(hdl, B_FALSE, newname))
1747ece3d9b3Slling 			return (zfs_error_fmt(hdl, EZFS_INVALIDNAME,
174899653d4eSeschrock 			    dgettext(TEXT_DOMAIN, "cannot import '%s'"),
174999653d4eSeschrock 			    newname));
1750fa9e4066Sahrens 		thename = (char *)newname;
1751fa9e4066Sahrens 	} else {
1752fa9e4066Sahrens 		thename = origname;
1753fa9e4066Sahrens 	}
1754fa9e4066Sahrens 
1755078266a5SMarcel Telka 	if (props != NULL) {
1756990b4856Slling 		uint64_t version;
1757f9af39baSGeorge Wilson 		prop_flags_t flags = { .create = B_FALSE, .import = B_TRUE };
1758fa9e4066Sahrens 
1759990b4856Slling 		verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
1760990b4856Slling 		    &version) == 0);
1761fa9e4066Sahrens 
17620a48a24eStimh 		if ((props = zpool_valid_proplist(hdl, origname,
1763078266a5SMarcel Telka 		    props, version, flags, errbuf)) == NULL)
1764990b4856Slling 			return (-1);
1765078266a5SMarcel Telka 		if (zcmd_write_src_nvlist(hdl, &zc, props) != 0) {
1766351420b3Slling 			nvlist_free(props);
1767990b4856Slling 			return (-1);
1768351420b3Slling 		}
1769078266a5SMarcel Telka 		nvlist_free(props);
1770990b4856Slling 	}
1771990b4856Slling 
1772990b4856Slling 	(void) strlcpy(zc.zc_name, thename, sizeof (zc.zc_name));
1773fa9e4066Sahrens 
1774fa9e4066Sahrens 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
1775ea8dc4b6Seschrock 	    &zc.zc_guid) == 0);
1776fa9e4066Sahrens 
1777351420b3Slling 	if (zcmd_write_conf_nvlist(hdl, &zc, config) != 0) {
1778078266a5SMarcel Telka 		zcmd_free_nvlists(&zc);
177999653d4eSeschrock 		return (-1);
1780351420b3Slling 	}
178157f304caSGeorge Wilson 	if (zcmd_alloc_dst_nvlist(hdl, &zc, zc.zc_nvlist_conf_size * 2) != 0) {
1782078266a5SMarcel Telka 		zcmd_free_nvlists(&zc);
1783468c413aSTim Haley 		return (-1);
1784468c413aSTim Haley 	}
1785fa9e4066Sahrens 
17864b964adaSGeorge Wilson 	zc.zc_cookie = flags;
17874b964adaSGeorge Wilson 	while ((ret = zfs_ioctl(hdl, ZFS_IOC_POOL_IMPORT, &zc)) != 0 &&
17884b964adaSGeorge Wilson 	    errno == ENOMEM) {
17894b964adaSGeorge Wilson 		if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
17904b964adaSGeorge Wilson 			zcmd_free_nvlists(&zc);
17914b964adaSGeorge Wilson 			return (-1);
17924b964adaSGeorge Wilson 		}
17934b964adaSGeorge Wilson 	}
17944b964adaSGeorge Wilson 	if (ret != 0)
17954b964adaSGeorge Wilson 		error = errno;
17964b964adaSGeorge Wilson 
17974b964adaSGeorge Wilson 	(void) zcmd_read_dst_nvlist(hdl, &zc, &nv);
1798078266a5SMarcel Telka 
1799078266a5SMarcel Telka 	zcmd_free_nvlists(&zc);
1800078266a5SMarcel Telka 
18015dafeea3SPavel Zakharov 	zpool_get_load_policy(config, &policy);
18024b964adaSGeorge Wilson 
18034b964adaSGeorge Wilson 	if (error) {
1804fa9e4066Sahrens 		char desc[1024];
1805468c413aSTim Haley 
1806468c413aSTim Haley 		/*
1807468c413aSTim Haley 		 * Dry-run failed, but we print out what success
1808468c413aSTim Haley 		 * looks like if we found a best txg
1809468c413aSTim Haley 		 */
18105dafeea3SPavel Zakharov 		if (policy.zlp_rewind & ZPOOL_TRY_REWIND) {
1811468c413aSTim Haley 			zpool_rewind_exclaim(hdl, newname ? origname : thename,
18124b964adaSGeorge Wilson 			    B_TRUE, nv);
18134b964adaSGeorge Wilson 			nvlist_free(nv);
1814468c413aSTim Haley 			return (-1);
1815468c413aSTim Haley 		}
1816468c413aSTim Haley 
1817fa9e4066Sahrens 		if (newname == NULL)
1818fa9e4066Sahrens 			(void) snprintf(desc, sizeof (desc),
1819fa9e4066Sahrens 			    dgettext(TEXT_DOMAIN, "cannot import '%s'"),
1820fa9e4066Sahrens 			    thename);
1821fa9e4066Sahrens 		else
1822fa9e4066Sahrens 			(void) snprintf(desc, sizeof (desc),
1823fa9e4066Sahrens 			    dgettext(TEXT_DOMAIN, "cannot import '%s' as '%s'"),
1824fa9e4066Sahrens 			    origname, thename);
1825fa9e4066Sahrens 
18264b964adaSGeorge Wilson 		switch (error) {
1827ea8dc4b6Seschrock 		case ENOTSUP:
1828ad135b5dSChristopher Siden 			if (nv != NULL && nvlist_lookup_nvlist(nv,
1829ad135b5dSChristopher Siden 			    ZPOOL_CONFIG_LOAD_INFO, &nvinfo) == 0 &&
1830ad135b5dSChristopher Siden 			    nvlist_exists(nvinfo, ZPOOL_CONFIG_UNSUP_FEAT)) {
1831ad135b5dSChristopher Siden 				(void) printf(dgettext(TEXT_DOMAIN, "This "
1832ad135b5dSChristopher Siden 				    "pool uses the following feature(s) not "
1833ad135b5dSChristopher Siden 				    "supported by this system:\n"));
1834ad135b5dSChristopher Siden 				zpool_print_unsup_feat(nv);
1835ad135b5dSChristopher Siden 				if (nvlist_exists(nvinfo,
1836ad135b5dSChristopher Siden 				    ZPOOL_CONFIG_CAN_RDONLY)) {
1837ad135b5dSChristopher Siden 					(void) printf(dgettext(TEXT_DOMAIN,
1838ad135b5dSChristopher Siden 					    "All unsupported features are only "
1839ad135b5dSChristopher Siden 					    "required for writing to the pool."
1840ad135b5dSChristopher Siden 					    "\nThe pool can be imported using "
1841ad135b5dSChristopher Siden 					    "'-o readonly=on'.\n"));
1842ad135b5dSChristopher Siden 				}
1843ad135b5dSChristopher Siden 			}
1844ea8dc4b6Seschrock 			/*
1845ea8dc4b6Seschrock 			 * Unsupported version.
1846ea8dc4b6Seschrock 			 */
184799653d4eSeschrock 			(void) zfs_error(hdl, EZFS_BADVERSION, desc);
1848ea8dc4b6Seschrock 			break;
1849ea8dc4b6Seschrock 
1850b5989ec7Seschrock 		case EINVAL:
1851b5989ec7Seschrock 			(void) zfs_error(hdl, EZFS_INVALCONFIG, desc);
1852b5989ec7Seschrock 			break;
1853b5989ec7Seschrock 
185454a91118SChris Kirby 		case EROFS:
185554a91118SChris Kirby 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
185654a91118SChris Kirby 			    "one or more devices is read only"));
185754a91118SChris Kirby 			(void) zfs_error(hdl, EZFS_BADDEV, desc);
185854a91118SChris Kirby 			break;
185954a91118SChris Kirby 
18604b964adaSGeorge Wilson 		case ENXIO:
18614b964adaSGeorge Wilson 			if (nv && nvlist_lookup_nvlist(nv,
18624b964adaSGeorge Wilson 			    ZPOOL_CONFIG_LOAD_INFO, &nvinfo) == 0 &&
18634b964adaSGeorge Wilson 			    nvlist_lookup_nvlist(nvinfo,
18644b964adaSGeorge Wilson 			    ZPOOL_CONFIG_MISSING_DEVICES, &missing) == 0) {
18654b964adaSGeorge Wilson 				(void) printf(dgettext(TEXT_DOMAIN,
18666f793812SPavel Zakharov 				    "The devices below are missing or "
18676f793812SPavel Zakharov 				    "corrupted, use '-m' to import the pool "
18686f793812SPavel Zakharov 				    "anyway:\n"));
18694b964adaSGeorge Wilson 				print_vdev_tree(hdl, NULL, missing, 2);
18704b964adaSGeorge Wilson 				(void) printf("\n");
18714b964adaSGeorge Wilson 			}
18724b964adaSGeorge Wilson 			(void) zpool_standard_error(hdl, error, desc);
18734b964adaSGeorge Wilson 			break;
18744b964adaSGeorge Wilson 
18754b964adaSGeorge Wilson 		case EEXIST:
18764b964adaSGeorge Wilson 			(void) zpool_standard_error(hdl, error, desc);
18774b964adaSGeorge Wilson 			break;
1878c971037bSPaul Dagnelie 		case ENAMETOOLONG:
1879c971037bSPaul Dagnelie 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1880c971037bSPaul Dagnelie 			    "new name of at least one dataset is longer than "
1881c971037bSPaul Dagnelie 			    "the maximum allowable length"));
1882c971037bSPaul Dagnelie 			(void) zfs_error(hdl, EZFS_NAMETOOLONG, desc);
1883c971037bSPaul Dagnelie 			break;
1884fa9e4066Sahrens 		default:
18854b964adaSGeorge Wilson 			(void) zpool_standard_error(hdl, error, desc);
1886468c413aSTim Haley 			zpool_explain_recover(hdl,
18874b964adaSGeorge Wilson 			    newname ? origname : thename, -error, nv);
1888468c413aSTim Haley 			break;
1889fa9e4066Sahrens 		}
1890fa9e4066Sahrens 
18914b964adaSGeorge Wilson 		nvlist_free(nv);
1892fa9e4066Sahrens 		ret = -1;
1893fa9e4066Sahrens 	} else {
1894fa9e4066Sahrens 		zpool_handle_t *zhp;
1895ecd6cf80Smarks 
1896fa9e4066Sahrens 		/*
1897fa9e4066Sahrens 		 * This should never fail, but play it safe anyway.
1898fa9e4066Sahrens 		 */
1899681d9761SEric Taylor 		if (zpool_open_silent(hdl, thename, &zhp) != 0)
190094de1d4cSeschrock 			ret = -1;
1901681d9761SEric Taylor 		else if (zhp != NULL)
1902fa9e4066Sahrens 			zpool_close(zhp);
19035dafeea3SPavel Zakharov 		if (policy.zlp_rewind &
1904468c413aSTim Haley 		    (ZPOOL_DO_REWIND | ZPOOL_TRY_REWIND)) {
1905468c413aSTim Haley 			zpool_rewind_exclaim(hdl, newname ? origname : thename,
19065dafeea3SPavel Zakharov 			    ((policy.zlp_rewind & ZPOOL_TRY_REWIND) != 0), nv);
1907468c413aSTim Haley 		}
19084b964adaSGeorge Wilson 		nvlist_free(nv);
1909468c413aSTim Haley 		return (0);
1910fa9e4066Sahrens 	}
1911fa9e4066Sahrens 
1912fa9e4066Sahrens 	return (ret);
1913fa9e4066Sahrens }
1914fa9e4066Sahrens 
1915fa9e4066Sahrens /*
19163f9d6ad7SLin Ling  * Scan the pool.
1917fa9e4066Sahrens  */
1918fa9e4066Sahrens int
19191702cce7SAlek Pinchuk zpool_scan(zpool_handle_t *zhp, pool_scan_func_t func, pool_scrub_cmd_t cmd)
1920fa9e4066Sahrens {
1921fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
1922fa9e4066Sahrens 	char msg[1024];
19231702cce7SAlek Pinchuk 	int err;
192499653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
1925fa9e4066Sahrens 
1926fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
19273f9d6ad7SLin Ling 	zc.zc_cookie = func;
19281702cce7SAlek Pinchuk 	zc.zc_flags = cmd;
1929fa9e4066Sahrens 
19301702cce7SAlek Pinchuk 	if (zfs_ioctl(hdl, ZFS_IOC_POOL_SCAN, &zc) == 0)
19311702cce7SAlek Pinchuk 		return (0);
19321702cce7SAlek Pinchuk 
19331702cce7SAlek Pinchuk 	err = errno;
19341702cce7SAlek Pinchuk 
19351702cce7SAlek Pinchuk 	/* ECANCELED on a scrub means we resumed a paused scrub */
19361702cce7SAlek Pinchuk 	if (err == ECANCELED && func == POOL_SCAN_SCRUB &&
19371702cce7SAlek Pinchuk 	    cmd == POOL_SCRUB_NORMAL)
19381702cce7SAlek Pinchuk 		return (0);
19391702cce7SAlek Pinchuk 
19401702cce7SAlek Pinchuk 	if (err == ENOENT && func != POOL_SCAN_NONE && cmd == POOL_SCRUB_NORMAL)
1941fa9e4066Sahrens 		return (0);
1942fa9e4066Sahrens 
19433f9d6ad7SLin Ling 	if (func == POOL_SCAN_SCRUB) {
19441702cce7SAlek Pinchuk 		if (cmd == POOL_SCRUB_PAUSE) {
19451702cce7SAlek Pinchuk 			(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
19461702cce7SAlek Pinchuk 			    "cannot pause scrubbing %s"), zc.zc_name);
19471702cce7SAlek Pinchuk 		} else {
19481702cce7SAlek Pinchuk 			assert(cmd == POOL_SCRUB_NORMAL);
19491702cce7SAlek Pinchuk 			(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
19501702cce7SAlek Pinchuk 			    "cannot scrub %s"), zc.zc_name);
19511702cce7SAlek Pinchuk 		}
19523f9d6ad7SLin Ling 	} else if (func == POOL_SCAN_NONE) {
19533f9d6ad7SLin Ling 		(void) snprintf(msg, sizeof (msg),
19543f9d6ad7SLin Ling 		    dgettext(TEXT_DOMAIN, "cannot cancel scrubbing %s"),
19553f9d6ad7SLin Ling 		    zc.zc_name);
19563f9d6ad7SLin Ling 	} else {
19573f9d6ad7SLin Ling 		assert(!"unexpected result");
19583f9d6ad7SLin Ling 	}
1959fa9e4066Sahrens 
19601702cce7SAlek Pinchuk 	if (err == EBUSY) {
19613f9d6ad7SLin Ling 		nvlist_t *nvroot;
19623f9d6ad7SLin Ling 		pool_scan_stat_t *ps = NULL;
19633f9d6ad7SLin Ling 		uint_t psc;
19643f9d6ad7SLin Ling 
19653f9d6ad7SLin Ling 		verify(nvlist_lookup_nvlist(zhp->zpool_config,
19663f9d6ad7SLin Ling 		    ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
19673f9d6ad7SLin Ling 		(void) nvlist_lookup_uint64_array(nvroot,
19683f9d6ad7SLin Ling 		    ZPOOL_CONFIG_SCAN_STATS, (uint64_t **)&ps, &psc);
19691702cce7SAlek Pinchuk 		if (ps && ps->pss_func == POOL_SCAN_SCRUB) {
19701702cce7SAlek Pinchuk 			if (cmd == POOL_SCRUB_PAUSE)
19711702cce7SAlek Pinchuk 				return (zfs_error(hdl, EZFS_SCRUB_PAUSED, msg));
19721702cce7SAlek Pinchuk 			else
19731702cce7SAlek Pinchuk 				return (zfs_error(hdl, EZFS_SCRUBBING, msg));
19741702cce7SAlek Pinchuk 		} else {
19753f9d6ad7SLin Ling 			return (zfs_error(hdl, EZFS_RESILVERING, msg));
19761702cce7SAlek Pinchuk 		}
19771702cce7SAlek Pinchuk 	} else if (err == ENOENT) {
19783f9d6ad7SLin Ling 		return (zfs_error(hdl, EZFS_NO_SCRUB, msg));
19793f9d6ad7SLin Ling 	} else {
19801702cce7SAlek Pinchuk 		return (zpool_standard_error(hdl, err, msg));
19813f9d6ad7SLin Ling 	}
1982fa9e4066Sahrens }
1983fa9e4066Sahrens 
1984094e47e9SGeorge Wilson static int
1985094e47e9SGeorge Wilson xlate_init_err(int err)
1986094e47e9SGeorge Wilson {
1987094e47e9SGeorge Wilson 	switch (err) {
1988094e47e9SGeorge Wilson 	case ENODEV:
1989094e47e9SGeorge Wilson 		return (EZFS_NODEVICE);
1990094e47e9SGeorge Wilson 	case EINVAL:
1991094e47e9SGeorge Wilson 	case EROFS:
1992094e47e9SGeorge Wilson 		return (EZFS_BADDEV);
1993094e47e9SGeorge Wilson 	case EBUSY:
1994094e47e9SGeorge Wilson 		return (EZFS_INITIALIZING);
1995094e47e9SGeorge Wilson 	case ESRCH:
1996094e47e9SGeorge Wilson 		return (EZFS_NO_INITIALIZE);
1997094e47e9SGeorge Wilson 	}
1998094e47e9SGeorge Wilson 	return (err);
1999094e47e9SGeorge Wilson }
2000094e47e9SGeorge Wilson 
2001094e47e9SGeorge Wilson /*
2002094e47e9SGeorge Wilson  * Begin, suspend, or cancel the initialization (initializing of all free
2003094e47e9SGeorge Wilson  * blocks) for the given vdevs in the given pool.
2004094e47e9SGeorge Wilson  */
2005094e47e9SGeorge Wilson int
2006094e47e9SGeorge Wilson zpool_initialize(zpool_handle_t *zhp, pool_initialize_func_t cmd_type,
2007094e47e9SGeorge Wilson     nvlist_t *vds)
2008094e47e9SGeorge Wilson {
2009094e47e9SGeorge Wilson 	char msg[1024];
2010094e47e9SGeorge Wilson 	libzfs_handle_t *hdl = zhp->zpool_hdl;
2011094e47e9SGeorge Wilson 
2012094e47e9SGeorge Wilson 	nvlist_t *errlist;
2013094e47e9SGeorge Wilson 
2014094e47e9SGeorge Wilson 	/* translate vdev names to guids */
2015094e47e9SGeorge Wilson 	nvlist_t *vdev_guids = fnvlist_alloc();
2016094e47e9SGeorge Wilson 	nvlist_t *guids_to_paths = fnvlist_alloc();
2017094e47e9SGeorge Wilson 	boolean_t spare, cache;
2018094e47e9SGeorge Wilson 	nvlist_t *tgt;
2019094e47e9SGeorge Wilson 	nvpair_t *elem;
2020094e47e9SGeorge Wilson 
2021094e47e9SGeorge Wilson 	for (elem = nvlist_next_nvpair(vds, NULL); elem != NULL;
2022094e47e9SGeorge Wilson 	    elem = nvlist_next_nvpair(vds, elem)) {
2023094e47e9SGeorge Wilson 		char *vd_path = nvpair_name(elem);
2024094e47e9SGeorge Wilson 		tgt = zpool_find_vdev(zhp, vd_path, &spare, &cache, NULL);
2025094e47e9SGeorge Wilson 
2026094e47e9SGeorge Wilson 		if ((tgt == NULL) || cache || spare) {
2027094e47e9SGeorge Wilson 			(void) snprintf(msg, sizeof (msg),
2028094e47e9SGeorge Wilson 			    dgettext(TEXT_DOMAIN, "cannot initialize '%s'"),
2029094e47e9SGeorge Wilson 			    vd_path);
2030094e47e9SGeorge Wilson 			int err = (tgt == NULL) ? EZFS_NODEVICE :
2031094e47e9SGeorge Wilson 			    (spare ? EZFS_ISSPARE : EZFS_ISL2CACHE);
2032094e47e9SGeorge Wilson 			fnvlist_free(vdev_guids);
2033094e47e9SGeorge Wilson 			fnvlist_free(guids_to_paths);
2034094e47e9SGeorge Wilson 			return (zfs_error(hdl, err, msg));
2035094e47e9SGeorge Wilson 		}
2036094e47e9SGeorge Wilson 
2037094e47e9SGeorge Wilson 		uint64_t guid = fnvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID);
2038094e47e9SGeorge Wilson 		fnvlist_add_uint64(vdev_guids, vd_path, guid);
2039094e47e9SGeorge Wilson 
2040094e47e9SGeorge Wilson 		(void) snprintf(msg, sizeof (msg), "%llu", guid);
2041094e47e9SGeorge Wilson 		fnvlist_add_string(guids_to_paths, msg, vd_path);
2042094e47e9SGeorge Wilson 	}
2043094e47e9SGeorge Wilson 
2044094e47e9SGeorge Wilson 	int err = lzc_initialize(zhp->zpool_name, cmd_type, vdev_guids,
2045094e47e9SGeorge Wilson 	    &errlist);
2046094e47e9SGeorge Wilson 	fnvlist_free(vdev_guids);
2047094e47e9SGeorge Wilson 
2048094e47e9SGeorge Wilson 	if (err == 0) {
2049094e47e9SGeorge Wilson 		fnvlist_free(guids_to_paths);
2050094e47e9SGeorge Wilson 		return (0);
2051094e47e9SGeorge Wilson 	}
2052094e47e9SGeorge Wilson 
2053094e47e9SGeorge Wilson 	nvlist_t *vd_errlist = NULL;
2054094e47e9SGeorge Wilson 	if (errlist != NULL) {
2055094e47e9SGeorge Wilson 		vd_errlist = fnvlist_lookup_nvlist(errlist,
2056094e47e9SGeorge Wilson 		    ZPOOL_INITIALIZE_VDEVS);
2057094e47e9SGeorge Wilson 	}
2058094e47e9SGeorge Wilson 
2059094e47e9SGeorge Wilson 	(void) snprintf(msg, sizeof (msg),
2060094e47e9SGeorge Wilson 	    dgettext(TEXT_DOMAIN, "operation failed"));
2061094e47e9SGeorge Wilson 
2062094e47e9SGeorge Wilson 	for (elem = nvlist_next_nvpair(vd_errlist, NULL); elem != NULL;
2063094e47e9SGeorge Wilson 	    elem = nvlist_next_nvpair(vd_errlist, elem)) {
2064094e47e9SGeorge Wilson 		int64_t vd_error = xlate_init_err(fnvpair_value_int64(elem));
2065094e47e9SGeorge Wilson 		char *path = fnvlist_lookup_string(guids_to_paths,
2066094e47e9SGeorge Wilson 		    nvpair_name(elem));
2067094e47e9SGeorge Wilson 		(void) zfs_error_fmt(hdl, vd_error, "cannot initialize '%s'",
2068094e47e9SGeorge Wilson 		    path);
2069094e47e9SGeorge Wilson 	}
2070094e47e9SGeorge Wilson 
2071094e47e9SGeorge Wilson 	fnvlist_free(guids_to_paths);
2072094e47e9SGeorge Wilson 	if (vd_errlist != NULL)
2073094e47e9SGeorge Wilson 		return (-1);
2074094e47e9SGeorge Wilson 
2075094e47e9SGeorge Wilson 	return (zpool_standard_error(hdl, err, msg));
2076094e47e9SGeorge Wilson }
2077094e47e9SGeorge Wilson 
20783fdda499SJohn Harres /*
20793fdda499SJohn Harres  * This provides a very minimal check whether a given string is likely a
20803fdda499SJohn Harres  * c#t#d# style string.  Users of this are expected to do their own
20813fdda499SJohn Harres  * verification of the s# part.
20823fdda499SJohn Harres  */
20833fdda499SJohn Harres #define	CTD_CHECK(str)  (str && str[0] == 'c' && isdigit(str[1]))
20843fdda499SJohn Harres 
20853fdda499SJohn Harres /*
20863fdda499SJohn Harres  * More elaborate version for ones which may start with "/dev/dsk/"
20873fdda499SJohn Harres  * and the like.
20883fdda499SJohn Harres  */
20893fdda499SJohn Harres static int
20909a686fbcSPaul Dagnelie ctd_check_path(char *str)
20919a686fbcSPaul Dagnelie {
20923fdda499SJohn Harres 	/*
20933fdda499SJohn Harres 	 * If it starts with a slash, check the last component.
20943fdda499SJohn Harres 	 */
20953fdda499SJohn Harres 	if (str && str[0] == '/') {
20963fdda499SJohn Harres 		char *tmp = strrchr(str, '/');
20973fdda499SJohn Harres 
20983fdda499SJohn Harres 		/*
20993fdda499SJohn Harres 		 * If it ends in "/old", check the second-to-last
21003fdda499SJohn Harres 		 * component of the string instead.
21013fdda499SJohn Harres 		 */
21023fdda499SJohn Harres 		if (tmp != str && strcmp(tmp, "/old") == 0) {
21033fdda499SJohn Harres 			for (tmp--; *tmp != '/'; tmp--)
21043fdda499SJohn Harres 				;
21053fdda499SJohn Harres 		}
21063fdda499SJohn Harres 		str = tmp + 1;
21073fdda499SJohn Harres 	}
21083fdda499SJohn Harres 	return (CTD_CHECK(str));
21093fdda499SJohn Harres }
21103fdda499SJohn Harres 
2111a43d325bSek /*
2112573ca77eSGeorge Wilson  * Find a vdev that matches the search criteria specified. We use the
2113573ca77eSGeorge Wilson  * the nvpair name to determine how we should look for the device.
2114a43d325bSek  * 'avail_spare' is set to TRUE if the provided guid refers to an AVAIL
2115a43d325bSek  * spare; but FALSE if its an INUSE spare.
2116a43d325bSek  */
211799653d4eSeschrock static nvlist_t *
2118573ca77eSGeorge Wilson vdev_to_nvlist_iter(nvlist_t *nv, nvlist_t *search, boolean_t *avail_spare,
2119573ca77eSGeorge Wilson     boolean_t *l2cache, boolean_t *log)
2120ea8dc4b6Seschrock {
2121ea8dc4b6Seschrock 	uint_t c, children;
2122ea8dc4b6Seschrock 	nvlist_t **child;
212399653d4eSeschrock 	nvlist_t *ret;
2124ee0eb9f2SEric Schrock 	uint64_t is_log;
2125573ca77eSGeorge Wilson 	char *srchkey;
2126573ca77eSGeorge Wilson 	nvpair_t *pair = nvlist_next_nvpair(search, NULL);
2127573ca77eSGeorge Wilson 
2128573ca77eSGeorge Wilson 	/* Nothing to look for */
2129573ca77eSGeorge Wilson 	if (search == NULL || pair == NULL)
2130573ca77eSGeorge Wilson 		return (NULL);
2131ea8dc4b6Seschrock 
2132573ca77eSGeorge Wilson 	/* Obtain the key we will use to search */
2133573ca77eSGeorge Wilson 	srchkey = nvpair_name(pair);
2134573ca77eSGeorge Wilson 
2135573ca77eSGeorge Wilson 	switch (nvpair_type(pair)) {
2136cb04b873SMark J Musante 	case DATA_TYPE_UINT64:
2137573ca77eSGeorge Wilson 		if (strcmp(srchkey, ZPOOL_CONFIG_GUID) == 0) {
2138cb04b873SMark J Musante 			uint64_t srchval, theguid;
2139cb04b873SMark J Musante 
2140cb04b873SMark J Musante 			verify(nvpair_value_uint64(pair, &srchval) == 0);
2141cb04b873SMark J Musante 			verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
2142cb04b873SMark J Musante 			    &theguid) == 0);
2143cb04b873SMark J Musante 			if (theguid == srchval)
2144cb04b873SMark J Musante 				return (nv);
2145573ca77eSGeorge Wilson 		}
2146573ca77eSGeorge Wilson 		break;
2147573ca77eSGeorge Wilson 
2148573ca77eSGeorge Wilson 	case DATA_TYPE_STRING: {
2149573ca77eSGeorge Wilson 		char *srchval, *val;
2150573ca77eSGeorge Wilson 
2151573ca77eSGeorge Wilson 		verify(nvpair_value_string(pair, &srchval) == 0);
2152573ca77eSGeorge Wilson 		if (nvlist_lookup_string(nv, srchkey, &val) != 0)
2153573ca77eSGeorge Wilson 			break;
2154ea8dc4b6Seschrock 
2155ea8dc4b6Seschrock 		/*
21563fdda499SJohn Harres 		 * Search for the requested value. Special cases:
21573fdda499SJohn Harres 		 *
21587855d95bSToomas Soome 		 * - ZPOOL_CONFIG_PATH for whole disk entries. To support
21597855d95bSToomas Soome 		 *   UEFI boot, these end in "s0" or "s0/old" or "s1" or
21607855d95bSToomas Soome 		 *   "s1/old".   The "s0" or "s1" part is hidden from the user,
21613fdda499SJohn Harres 		 *   but included in the string, so this matches around it.
21623fdda499SJohn Harres 		 * - looking for a top-level vdev name (i.e. ZPOOL_CONFIG_TYPE).
21633fdda499SJohn Harres 		 *
216488ecc943SGeorge Wilson 		 * Otherwise, all other searches are simple string compares.
2165ea8dc4b6Seschrock 		 */
21663fdda499SJohn Harres 		if (strcmp(srchkey, ZPOOL_CONFIG_PATH) == 0 &&
21673fdda499SJohn Harres 		    ctd_check_path(val)) {
2168573ca77eSGeorge Wilson 			uint64_t wholedisk = 0;
2169573ca77eSGeorge Wilson 
2170573ca77eSGeorge Wilson 			(void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK,
2171573ca77eSGeorge Wilson 			    &wholedisk);
2172573ca77eSGeorge Wilson 			if (wholedisk) {
21733fdda499SJohn Harres 				int slen = strlen(srchval);
21743fdda499SJohn Harres 				int vlen = strlen(val);
21753fdda499SJohn Harres 
21763fdda499SJohn Harres 				if (slen != vlen - 2)
21773fdda499SJohn Harres 					break;
21783fdda499SJohn Harres 
21793fdda499SJohn Harres 				/*
21803fdda499SJohn Harres 				 * make_leaf_vdev() should only set
21813fdda499SJohn Harres 				 * wholedisk for ZPOOL_CONFIG_PATHs which
21823fdda499SJohn Harres 				 * will include "/dev/dsk/", giving plenty of
21833fdda499SJohn Harres 				 * room for the indices used next.
21843fdda499SJohn Harres 				 */
21853fdda499SJohn Harres 				ASSERT(vlen >= 6);
21863fdda499SJohn Harres 
21873fdda499SJohn Harres 				/*
21883fdda499SJohn Harres 				 * strings identical except trailing "s0"
21893fdda499SJohn Harres 				 */
21907855d95bSToomas Soome 				if ((strcmp(&val[vlen - 2], "s0") == 0 ||
21917855d95bSToomas Soome 				    strcmp(&val[vlen - 2], "s1") == 0) &&
21923fdda499SJohn Harres 				    strncmp(srchval, val, slen) == 0)
21933fdda499SJohn Harres 					return (nv);
21943fdda499SJohn Harres 
2195573ca77eSGeorge Wilson 				/*
21963fdda499SJohn Harres 				 * strings identical except trailing "s0/old"
2197573ca77eSGeorge Wilson 				 */
21987855d95bSToomas Soome 				if ((strcmp(&val[vlen - 6], "s0/old") == 0 ||
21997855d95bSToomas Soome 				    strcmp(&val[vlen - 6], "s1/old") == 0) &&
22003fdda499SJohn Harres 				    strcmp(&srchval[slen - 4], "/old") == 0 &&
22013fdda499SJohn Harres 				    strncmp(srchval, val, slen - 4) == 0)
2202573ca77eSGeorge Wilson 					return (nv);
22033fdda499SJohn Harres 
2204573ca77eSGeorge Wilson 				break;
2205573ca77eSGeorge Wilson 			}
220688ecc943SGeorge Wilson 		} else if (strcmp(srchkey, ZPOOL_CONFIG_TYPE) == 0 && val) {
220788ecc943SGeorge Wilson 			char *type, *idx, *end, *p;
220888ecc943SGeorge Wilson 			uint64_t id, vdev_id;
220988ecc943SGeorge Wilson 
221088ecc943SGeorge Wilson 			/*
221188ecc943SGeorge Wilson 			 * Determine our vdev type, keeping in mind
221288ecc943SGeorge Wilson 			 * that the srchval is composed of a type and
221388ecc943SGeorge Wilson 			 * vdev id pair (i.e. mirror-4).
221488ecc943SGeorge Wilson 			 */
221588ecc943SGeorge Wilson 			if ((type = strdup(srchval)) == NULL)
221688ecc943SGeorge Wilson 				return (NULL);
221788ecc943SGeorge Wilson 
221888ecc943SGeorge Wilson 			if ((p = strrchr(type, '-')) == NULL) {
221988ecc943SGeorge Wilson 				free(type);
222088ecc943SGeorge Wilson 				break;
222188ecc943SGeorge Wilson 			}
222288ecc943SGeorge Wilson 			idx = p + 1;
222388ecc943SGeorge Wilson 			*p = '\0';
222488ecc943SGeorge Wilson 
222588ecc943SGeorge Wilson 			/*
222688ecc943SGeorge Wilson 			 * If the types don't match then keep looking.
222788ecc943SGeorge Wilson 			 */
222888ecc943SGeorge Wilson 			if (strncmp(val, type, strlen(val)) != 0) {
222988ecc943SGeorge Wilson 				free(type);
223088ecc943SGeorge Wilson 				break;
223188ecc943SGeorge Wilson 			}
223288ecc943SGeorge Wilson 
22332ba5f978SAlan Somers 			verify(zpool_vdev_is_interior(type));
223488ecc943SGeorge Wilson 			verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_ID,
223588ecc943SGeorge Wilson 			    &id) == 0);
223688ecc943SGeorge Wilson 
223788ecc943SGeorge Wilson 			errno = 0;
223888ecc943SGeorge Wilson 			vdev_id = strtoull(idx, &end, 10);
223988ecc943SGeorge Wilson 
224088ecc943SGeorge Wilson 			free(type);
224188ecc943SGeorge Wilson 			if (errno != 0)
224288ecc943SGeorge Wilson 				return (NULL);
224388ecc943SGeorge Wilson 
224488ecc943SGeorge Wilson 			/*
224588ecc943SGeorge Wilson 			 * Now verify that we have the correct vdev id.
224688ecc943SGeorge Wilson 			 */
224788ecc943SGeorge Wilson 			if (vdev_id == id)
224888ecc943SGeorge Wilson 				return (nv);
2249ea8dc4b6Seschrock 		}
2250573ca77eSGeorge Wilson 
2251573ca77eSGeorge Wilson 		/*
2252573ca77eSGeorge Wilson 		 * Common case
2253573ca77eSGeorge Wilson 		 */
2254573ca77eSGeorge Wilson 		if (strcmp(srchval, val) == 0)
2255573ca77eSGeorge Wilson 			return (nv);
2256573ca77eSGeorge Wilson 		break;
2257573ca77eSGeorge Wilson 	}
2258573ca77eSGeorge Wilson 
2259573ca77eSGeorge Wilson 	default:
2260573ca77eSGeorge Wilson 		break;
2261ea8dc4b6Seschrock 	}
2262ea8dc4b6Seschrock 
2263ea8dc4b6Seschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
2264ea8dc4b6Seschrock 	    &child, &children) != 0)
226599653d4eSeschrock 		return (NULL);
2266ea8dc4b6Seschrock 
2267ee0eb9f2SEric Schrock 	for (c = 0; c < children; c++) {
2268573ca77eSGeorge Wilson 		if ((ret = vdev_to_nvlist_iter(child[c], search,
2269ee0eb9f2SEric Schrock 		    avail_spare, l2cache, NULL)) != NULL) {
2270ee0eb9f2SEric Schrock 			/*
2271ee0eb9f2SEric Schrock 			 * The 'is_log' value is only set for the toplevel
2272ee0eb9f2SEric Schrock 			 * vdev, not the leaf vdevs.  So we always lookup the
2273ee0eb9f2SEric Schrock 			 * log device from the root of the vdev tree (where
2274ee0eb9f2SEric Schrock 			 * 'log' is non-NULL).
2275ee0eb9f2SEric Schrock 			 */
2276ee0eb9f2SEric Schrock 			if (log != NULL &&
2277ee0eb9f2SEric Schrock 			    nvlist_lookup_uint64(child[c],
2278ee0eb9f2SEric Schrock 			    ZPOOL_CONFIG_IS_LOG, &is_log) == 0 &&
2279ee0eb9f2SEric Schrock 			    is_log) {
2280ee0eb9f2SEric Schrock 				*log = B_TRUE;
2281ee0eb9f2SEric Schrock 			}
2282ea8dc4b6Seschrock 			return (ret);
2283ee0eb9f2SEric Schrock 		}
2284ee0eb9f2SEric Schrock 	}
2285ea8dc4b6Seschrock 
228699653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
228799653d4eSeschrock 	    &child, &children) == 0) {
228899653d4eSeschrock 		for (c = 0; c < children; c++) {
2289573ca77eSGeorge Wilson 			if ((ret = vdev_to_nvlist_iter(child[c], search,
2290ee0eb9f2SEric Schrock 			    avail_spare, l2cache, NULL)) != NULL) {
2291a43d325bSek 				*avail_spare = B_TRUE;
229299653d4eSeschrock 				return (ret);
229399653d4eSeschrock 			}
229499653d4eSeschrock 		}
229599653d4eSeschrock 	}
229699653d4eSeschrock 
2297fa94a07fSbrendan 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
2298fa94a07fSbrendan 	    &child, &children) == 0) {
2299fa94a07fSbrendan 		for (c = 0; c < children; c++) {
2300573ca77eSGeorge Wilson 			if ((ret = vdev_to_nvlist_iter(child[c], search,
2301ee0eb9f2SEric Schrock 			    avail_spare, l2cache, NULL)) != NULL) {
2302fa94a07fSbrendan 				*l2cache = B_TRUE;
2303fa94a07fSbrendan 				return (ret);
2304fa94a07fSbrendan 			}
2305fa94a07fSbrendan 		}
2306fa94a07fSbrendan 	}
2307fa94a07fSbrendan 
230899653d4eSeschrock 	return (NULL);
2309ea8dc4b6Seschrock }
2310ea8dc4b6Seschrock 
2311573ca77eSGeorge Wilson /*
2312573ca77eSGeorge Wilson  * Given a physical path (minus the "/devices" prefix), find the
2313573ca77eSGeorge Wilson  * associated vdev.
2314573ca77eSGeorge Wilson  */
2315573ca77eSGeorge Wilson nvlist_t *
2316573ca77eSGeorge Wilson zpool_find_vdev_by_physpath(zpool_handle_t *zhp, const char *ppath,
2317573ca77eSGeorge Wilson     boolean_t *avail_spare, boolean_t *l2cache, boolean_t *log)
2318573ca77eSGeorge Wilson {
2319573ca77eSGeorge Wilson 	nvlist_t *search, *nvroot, *ret;
2320573ca77eSGeorge Wilson 
2321573ca77eSGeorge Wilson 	verify(nvlist_alloc(&search, NV_UNIQUE_NAME, KM_SLEEP) == 0);
2322573ca77eSGeorge Wilson 	verify(nvlist_add_string(search, ZPOOL_CONFIG_PHYS_PATH, ppath) == 0);
2323573ca77eSGeorge Wilson 
2324573ca77eSGeorge Wilson 	verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE,
2325573ca77eSGeorge Wilson 	    &nvroot) == 0);
2326573ca77eSGeorge Wilson 
2327573ca77eSGeorge Wilson 	*avail_spare = B_FALSE;
2328cb04b873SMark J Musante 	*l2cache = B_FALSE;
2329daeb70e5SMark J Musante 	if (log != NULL)
2330daeb70e5SMark J Musante 		*log = B_FALSE;
2331573ca77eSGeorge Wilson 	ret = vdev_to_nvlist_iter(nvroot, search, avail_spare, l2cache, log);
2332573ca77eSGeorge Wilson 	nvlist_free(search);
2333573ca77eSGeorge Wilson 
2334573ca77eSGeorge Wilson 	return (ret);
2335573ca77eSGeorge Wilson }
2336573ca77eSGeorge Wilson 
233788ecc943SGeorge Wilson /*
233888ecc943SGeorge Wilson  * Determine if we have an "interior" top-level vdev (i.e mirror/raidz).
233988ecc943SGeorge Wilson  */
23402ba5f978SAlan Somers static boolean_t
234188ecc943SGeorge Wilson zpool_vdev_is_interior(const char *name)
234288ecc943SGeorge Wilson {
234388ecc943SGeorge Wilson 	if (strncmp(name, VDEV_TYPE_RAIDZ, strlen(VDEV_TYPE_RAIDZ)) == 0 ||
23442ba5f978SAlan Somers 	    strncmp(name, VDEV_TYPE_SPARE, strlen(VDEV_TYPE_SPARE)) == 0 ||
23452ba5f978SAlan Somers 	    strncmp(name,
23462ba5f978SAlan Somers 	    VDEV_TYPE_REPLACING, strlen(VDEV_TYPE_REPLACING)) == 0 ||
234788ecc943SGeorge Wilson 	    strncmp(name, VDEV_TYPE_MIRROR, strlen(VDEV_TYPE_MIRROR)) == 0)
234888ecc943SGeorge Wilson 		return (B_TRUE);
234988ecc943SGeorge Wilson 	return (B_FALSE);
235088ecc943SGeorge Wilson }
235188ecc943SGeorge Wilson 
235299653d4eSeschrock nvlist_t *
2353fa94a07fSbrendan zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare,
2354ee0eb9f2SEric Schrock     boolean_t *l2cache, boolean_t *log)
2355ea8dc4b6Seschrock {
2356ea8dc4b6Seschrock 	char buf[MAXPATHLEN];
2357ea8dc4b6Seschrock 	char *end;
2358573ca77eSGeorge Wilson 	nvlist_t *nvroot, *search, *ret;
2359ea8dc4b6Seschrock 	uint64_t guid;
2360ea8dc4b6Seschrock 
2361573ca77eSGeorge Wilson 	verify(nvlist_alloc(&search, NV_UNIQUE_NAME, KM_SLEEP) == 0);
2362573ca77eSGeorge Wilson 
23630917b783Seschrock 	guid = strtoull(path, &end, 10);
2364ea8dc4b6Seschrock 	if (guid != 0 && *end == '\0') {
2365573ca77eSGeorge Wilson 		verify(nvlist_add_uint64(search, ZPOOL_CONFIG_GUID, guid) == 0);
236688ecc943SGeorge Wilson 	} else if (zpool_vdev_is_interior(path)) {
236788ecc943SGeorge Wilson 		verify(nvlist_add_string(search, ZPOOL_CONFIG_TYPE, path) == 0);
2368ea8dc4b6Seschrock 	} else if (path[0] != '/') {
23696401734dSWill Andrews 		(void) snprintf(buf, sizeof (buf), "%s/%s", ZFS_DISK_ROOT,
23706401734dSWill Andrews 		    path);
2371573ca77eSGeorge Wilson 		verify(nvlist_add_string(search, ZPOOL_CONFIG_PATH, buf) == 0);
2372ea8dc4b6Seschrock 	} else {
2373573ca77eSGeorge Wilson 		verify(nvlist_add_string(search, ZPOOL_CONFIG_PATH, path) == 0);
2374ea8dc4b6Seschrock 	}
2375ea8dc4b6Seschrock 
2376ea8dc4b6Seschrock 	verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE,
2377ea8dc4b6Seschrock 	    &nvroot) == 0);
2378ea8dc4b6Seschrock 
2379a43d325bSek 	*avail_spare = B_FALSE;
2380fa94a07fSbrendan 	*l2cache = B_FALSE;
2381ee0eb9f2SEric Schrock 	if (log != NULL)
2382ee0eb9f2SEric Schrock 		*log = B_FALSE;
2383573ca77eSGeorge Wilson 	ret = vdev_to_nvlist_iter(nvroot, search, avail_spare, l2cache, log);
2384573ca77eSGeorge Wilson 	nvlist_free(search);
2385573ca77eSGeorge Wilson 
2386573ca77eSGeorge Wilson 	return (ret);
2387a43d325bSek }
2388a43d325bSek 
238919397407SSherry Moore static int
239019397407SSherry Moore vdev_online(nvlist_t *nv)
239119397407SSherry Moore {
239219397407SSherry Moore 	uint64_t ival;
239319397407SSherry Moore 
239419397407SSherry Moore 	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_OFFLINE, &ival) == 0 ||
239519397407SSherry Moore 	    nvlist_lookup_uint64(nv, ZPOOL_CONFIG_FAULTED, &ival) == 0 ||
239619397407SSherry Moore 	    nvlist_lookup_uint64(nv, ZPOOL_CONFIG_REMOVED, &ival) == 0)
239719397407SSherry Moore 		return (0);
239819397407SSherry Moore 
239919397407SSherry Moore 	return (1);
240019397407SSherry Moore }
240119397407SSherry Moore 
240219397407SSherry Moore /*
240321ecdf64SLin Ling  * Helper function for zpool_get_physpaths().
240419397407SSherry Moore  */
2405753a6d45SSherry Moore static int
240621ecdf64SLin Ling vdev_get_one_physpath(nvlist_t *config, char *physpath, size_t physpath_size,
2407753a6d45SSherry Moore     size_t *bytes_written)
240819397407SSherry Moore {
2409753a6d45SSherry Moore 	size_t bytes_left, pos, rsz;
2410753a6d45SSherry Moore 	char *tmppath;
2411753a6d45SSherry Moore 	const char *format;
2412753a6d45SSherry Moore 
2413753a6d45SSherry Moore 	if (nvlist_lookup_string(config, ZPOOL_CONFIG_PHYS_PATH,
2414753a6d45SSherry Moore 	    &tmppath) != 0)
2415753a6d45SSherry Moore 		return (EZFS_NODEVICE);
2416753a6d45SSherry Moore 
2417753a6d45SSherry Moore 	pos = *bytes_written;
2418753a6d45SSherry Moore 	bytes_left = physpath_size - pos;
2419753a6d45SSherry Moore 	format = (pos == 0) ? "%s" : " %s";
2420753a6d45SSherry Moore 
2421753a6d45SSherry Moore 	rsz = snprintf(physpath + pos, bytes_left, format, tmppath);
2422753a6d45SSherry Moore 	*bytes_written += rsz;
2423753a6d45SSherry Moore 
2424753a6d45SSherry Moore 	if (rsz >= bytes_left) {
2425753a6d45SSherry Moore 		/* if physpath was not copied properly, clear it */
2426753a6d45SSherry Moore 		if (bytes_left != 0) {
2427753a6d45SSherry Moore 			physpath[pos] = 0;
2428753a6d45SSherry Moore 		}
2429753a6d45SSherry Moore 		return (EZFS_NOSPC);
2430753a6d45SSherry Moore 	}
2431753a6d45SSherry Moore 	return (0);
2432753a6d45SSherry Moore }
2433753a6d45SSherry Moore 
243421ecdf64SLin Ling static int
243521ecdf64SLin Ling vdev_get_physpaths(nvlist_t *nv, char *physpath, size_t phypath_size,
243621ecdf64SLin Ling     size_t *rsz, boolean_t is_spare)
243721ecdf64SLin Ling {
243821ecdf64SLin Ling 	char *type;
243921ecdf64SLin Ling 	int ret;
244021ecdf64SLin Ling 
244121ecdf64SLin Ling 	if (nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) != 0)
244221ecdf64SLin Ling 		return (EZFS_INVALCONFIG);
244321ecdf64SLin Ling 
244421ecdf64SLin Ling 	if (strcmp(type, VDEV_TYPE_DISK) == 0) {
244521ecdf64SLin Ling 		/*
244621ecdf64SLin Ling 		 * An active spare device has ZPOOL_CONFIG_IS_SPARE set.
244721ecdf64SLin Ling 		 * For a spare vdev, we only want to boot from the active
244821ecdf64SLin Ling 		 * spare device.
244921ecdf64SLin Ling 		 */
245021ecdf64SLin Ling 		if (is_spare) {
245121ecdf64SLin Ling 			uint64_t spare = 0;
245221ecdf64SLin Ling 			(void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_IS_SPARE,
245321ecdf64SLin Ling 			    &spare);
245421ecdf64SLin Ling 			if (!spare)
245521ecdf64SLin Ling 				return (EZFS_INVALCONFIG);
245621ecdf64SLin Ling 		}
245721ecdf64SLin Ling 
245821ecdf64SLin Ling 		if (vdev_online(nv)) {
245921ecdf64SLin Ling 			if ((ret = vdev_get_one_physpath(nv, physpath,
246021ecdf64SLin Ling 			    phypath_size, rsz)) != 0)
246121ecdf64SLin Ling 				return (ret);
246221ecdf64SLin Ling 		}
246321ecdf64SLin Ling 	} else if (strcmp(type, VDEV_TYPE_MIRROR) == 0 ||
2464d5f26ad8SToomas Soome 	    strcmp(type, VDEV_TYPE_RAIDZ) == 0 ||
246521ecdf64SLin Ling 	    strcmp(type, VDEV_TYPE_REPLACING) == 0 ||
246621ecdf64SLin Ling 	    (is_spare = (strcmp(type, VDEV_TYPE_SPARE) == 0))) {
246721ecdf64SLin Ling 		nvlist_t **child;
246821ecdf64SLin Ling 		uint_t count;
246921ecdf64SLin Ling 		int i, ret;
247021ecdf64SLin Ling 
247121ecdf64SLin Ling 		if (nvlist_lookup_nvlist_array(nv,
247221ecdf64SLin Ling 		    ZPOOL_CONFIG_CHILDREN, &child, &count) != 0)
247321ecdf64SLin Ling 			return (EZFS_INVALCONFIG);
247421ecdf64SLin Ling 
247521ecdf64SLin Ling 		for (i = 0; i < count; i++) {
247621ecdf64SLin Ling 			ret = vdev_get_physpaths(child[i], physpath,
247721ecdf64SLin Ling 			    phypath_size, rsz, is_spare);
247821ecdf64SLin Ling 			if (ret == EZFS_NOSPC)
247921ecdf64SLin Ling 				return (ret);
248021ecdf64SLin Ling 		}
248121ecdf64SLin Ling 	}
248221ecdf64SLin Ling 
248321ecdf64SLin Ling 	return (EZFS_POOL_INVALARG);
248421ecdf64SLin Ling }
248521ecdf64SLin Ling 
2486753a6d45SSherry Moore /*
2487753a6d45SSherry Moore  * Get phys_path for a root pool config.
2488753a6d45SSherry Moore  * Return 0 on success; non-zero on failure.
2489753a6d45SSherry Moore  */
2490753a6d45SSherry Moore static int
2491753a6d45SSherry Moore zpool_get_config_physpath(nvlist_t *config, char *physpath, size_t phypath_size)
2492753a6d45SSherry Moore {
2493753a6d45SSherry Moore 	size_t rsz;
249419397407SSherry Moore 	nvlist_t *vdev_root;
249519397407SSherry Moore 	nvlist_t **child;
249619397407SSherry Moore 	uint_t count;
2497753a6d45SSherry Moore 	char *type;
2498753a6d45SSherry Moore 
2499753a6d45SSherry Moore 	rsz = 0;
2500753a6d45SSherry Moore 
2501753a6d45SSherry Moore 	if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
2502753a6d45SSherry Moore 	    &vdev_root) != 0)
2503753a6d45SSherry Moore 		return (EZFS_INVALCONFIG);
2504753a6d45SSherry Moore 
2505753a6d45SSherry Moore 	if (nvlist_lookup_string(vdev_root, ZPOOL_CONFIG_TYPE, &type) != 0 ||
2506753a6d45SSherry Moore 	    nvlist_lookup_nvlist_array(vdev_root, ZPOOL_CONFIG_CHILDREN,
2507753a6d45SSherry Moore 	    &child, &count) != 0)
2508753a6d45SSherry Moore 		return (EZFS_INVALCONFIG);
250919397407SSherry Moore 
251019397407SSherry Moore 	/*
25111a902ef8SHans Rosenfeld 	 * root pool can only have a single top-level vdev.
251219397407SSherry Moore 	 */
25131a902ef8SHans Rosenfeld 	if (strcmp(type, VDEV_TYPE_ROOT) != 0 || count != 1)
2514753a6d45SSherry Moore 		return (EZFS_POOL_INVALARG);
251519397407SSherry Moore 
251621ecdf64SLin Ling 	(void) vdev_get_physpaths(child[0], physpath, phypath_size, &rsz,
251721ecdf64SLin Ling 	    B_FALSE);
251819397407SSherry Moore 
2519753a6d45SSherry Moore 	/* No online devices */
2520753a6d45SSherry Moore 	if (rsz == 0)
2521753a6d45SSherry Moore 		return (EZFS_NODEVICE);
2522753a6d45SSherry Moore 
252319397407SSherry Moore 	return (0);
252419397407SSherry Moore }
252519397407SSherry Moore 
2526753a6d45SSherry Moore /*
2527753a6d45SSherry Moore  * Get phys_path for a root pool
2528753a6d45SSherry Moore  * Return 0 on success; non-zero on failure.
2529753a6d45SSherry Moore  */
2530753a6d45SSherry Moore int
2531753a6d45SSherry Moore zpool_get_physpath(zpool_handle_t *zhp, char *physpath, size_t phypath_size)
2532753a6d45SSherry Moore {
2533753a6d45SSherry Moore 	return (zpool_get_config_physpath(zhp->zpool_config, physpath,
2534753a6d45SSherry Moore 	    phypath_size));
2535753a6d45SSherry Moore }
2536753a6d45SSherry Moore 
2537573ca77eSGeorge Wilson /*
2538573ca77eSGeorge Wilson  * If the device has being dynamically expanded then we need to relabel
2539573ca77eSGeorge Wilson  * the disk to use the new unallocated space.
2540573ca77eSGeorge Wilson  */
2541573ca77eSGeorge Wilson static int
2542573ca77eSGeorge Wilson zpool_relabel_disk(libzfs_handle_t *hdl, const char *name)
2543573ca77eSGeorge Wilson {
2544573ca77eSGeorge Wilson 	char path[MAXPATHLEN];
2545573ca77eSGeorge Wilson 	char errbuf[1024];
2546573ca77eSGeorge Wilson 	int fd, error;
2547573ca77eSGeorge Wilson 	int (*_efi_use_whole_disk)(int);
2548573ca77eSGeorge Wilson 
2549573ca77eSGeorge Wilson 	if ((_efi_use_whole_disk = (int (*)(int))dlsym(RTLD_DEFAULT,
2550573ca77eSGeorge Wilson 	    "efi_use_whole_disk")) == NULL)
2551573ca77eSGeorge Wilson 		return (-1);
2552573ca77eSGeorge Wilson 
25536401734dSWill Andrews 	(void) snprintf(path, sizeof (path), "%s/%s", ZFS_RDISK_ROOT, name);
2554573ca77eSGeorge Wilson 
2555573ca77eSGeorge Wilson 	if ((fd = open(path, O_RDWR | O_NDELAY)) < 0) {
2556573ca77eSGeorge Wilson 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot "
2557573ca77eSGeorge Wilson 		    "relabel '%s': unable to open device"), name);
2558573ca77eSGeorge Wilson 		return (zfs_error(hdl, EZFS_OPENFAILED, errbuf));
2559573ca77eSGeorge Wilson 	}
2560573ca77eSGeorge Wilson 
2561573ca77eSGeorge Wilson 	/*
2562573ca77eSGeorge Wilson 	 * It's possible that we might encounter an error if the device
2563573ca77eSGeorge Wilson 	 * does not have any unallocated space left. If so, we simply
2564573ca77eSGeorge Wilson 	 * ignore that error and continue on.
2565573ca77eSGeorge Wilson 	 */
2566573ca77eSGeorge Wilson 	error = _efi_use_whole_disk(fd);
2567573ca77eSGeorge Wilson 	(void) close(fd);
2568573ca77eSGeorge Wilson 	if (error && error != VT_ENOSPC) {
2569573ca77eSGeorge Wilson 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot "
2570573ca77eSGeorge Wilson 		    "relabel '%s': unable to read disk capacity"), name);
2571573ca77eSGeorge Wilson 		return (zfs_error(hdl, EZFS_NOCAP, errbuf));
2572573ca77eSGeorge Wilson 	}
2573573ca77eSGeorge Wilson 	return (0);
2574573ca77eSGeorge Wilson }
2575573ca77eSGeorge Wilson 
2576fa9e4066Sahrens /*
25773d7072f8Seschrock  * Bring the specified vdev online.   The 'flags' parameter is a set of the
25783d7072f8Seschrock  * ZFS_ONLINE_* flags.
2579fa9e4066Sahrens  */
2580fa9e4066Sahrens int
25813d7072f8Seschrock zpool_vdev_online(zpool_handle_t *zhp, const char *path, int flags,
25823d7072f8Seschrock     vdev_state_t *newstate)
2583fa9e4066Sahrens {
2584fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
2585fa9e4066Sahrens 	char msg[1024];
25869a551dd6SYuri Pankov 	char *pathname;
258799653d4eSeschrock 	nvlist_t *tgt;
2588573ca77eSGeorge Wilson 	boolean_t avail_spare, l2cache, islog;
258999653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
2590fa9e4066Sahrens 
2591573ca77eSGeorge Wilson 	if (flags & ZFS_ONLINE_EXPAND) {
2592573ca77eSGeorge Wilson 		(void) snprintf(msg, sizeof (msg),
2593573ca77eSGeorge Wilson 		    dgettext(TEXT_DOMAIN, "cannot expand %s"), path);
2594573ca77eSGeorge Wilson 	} else {
2595573ca77eSGeorge Wilson 		(void) snprintf(msg, sizeof (msg),
2596573ca77eSGeorge Wilson 		    dgettext(TEXT_DOMAIN, "cannot online %s"), path);
2597573ca77eSGeorge Wilson 	}
2598ea8dc4b6Seschrock 
2599fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
2600ee0eb9f2SEric Schrock 	if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache,
2601573ca77eSGeorge Wilson 	    &islog)) == NULL)
260299653d4eSeschrock 		return (zfs_error(hdl, EZFS_NODEVICE, msg));
2603fa9e4066Sahrens 
260499653d4eSeschrock 	verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
2605fa9e4066Sahrens 
2606069f55e2SEric Schrock 	if (avail_spare)
2607a43d325bSek 		return (zfs_error(hdl, EZFS_ISSPARE, msg));
2608a43d325bSek 
26099a551dd6SYuri Pankov 	if ((flags & ZFS_ONLINE_EXPAND ||
26109a551dd6SYuri Pankov 	    zpool_get_prop_int(zhp, ZPOOL_PROP_AUTOEXPAND, NULL)) &&
26119a551dd6SYuri Pankov 	    nvlist_lookup_string(tgt, ZPOOL_CONFIG_PATH, &pathname) == 0) {
2612573ca77eSGeorge Wilson 		uint64_t wholedisk = 0;
2613573ca77eSGeorge Wilson 
2614573ca77eSGeorge Wilson 		(void) nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_WHOLE_DISK,
2615573ca77eSGeorge Wilson 		    &wholedisk);
2616573ca77eSGeorge Wilson 
2617573ca77eSGeorge Wilson 		/*
2618573ca77eSGeorge Wilson 		 * XXX - L2ARC 1.0 devices can't support expansion.
2619573ca77eSGeorge Wilson 		 */
2620573ca77eSGeorge Wilson 		if (l2cache) {
2621573ca77eSGeorge Wilson 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2622573ca77eSGeorge Wilson 			    "cannot expand cache devices"));
2623573ca77eSGeorge Wilson 			return (zfs_error(hdl, EZFS_VDEVNOTSUP, msg));
2624573ca77eSGeorge Wilson 		}
2625573ca77eSGeorge Wilson 
2626573ca77eSGeorge Wilson 		if (wholedisk) {
26276401734dSWill Andrews 			pathname += strlen(ZFS_DISK_ROOT) + 1;
2628cb04b873SMark J Musante 			(void) zpool_relabel_disk(hdl, pathname);
2629573ca77eSGeorge Wilson 		}
2630573ca77eSGeorge Wilson 	}
2631573ca77eSGeorge Wilson 
26323d7072f8Seschrock 	zc.zc_cookie = VDEV_STATE_ONLINE;
26333d7072f8Seschrock 	zc.zc_obj = flags;
2634fa9e4066Sahrens 
2635cb04b873SMark J Musante 	if (zfs_ioctl(hdl, ZFS_IOC_VDEV_SET_STATE, &zc) != 0) {
26361195e687SMark J Musante 		if (errno == EINVAL) {
26371195e687SMark J Musante 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "was split "
26381195e687SMark J Musante 			    "from this pool into a new one.  Use '%s' "
26391195e687SMark J Musante 			    "instead"), "zpool detach");
26401195e687SMark J Musante 			return (zfs_error(hdl, EZFS_POSTSPLIT_ONLINE, msg));
26411195e687SMark J Musante 		}
26423d7072f8Seschrock 		return (zpool_standard_error(hdl, errno, msg));
26431195e687SMark J Musante 	}
26443d7072f8Seschrock 
26453d7072f8Seschrock 	*newstate = zc.zc_cookie;
26463d7072f8Seschrock 	return (0);
2647fa9e4066Sahrens }
2648fa9e4066Sahrens 
2649fa9e4066Sahrens /*
2650fa9e4066Sahrens  * Take the specified vdev offline
2651fa9e4066Sahrens  */
2652fa9e4066Sahrens int
26533d7072f8Seschrock zpool_vdev_offline(zpool_handle_t *zhp, const char *path, boolean_t istmp)
2654fa9e4066Sahrens {
2655fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
2656fa9e4066Sahrens 	char msg[1024];
265799653d4eSeschrock 	nvlist_t *tgt;
2658fa94a07fSbrendan 	boolean_t avail_spare, l2cache;
265999653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
2660fa9e4066Sahrens 
2661ea8dc4b6Seschrock 	(void) snprintf(msg, sizeof (msg),
2662ea8dc4b6Seschrock 	    dgettext(TEXT_DOMAIN, "cannot offline %s"), path);
2663ea8dc4b6Seschrock 
2664fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
2665ee0eb9f2SEric Schrock 	if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache,
2666ee0eb9f2SEric Schrock 	    NULL)) == NULL)
266799653d4eSeschrock 		return (zfs_error(hdl, EZFS_NODEVICE, msg));
266899653d4eSeschrock 
266999653d4eSeschrock 	verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
2670fa9e4066Sahrens 
2671069f55e2SEric Schrock 	if (avail_spare)
2672a43d325bSek 		return (zfs_error(hdl, EZFS_ISSPARE, msg));
2673a43d325bSek 
26743d7072f8Seschrock 	zc.zc_cookie = VDEV_STATE_OFFLINE;
26753d7072f8Seschrock 	zc.zc_obj = istmp ? ZFS_OFFLINE_TEMPORARY : 0;
26763d7072f8Seschrock 
2677cb04b873SMark J Musante 	if (zfs_ioctl(hdl, ZFS_IOC_VDEV_SET_STATE, &zc) == 0)
26783d7072f8Seschrock 		return (0);
26793d7072f8Seschrock 
26803d7072f8Seschrock 	switch (errno) {
26813d7072f8Seschrock 	case EBUSY:
26823d7072f8Seschrock 
26833d7072f8Seschrock 		/*
26843d7072f8Seschrock 		 * There are no other replicas of this device.
26853d7072f8Seschrock 		 */
26863d7072f8Seschrock 		return (zfs_error(hdl, EZFS_NOREPLICAS, msg));
26873d7072f8Seschrock 
2688e6ca193dSGeorge Wilson 	case EEXIST:
2689e6ca193dSGeorge Wilson 		/*
2690e6ca193dSGeorge Wilson 		 * The log device has unplayed logs
2691e6ca193dSGeorge Wilson 		 */
2692e6ca193dSGeorge Wilson 		return (zfs_error(hdl, EZFS_UNPLAYED_LOGS, msg));
2693e6ca193dSGeorge Wilson 
26943d7072f8Seschrock 	default:
26953d7072f8Seschrock 		return (zpool_standard_error(hdl, errno, msg));
26963d7072f8Seschrock 	}
26973d7072f8Seschrock }
26983d7072f8Seschrock 
26993d7072f8Seschrock /*
27003d7072f8Seschrock  * Mark the given vdev faulted.
27013d7072f8Seschrock  */
27023d7072f8Seschrock int
2703069f55e2SEric Schrock zpool_vdev_fault(zpool_handle_t *zhp, uint64_t guid, vdev_aux_t aux)
27043d7072f8Seschrock {
27053d7072f8Seschrock 	zfs_cmd_t zc = { 0 };
27063d7072f8Seschrock 	char msg[1024];
27073d7072f8Seschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
27083d7072f8Seschrock 
27093d7072f8Seschrock 	(void) snprintf(msg, sizeof (msg),
27103d7072f8Seschrock 	    dgettext(TEXT_DOMAIN, "cannot fault %llu"), guid);
2711441d80aaSlling 
27123d7072f8Seschrock 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
27133d7072f8Seschrock 	zc.zc_guid = guid;
27143d7072f8Seschrock 	zc.zc_cookie = VDEV_STATE_FAULTED;
2715069f55e2SEric Schrock 	zc.zc_obj = aux;
27163d7072f8Seschrock 
2717cb04b873SMark J Musante 	if (ioctl(hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0)
2718fa9e4066Sahrens 		return (0);
2719fa9e4066Sahrens 
2720fa9e4066Sahrens 	switch (errno) {
272199653d4eSeschrock 	case EBUSY:
2722fa9e4066Sahrens 
2723fa9e4066Sahrens 		/*
2724fa9e4066Sahrens 		 * There are no other replicas of this device.
2725fa9e4066Sahrens 		 */
272699653d4eSeschrock 		return (zfs_error(hdl, EZFS_NOREPLICAS, msg));
2727fa9e4066Sahrens 
272899653d4eSeschrock 	default:
272999653d4eSeschrock 		return (zpool_standard_error(hdl, errno, msg));
2730fa9e4066Sahrens 	}
27313d7072f8Seschrock 
27323d7072f8Seschrock }
27333d7072f8Seschrock 
27343d7072f8Seschrock /*
27353d7072f8Seschrock  * Mark the given vdev degraded.
27363d7072f8Seschrock  */
27373d7072f8Seschrock int
2738069f55e2SEric Schrock zpool_vdev_degrade(zpool_handle_t *zhp, uint64_t guid, vdev_aux_t aux)
27393d7072f8Seschrock {
27403d7072f8Seschrock 	zfs_cmd_t zc = { 0 };
27413d7072f8Seschrock 	char msg[1024];
27423d7072f8Seschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
27433d7072f8Seschrock 
27443d7072f8Seschrock 	(void) snprintf(msg, sizeof (msg),
27453d7072f8Seschrock 	    dgettext(TEXT_DOMAIN, "cannot degrade %llu"), guid);
27463d7072f8Seschrock 
27473d7072f8Seschrock 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
27483d7072f8Seschrock 	zc.zc_guid = guid;
27493d7072f8Seschrock 	zc.zc_cookie = VDEV_STATE_DEGRADED;
2750069f55e2SEric Schrock 	zc.zc_obj = aux;
27513d7072f8Seschrock 
2752cb04b873SMark J Musante 	if (ioctl(hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0)
27533d7072f8Seschrock 		return (0);
27543d7072f8Seschrock 
27553d7072f8Seschrock 	return (zpool_standard_error(hdl, errno, msg));
275699653d4eSeschrock }
275799653d4eSeschrock 
275899653d4eSeschrock /*
275999653d4eSeschrock  * Returns TRUE if the given nvlist is a vdev that was originally swapped in as
276099653d4eSeschrock  * a hot spare.
276199653d4eSeschrock  */
276299653d4eSeschrock static boolean_t
276399653d4eSeschrock is_replacing_spare(nvlist_t *search, nvlist_t *tgt, int which)
276499653d4eSeschrock {
276599653d4eSeschrock 	nvlist_t **child;
276699653d4eSeschrock 	uint_t c, children;
276799653d4eSeschrock 	char *type;
276899653d4eSeschrock 
276999653d4eSeschrock 	if (nvlist_lookup_nvlist_array(search, ZPOOL_CONFIG_CHILDREN, &child,
277099653d4eSeschrock 	    &children) == 0) {
277199653d4eSeschrock 		verify(nvlist_lookup_string(search, ZPOOL_CONFIG_TYPE,
277299653d4eSeschrock 		    &type) == 0);
277399653d4eSeschrock 
277499653d4eSeschrock 		if (strcmp(type, VDEV_TYPE_SPARE) == 0 &&
277599653d4eSeschrock 		    children == 2 && child[which] == tgt)
277699653d4eSeschrock 			return (B_TRUE);
277799653d4eSeschrock 
277899653d4eSeschrock 		for (c = 0; c < children; c++)
277999653d4eSeschrock 			if (is_replacing_spare(child[c], tgt, which))
278099653d4eSeschrock 				return (B_TRUE);
278199653d4eSeschrock 	}
278299653d4eSeschrock 
278399653d4eSeschrock 	return (B_FALSE);
2784fa9e4066Sahrens }
2785fa9e4066Sahrens 
2786fa9e4066Sahrens /*
2787fa9e4066Sahrens  * Attach new_disk (fully described by nvroot) to old_disk.
27888654d025Sperrin  * If 'replacing' is specified, the new disk will replace the old one.
2789fa9e4066Sahrens  */
2790fa9e4066Sahrens int
2791fa9e4066Sahrens zpool_vdev_attach(zpool_handle_t *zhp,
2792fa9e4066Sahrens     const char *old_disk, const char *new_disk, nvlist_t *nvroot, int replacing)
2793fa9e4066Sahrens {
2794fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
2795fa9e4066Sahrens 	char msg[1024];
2796fa9e4066Sahrens 	int ret;
279799653d4eSeschrock 	nvlist_t *tgt;
2798ee0eb9f2SEric Schrock 	boolean_t avail_spare, l2cache, islog;
2799ee0eb9f2SEric Schrock 	uint64_t val;
2800cb04b873SMark J Musante 	char *newname;
280199653d4eSeschrock 	nvlist_t **child;
280299653d4eSeschrock 	uint_t children;
280399653d4eSeschrock 	nvlist_t *config_root;
280499653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
28054263d13fSGeorge Wilson 	boolean_t rootpool = zpool_is_bootable(zhp);
2806fa9e4066Sahrens 
2807ea8dc4b6Seschrock 	if (replacing)
2808ea8dc4b6Seschrock 		(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
2809ea8dc4b6Seschrock 		    "cannot replace %s with %s"), old_disk, new_disk);
2810ea8dc4b6Seschrock 	else
2811ea8dc4b6Seschrock 		(void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
2812ea8dc4b6Seschrock 		    "cannot attach %s to %s"), new_disk, old_disk);
2813ea8dc4b6Seschrock 
2814fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
2815ee0eb9f2SEric Schrock 	if ((tgt = zpool_find_vdev(zhp, old_disk, &avail_spare, &l2cache,
28165cabbc6bSPrashanth Sreenivasa 	    &islog)) == NULL)
281799653d4eSeschrock 		return (zfs_error(hdl, EZFS_NODEVICE, msg));
281899653d4eSeschrock 
2819a43d325bSek 	if (avail_spare)
282099653d4eSeschrock 		return (zfs_error(hdl, EZFS_ISSPARE, msg));
282199653d4eSeschrock 
2822fa94a07fSbrendan 	if (l2cache)
2823fa94a07fSbrendan 		return (zfs_error(hdl, EZFS_ISL2CACHE, msg));
2824fa94a07fSbrendan 
282599653d4eSeschrock 	verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
2826fa9e4066Sahrens 	zc.zc_cookie = replacing;
2827fa9e4066Sahrens 
282899653d4eSeschrock 	if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
282999653d4eSeschrock 	    &child, &children) != 0 || children != 1) {
283099653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
283199653d4eSeschrock 		    "new device must be a single disk"));
283299653d4eSeschrock 		return (zfs_error(hdl, EZFS_INVALCONFIG, msg));
283399653d4eSeschrock 	}
283499653d4eSeschrock 
283599653d4eSeschrock 	verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL),
283699653d4eSeschrock 	    ZPOOL_CONFIG_VDEV_TREE, &config_root) == 0);
283799653d4eSeschrock 
283888ecc943SGeorge Wilson 	if ((newname = zpool_vdev_name(NULL, NULL, child[0], B_FALSE)) == NULL)
28390430f8daSeschrock 		return (-1);
28400430f8daSeschrock 
284199653d4eSeschrock 	/*
284299653d4eSeschrock 	 * If the target is a hot spare that has been swapped in, we can only
284399653d4eSeschrock 	 * replace it with another hot spare.
284499653d4eSeschrock 	 */
284599653d4eSeschrock 	if (replacing &&
284699653d4eSeschrock 	    nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_IS_SPARE, &val) == 0 &&
2847ee0eb9f2SEric Schrock 	    (zpool_find_vdev(zhp, newname, &avail_spare, &l2cache,
2848ee0eb9f2SEric Schrock 	    NULL) == NULL || !avail_spare) &&
2849ee0eb9f2SEric Schrock 	    is_replacing_spare(config_root, tgt, 1)) {
285099653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
285199653d4eSeschrock 		    "can only be replaced by another hot spare"));
28520430f8daSeschrock 		free(newname);
285399653d4eSeschrock 		return (zfs_error(hdl, EZFS_BADTARGET, msg));
285499653d4eSeschrock 	}
285599653d4eSeschrock 
28560430f8daSeschrock 	free(newname);
28570430f8daSeschrock 
2858990b4856Slling 	if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0)
285999653d4eSeschrock 		return (-1);
2860fa9e4066Sahrens 
2861cb04b873SMark J Musante 	ret = zfs_ioctl(hdl, ZFS_IOC_VDEV_ATTACH, &zc);
2862fa9e4066Sahrens 
2863e9dbad6fSeschrock 	zcmd_free_nvlists(&zc);
2864fa9e4066Sahrens 
2865b5b76fecSGeorge Wilson 	if (ret == 0) {
2866b5b76fecSGeorge Wilson 		if (rootpool) {
286721ecdf64SLin Ling 			/*
286821ecdf64SLin Ling 			 * XXX need a better way to prevent user from
286921ecdf64SLin Ling 			 * booting up a half-baked vdev.
287021ecdf64SLin Ling 			 */
287121ecdf64SLin Ling 			(void) fprintf(stderr, dgettext(TEXT_DOMAIN, "Make "
287221ecdf64SLin Ling 			    "sure to wait until resilver is done "
287321ecdf64SLin Ling 			    "before rebooting.\n"));
2874b5b76fecSGeorge Wilson 		}
2875fa9e4066Sahrens 		return (0);
2876b5b76fecSGeorge Wilson 	}
2877fa9e4066Sahrens 
2878fa9e4066Sahrens 	switch (errno) {
2879ea8dc4b6Seschrock 	case ENOTSUP:
2880fa9e4066Sahrens 		/*
2881fa9e4066Sahrens 		 * Can't attach to or replace this type of vdev.
2882fa9e4066Sahrens 		 */
28838654d025Sperrin 		if (replacing) {
2884cb04b873SMark J Musante 			uint64_t version = zpool_get_prop_int(zhp,
2885cb04b873SMark J Musante 			    ZPOOL_PROP_VERSION, NULL);
2886cb04b873SMark J Musante 
2887ee0eb9f2SEric Schrock 			if (islog)
28888654d025Sperrin 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
28898654d025Sperrin 				    "cannot replace a log with a spare"));
2890cb04b873SMark J Musante 			else if (version >= SPA_VERSION_MULTI_REPLACE)
2891cb04b873SMark J Musante 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2892cb04b873SMark J Musante 				    "already in replacing/spare config; wait "
2893cb04b873SMark J Musante 				    "for completion or use 'zpool detach'"));
28948654d025Sperrin 			else
28958654d025Sperrin 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
28968654d025Sperrin 				    "cannot replace a replacing device"));
28978654d025Sperrin 		} else {
289899653d4eSeschrock 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
289999653d4eSeschrock 			    "can only attach to mirrors and top-level "
290099653d4eSeschrock 			    "disks"));
29018654d025Sperrin 		}
290299653d4eSeschrock 		(void) zfs_error(hdl, EZFS_BADTARGET, msg);
2903fa9e4066Sahrens 		break;
2904fa9e4066Sahrens 
2905ea8dc4b6Seschrock 	case EINVAL:
2906fa9e4066Sahrens 		/*
2907fa9e4066Sahrens 		 * The new device must be a single disk.
2908fa9e4066Sahrens 		 */
290999653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
291099653d4eSeschrock 		    "new device must be a single disk"));
291199653d4eSeschrock 		(void) zfs_error(hdl, EZFS_INVALCONFIG, msg);
2912fa9e4066Sahrens 		break;
2913fa9e4066Sahrens 
2914ea8dc4b6Seschrock 	case EBUSY:
29155cabbc6bSPrashanth Sreenivasa 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "%s is busy, "
29163a4b1be9SMatthew Ahrens 		    "or device removal is in progress"),
291799653d4eSeschrock 		    new_disk);
291899653d4eSeschrock 		(void) zfs_error(hdl, EZFS_BADDEV, msg);
2919fa9e4066Sahrens 		break;
2920fa9e4066Sahrens 
2921ea8dc4b6Seschrock 	case EOVERFLOW:
2922fa9e4066Sahrens 		/*
2923fa9e4066Sahrens 		 * The new device is too small.
2924fa9e4066Sahrens 		 */
292599653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
292699653d4eSeschrock 		    "device is too small"));
292799653d4eSeschrock 		(void) zfs_error(hdl, EZFS_BADDEV, msg);
2928fa9e4066Sahrens 		break;
2929fa9e4066Sahrens 
2930ea8dc4b6Seschrock 	case EDOM:
2931fa9e4066Sahrens 		/*
2932fa9e4066Sahrens 		 * The new device has a different alignment requirement.
2933fa9e4066Sahrens 		 */
293499653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
293599653d4eSeschrock 		    "devices have different sector alignment"));
293699653d4eSeschrock 		(void) zfs_error(hdl, EZFS_BADDEV, msg);
2937fa9e4066Sahrens 		break;
2938fa9e4066Sahrens 
2939ea8dc4b6Seschrock 	case ENAMETOOLONG:
2940fa9e4066Sahrens 		/*
2941fa9e4066Sahrens 		 * The resulting top-level vdev spec won't fit in the label.
2942fa9e4066Sahrens 		 */
294399653d4eSeschrock 		(void) zfs_error(hdl, EZFS_DEVOVERFLOW, msg);
2944fa9e4066Sahrens 		break;
2945fa9e4066Sahrens 
2946ea8dc4b6Seschrock 	default:
294799653d4eSeschrock 		(void) zpool_standard_error(hdl, errno, msg);
2948fa9e4066Sahrens 	}
2949fa9e4066Sahrens 
295099653d4eSeschrock 	return (-1);
2951fa9e4066Sahrens }
2952fa9e4066Sahrens 
2953fa9e4066Sahrens /*
2954fa9e4066Sahrens  * Detach the specified device.
2955fa9e4066Sahrens  */
2956fa9e4066Sahrens int
2957fa9e4066Sahrens zpool_vdev_detach(zpool_handle_t *zhp, const char *path)
2958fa9e4066Sahrens {
2959fa9e4066Sahrens 	zfs_cmd_t zc = { 0 };
2960fa9e4066Sahrens 	char msg[1024];
296199653d4eSeschrock 	nvlist_t *tgt;
2962fa94a07fSbrendan 	boolean_t avail_spare, l2cache;
296399653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
2964fa9e4066Sahrens 
2965ea8dc4b6Seschrock 	(void) snprintf(msg, sizeof (msg),
2966ea8dc4b6Seschrock 	    dgettext(TEXT_DOMAIN, "cannot detach %s"), path);
2967ea8dc4b6Seschrock 
2968fa9e4066Sahrens 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
2969ee0eb9f2SEric Schrock 	if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache,
29705cabbc6bSPrashanth Sreenivasa 	    NULL)) == NULL)
297199653d4eSeschrock 		return (zfs_error(hdl, EZFS_NODEVICE, msg));
2972fa9e4066Sahrens 
2973a43d325bSek 	if (avail_spare)
297499653d4eSeschrock 		return (zfs_error(hdl, EZFS_ISSPARE, msg));
297599653d4eSeschrock 
2976fa94a07fSbrendan 	if (l2cache)
2977fa94a07fSbrendan 		return (zfs_error(hdl, EZFS_ISL2CACHE, msg));
2978fa94a07fSbrendan 
297999653d4eSeschrock 	verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
298099653d4eSeschrock 
2981ecd6cf80Smarks 	if (zfs_ioctl(hdl, ZFS_IOC_VDEV_DETACH, &zc) == 0)
2982fa9e4066Sahrens 		return (0);
2983fa9e4066Sahrens 
2984fa9e4066Sahrens 	switch (errno) {
2985fa9e4066Sahrens 
2986ea8dc4b6Seschrock 	case ENOTSUP:
2987fa9e4066Sahrens 		/*
2988fa9e4066Sahrens 		 * Can't detach from this type of vdev.
2989fa9e4066Sahrens 		 */
299099653d4eSeschrock 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "only "
299199653d4eSeschrock 		    "applicable to mirror and replacing vdevs"));
2992cb04b873SMark J Musante 		(void) zfs_error(hdl, EZFS_BADTARGET, msg);
2993fa9e4066Sahrens 		break;
2994fa9e4066Sahrens 
2995ea8dc4b6Seschrock 	case EBUSY:
2996fa9e4066Sahrens 		/*
2997fa9e4066Sahrens 		 * There are no other replicas of this device.
2998fa9e4066Sahrens 		 */
299999653d4eSeschrock 		(void) zfs_error(hdl, EZFS_NOREPLICAS, msg);
3000fa9e4066Sahrens 		break;
3001fa9e4066Sahrens 
3002ea8dc4b6Seschrock 	default:
300399653d4eSeschrock 		(void) zpool_standard_error(hdl, errno, msg);
3004ea8dc4b6Seschrock 	}
3005ea8dc4b6Seschrock 
300699653d4eSeschrock 	return (-1);
300799653d4eSeschrock }
300899653d4eSeschrock 
30091195e687SMark J Musante /*
30101195e687SMark J Musante  * Find a mirror vdev in the source nvlist.
30111195e687SMark J Musante  *
30121195e687SMark J Musante  * The mchild array contains a list of disks in one of the top-level mirrors
30131195e687SMark J Musante  * of the source pool.  The schild array contains a list of disks that the
30141195e687SMark J Musante  * user specified on the command line.  We loop over the mchild array to
30151195e687SMark J Musante  * see if any entry in the schild array matches.
30161195e687SMark J Musante  *
30171195e687SMark J Musante  * If a disk in the mchild array is found in the schild array, we return
30181195e687SMark J Musante  * the index of that entry.  Otherwise we return -1.
30191195e687SMark J Musante  */
30201195e687SMark J Musante static int
30211195e687SMark J Musante find_vdev_entry(zpool_handle_t *zhp, nvlist_t **mchild, uint_t mchildren,
30221195e687SMark J Musante     nvlist_t **schild, uint_t schildren)
30231195e687SMark J Musante {
30241195e687SMark J Musante 	uint_t mc;
30251195e687SMark J Musante 
30261195e687SMark J Musante 	for (mc = 0; mc < mchildren; mc++) {
30271195e687SMark J Musante 		uint_t sc;
30281195e687SMark J Musante 		char *mpath = zpool_vdev_name(zhp->zpool_hdl, zhp,
30291195e687SMark J Musante 		    mchild[mc], B_FALSE);
30301195e687SMark J Musante 
30311195e687SMark J Musante 		for (sc = 0; sc < schildren; sc++) {
30321195e687SMark J Musante 			char *spath = zpool_vdev_name(zhp->zpool_hdl, zhp,
30331195e687SMark J Musante 			    schild[sc], B_FALSE);
30341195e687SMark J Musante 			boolean_t result = (strcmp(mpath, spath) == 0);
30351195e687SMark J Musante 
30361195e687SMark J Musante 			free(spath);
30371195e687SMark J Musante 			if (result) {
30381195e687SMark J Musante 				free(mpath);
30391195e687SMark J Musante 				return (mc);
30401195e687SMark J Musante 			}
30411195e687SMark J Musante 		}
30421195e687SMark J Musante 
30431195e687SMark J Musante 		free(mpath);
30441195e687SMark J Musante 	}
30451195e687SMark J Musante 
30461195e687SMark J Musante 	return (-1);
30471195e687SMark J Musante }
30481195e687SMark J Musante 
30491195e687SMark J Musante /*
30501195e687SMark J Musante  * Split a mirror pool.  If newroot points to null, then a new nvlist
30511195e687SMark J Musante  * is generated and it is the responsibility of the caller to free it.
30521195e687SMark J Musante  */
30531195e687SMark J Musante int
30541195e687SMark J Musante zpool_vdev_split(zpool_handle_t *zhp, char *newname, nvlist_t **newroot,
30551195e687SMark J Musante     nvlist_t *props, splitflags_t flags)
30561195e687SMark J Musante {
30571195e687SMark J Musante 	zfs_cmd_t zc = { 0 };
30581195e687SMark J Musante 	char msg[1024];
30591195e687SMark J Musante 	nvlist_t *tree, *config, **child, **newchild, *newconfig = NULL;
30601195e687SMark J Musante 	nvlist_t **varray = NULL, *zc_props = NULL;
30611195e687SMark J Musante 	uint_t c, children, newchildren, lastlog = 0, vcount, found = 0;
30621195e687SMark J Musante 	libzfs_handle_t *hdl = zhp->zpool_hdl;
30631195e687SMark J Musante 	uint64_t vers;
30641195e687SMark J Musante 	boolean_t freelist = B_FALSE, memory_err = B_TRUE;
30651195e687SMark J Musante 	int retval = 0;
30661195e687SMark J Musante 
30671195e687SMark J Musante 	(void) snprintf(msg, sizeof (msg),
30681195e687SMark J Musante 	    dgettext(TEXT_DOMAIN, "Unable to split %s"), zhp->zpool_name);
30691195e687SMark J Musante 
30701195e687SMark J Musante 	if (!zpool_name_valid(hdl, B_FALSE, newname))
30711195e687SMark J Musante 		return (zfs_error(hdl, EZFS_INVALIDNAME, msg));
30721195e687SMark J Musante 
30731195e687SMark J Musante 	if ((config = zpool_get_config(zhp, NULL)) == NULL) {
30741195e687SMark J Musante 		(void) fprintf(stderr, gettext("Internal error: unable to "
30751195e687SMark J Musante 		    "retrieve pool configuration\n"));
30761195e687SMark J Musante 		return (-1);
30771195e687SMark J Musante 	}
30781195e687SMark J Musante 
30791195e687SMark J Musante 	verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &tree)
30801195e687SMark J Musante 	    == 0);
30811195e687SMark J Musante 	verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, &vers) == 0);
30821195e687SMark J Musante 
30831195e687SMark J Musante 	if (props) {
3084f9af39baSGeorge Wilson 		prop_flags_t flags = { .create = B_FALSE, .import = B_TRUE };
30851195e687SMark J Musante 		if ((zc_props = zpool_valid_proplist(hdl, zhp->zpool_name,
3086f9af39baSGeorge Wilson 		    props, vers, flags, msg)) == NULL)
30871195e687SMark J Musante 			return (-1);
30881195e687SMark J Musante 	}
30891195e687SMark J Musante 
30901195e687SMark J Musante 	if (nvlist_lookup_nvlist_array(tree, ZPOOL_CONFIG_CHILDREN, &child,
30911195e687SMark J Musante 	    &children) != 0) {
30921195e687SMark J Musante 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
30931195e687SMark J Musante 		    "Source pool is missing vdev tree"));
3094aab83bb8SJosef 'Jeff' Sipek 		nvlist_free(zc_props);
30951195e687SMark J Musante 		return (-1);
30961195e687SMark J Musante 	}
30971195e687SMark J Musante 
30981195e687SMark J Musante 	varray = zfs_alloc(hdl, children * sizeof (nvlist_t *));
30991195e687SMark J Musante 	vcount = 0;
31001195e687SMark J Musante 
31011195e687SMark J Musante 	if (*newroot == NULL ||
31021195e687SMark J Musante 	    nvlist_lookup_nvlist_array(*newroot, ZPOOL_CONFIG_CHILDREN,
31031195e687SMark J Musante 	    &newchild, &newchildren) != 0)
31041195e687SMark J Musante 		newchildren = 0;
31051195e687SMark J Musante 
31061195e687SMark J Musante 	for (c = 0; c < children; c++) {
31071195e687SMark J Musante 		uint64_t is_log = B_FALSE, is_hole = B_FALSE;
31081195e687SMark J Musante 		char *type;
31091195e687SMark J Musante 		nvlist_t **mchild, *vdev;
31101195e687SMark J Musante 		uint_t mchildren;
31111195e687SMark J Musante 		int entry;
31121195e687SMark J Musante 
31131195e687SMark J Musante 		/*
31141195e687SMark J Musante 		 * Unlike cache & spares, slogs are stored in the
31151195e687SMark J Musante 		 * ZPOOL_CONFIG_CHILDREN array.  We filter them out here.
31161195e687SMark J Musante 		 */
31171195e687SMark J Musante 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
31181195e687SMark J Musante 		    &is_log);
31191195e687SMark J Musante 		(void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_HOLE,
31201195e687SMark J Musante 		    &is_hole);
31211195e687SMark J Musante 		if (is_log || is_hole) {
31221195e687SMark J Musante 			/*
31231195e687SMark J Musante 			 * Create a hole vdev and put it in the config.
31241195e687SMark J Musante 			 */
31251195e687SMark J Musante 			if (nvlist_alloc(&vdev, NV_UNIQUE_NAME, 0) != 0)
31261195e687SMark J Musante 				goto out;
31271195e687SMark J Musante 			if (nvlist_add_string(vdev, ZPOOL_CONFIG_TYPE,
31281195e687SMark J Musante 			    VDEV_TYPE_HOLE) != 0)
31291195e687SMark J Musante 				goto out;
31301195e687SMark J Musante 			if (nvlist_add_uint64(vdev, ZPOOL_CONFIG_IS_HOLE,
31311195e687SMark J Musante 			    1) != 0)
31321195e687SMark J Musante 				goto out;
31331195e687SMark J Musante 			if (lastlog == 0)
31341195e687SMark J Musante 				lastlog = vcount;
31351195e687SMark J Musante 			varray[vcount++] = vdev;
31361195e687SMark J Musante 			continue;
31371195e687SMark J Musante 		}
31381195e687SMark J Musante 		lastlog = 0;
31391195e687SMark J Musante 		verify(nvlist_lookup_string(child[c], ZPOOL_CONFIG_TYPE, &type)
31401195e687SMark J Musante 		    == 0);
31411195e687SMark J Musante 		if (strcmp(type, VDEV_TYPE_MIRROR) != 0) {
31421195e687SMark J Musante 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
31431195e687SMark J Musante 			    "Source pool must be composed only of mirrors\n"));
31441195e687SMark J Musante 			retval = zfs_error(hdl, EZFS_INVALCONFIG, msg);
31451195e687SMark J Musante 			goto out;
31461195e687SMark J Musante 		}
31471195e687SMark J Musante 
31481195e687SMark J Musante 		verify(nvlist_lookup_nvlist_array(child[c],
31491195e687SMark J Musante 		    ZPOOL_CONFIG_CHILDREN, &mchild, &mchildren) == 0);
31501195e687SMark J Musante 
31511195e687SMark J Musante 		/* find or add an entry for this top-level vdev */
31521195e687SMark J Musante 		if (newchildren > 0 &&
31531195e687SMark J Musante 		    (entry = find_vdev_entry(zhp, mchild, mchildren,
31541195e687SMark J Musante 		    newchild, newchildren)) >= 0) {
31551195e687SMark J Musante 			/* We found a disk that the user specified. */
31561195e687SMark J Musante 			vdev = mchild[entry];
31571195e687SMark J Musante 			++found;
31581195e687SMark J Musante 		} else {
31591195e687SMark J Musante 			/* User didn't specify a disk for this vdev. */
31601195e687SMark J Musante 			vdev = mchild[mchildren - 1];
31611195e687SMark J Musante 		}
31621195e687SMark J Musante 
31631195e687SMark J Musante 		if (nvlist_dup(vdev, &varray[vcount++], 0) != 0)
31641195e687SMark J Musante 			goto out;
31651195e687SMark J Musante 	}
31661195e687SMark J Musante 
31671195e687SMark J Musante 	/* did we find every disk the user specified? */
31681195e687SMark J Musante 	if (found != newchildren) {
31691195e687SMark J Musante 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "Device list must "
31701195e687SMark J Musante 		    "include at most one disk from each mirror"));
31711195e687SMark J Musante 		retval = zfs_error(hdl, EZFS_INVALCONFIG, msg);
31721195e687SMark J Musante 		goto out;
31731195e687SMark J Musante 	}
31741195e687SMark J Musante 
31751195e687SMark J Musante 	/* Prepare the nvlist for populating. */
31761195e687SMark J Musante 	if (*newroot == NULL) {
31771195e687SMark J Musante 		if (nvlist_alloc(newroot, NV_UNIQUE_NAME, 0) != 0)
31781195e687SMark J Musante 			goto out;
31791195e687SMark J Musante 		freelist = B_TRUE;
31801195e687SMark J Musante 		if (nvlist_add_string(*newroot, ZPOOL_CONFIG_TYPE,
31811195e687SMark J Musante 		    VDEV_TYPE_ROOT) != 0)
31821195e687SMark J Musante 			goto out;
31831195e687SMark J Musante 	} else {
31841195e687SMark J Musante 		verify(nvlist_remove_all(*newroot, ZPOOL_CONFIG_CHILDREN) == 0);
31851195e687SMark J Musante 	}
31861195e687SMark J Musante 
31871195e687SMark J Musante 	/* Add all the children we found */
31881195e687SMark J Musante 	if (nvlist_add_nvlist_array(*newroot, ZPOOL_CONFIG_CHILDREN, varray,
31891195e687SMark J Musante 	    lastlog == 0 ? vcount : lastlog) != 0)
31901195e687SMark J Musante 		goto out;
31911195e687SMark J Musante 
31921195e687SMark J Musante 	/*
31931195e687SMark J Musante 	 * If we're just doing a dry run, exit now with success.
31941195e687SMark J Musante 	 */
31951195e687SMark J Musante 	if (flags.dryrun) {
31961195e687SMark J Musante 		memory_err = B_FALSE;
31971195e687SMark J Musante 		freelist = B_FALSE;
31981195e687SMark J Musante 		goto out;
31991195e687SMark J Musante 	}
32001195e687SMark J Musante 
32011195e687SMark J Musante 	/* now build up the config list & call the ioctl */
32021195e687SMark J Musante 	if (nvlist_alloc(&newconfig, NV_UNIQUE_NAME, 0) != 0)
32031195e687SMark J Musante 		goto out;
32041195e687SMark J Musante 
32051195e687SMark J Musante 	if (nvlist_add_nvlist(newconfig,
32061195e687SMark J Musante 	    ZPOOL_CONFIG_VDEV_TREE, *newroot) != 0 ||
32071195e687SMark J Musante 	    nvlist_add_string(newconfig,
32081195e687SMark J Musante 	    ZPOOL_CONFIG_POOL_NAME, newname) != 0 ||
32091195e687SMark J Musante 	    nvlist_add_uint64(newconfig, ZPOOL_CONFIG_VERSION, vers) != 0)
32101195e687SMark J Musante 		goto out;
32111195e687SMark J Musante 
32121195e687SMark J Musante 	/*
32131195e687SMark J Musante 	 * The new pool is automatically part of the namespace unless we
32141195e687SMark J Musante 	 * explicitly export it.
32151195e687SMark J Musante 	 */
32161195e687SMark J Musante 	if (!flags.import)
32171195e687SMark J Musante 		zc.zc_cookie = ZPOOL_EXPORT_AFTER_SPLIT;
32181195e687SMark J Musante 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
32191195e687SMark J Musante 	(void) strlcpy(zc.zc_string, newname, sizeof (zc.zc_string));
32201195e687SMark J Musante 	if (zcmd_write_conf_nvlist(hdl, &zc, newconfig) != 0)
32211195e687SMark J Musante 		goto out;
32221195e687SMark J Musante 	if (zc_props != NULL && zcmd_write_src_nvlist(hdl, &zc, zc_props) != 0)
32231195e687SMark J Musante 		goto out;
32241195e687SMark J Musante 
32251195e687SMark J Musante 	if (zfs_ioctl(hdl, ZFS_IOC_VDEV_SPLIT, &zc) != 0) {
32261195e687SMark J Musante 		retval = zpool_standard_error(hdl, errno, msg);
32271195e687SMark J Musante 		goto out;
32281195e687SMark J Musante 	}
32291195e687SMark J Musante 
32301195e687SMark J Musante 	freelist = B_FALSE;
32311195e687SMark J Musante 	memory_err = B_FALSE;
32321195e687SMark J Musante 
32331195e687SMark J Musante out:
32341195e687SMark J Musante 	if (varray != NULL) {
32351195e687SMark J Musante 		int v;
32361195e687SMark J Musante 
32371195e687SMark J Musante 		for (v = 0; v < vcount; v++)
32381195e687SMark J Musante 			nvlist_free(varray[v]);
32391195e687SMark J Musante 		free(varray);
32401195e687SMark J Musante 	}
32411195e687SMark J Musante 	zcmd_free_nvlists(&zc);
3242aab83bb8SJosef 'Jeff' Sipek 	nvlist_free(zc_props);
3243aab83bb8SJosef 'Jeff' Sipek 	nvlist_free(newconfig);
32441195e687SMark J Musante 	if (freelist) {
32451195e687SMark J Musante 		nvlist_free(*newroot);
32461195e687SMark J Musante 		*newroot = NULL;
32471195e687SMark J Musante 	}
32481195e687SMark J Musante 
32491195e687SMark J Musante 	if (retval != 0)
32501195e687SMark J Musante 		return (retval);
32511195e687SMark J Musante 
32521195e687SMark J Musante 	if (memory_err)
32531195e687SMark J Musante 		return (no_memory(hdl));
32541195e687SMark J Musante 
32551195e687SMark J Musante 	return (0);
32561195e687SMark J Musante }
32571195e687SMark J Musante 
325899653d4eSeschrock /*
32595cabbc6bSPrashanth Sreenivasa  * Remove the given device.
326099653d4eSeschrock  */
326199653d4eSeschrock int
326299653d4eSeschrock zpool_vdev_remove(zpool_handle_t *zhp, const char *path)
326399653d4eSeschrock {
326499653d4eSeschrock 	zfs_cmd_t zc = { 0 };
326599653d4eSeschrock 	char msg[1024];
326699653d4eSeschrock 	nvlist_t *tgt;
326788ecc943SGeorge Wilson 	boolean_t avail_spare, l2cache, islog;
326899653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
326988ecc943SGeorge Wilson 	uint64_t version;
327099653d4eSeschrock 
327199653d4eSeschrock 	(void) snprintf(msg, sizeof (msg),
327299653d4eSeschrock 	    dgettext(TEXT_DOMAIN, "cannot remove %s"), path);
327399653d4eSeschrock 
327499653d4eSeschrock 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
3275ee0eb9f2SEric Schrock 	if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache,
32765cabbc6bSPrashanth Sreenivasa 	    &islog)) == NULL)
327799653d4eSeschrock 		return (zfs_error(hdl, EZFS_NODEVICE, msg));
327899653d4eSeschrock 
327988ecc943SGeorge Wilson 	version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
328088ecc943SGeorge Wilson 	if (islog && version < SPA_VERSION_HOLES) {
328188ecc943SGeorge Wilson 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
32825cabbc6bSPrashanth Sreenivasa 		    "pool must be upgraded to support log removal"));
328388ecc943SGeorge Wilson 		return (zfs_error(hdl, EZFS_BADVERSION, msg));
328488ecc943SGeorge Wilson 	}
328588ecc943SGeorge Wilson 
32865cabbc6bSPrashanth Sreenivasa 	if (!islog && !avail_spare && !l2cache && zpool_is_bootable(zhp)) {
32875cabbc6bSPrashanth Sreenivasa 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
32885cabbc6bSPrashanth Sreenivasa 		    "root pool can not have removed devices, "
32895cabbc6bSPrashanth Sreenivasa 		    "because GRUB does not understand them"));
32905cabbc6bSPrashanth Sreenivasa 		return (zfs_error(hdl, EINVAL, msg));
32915cabbc6bSPrashanth Sreenivasa 	}
32925cabbc6bSPrashanth Sreenivasa 
32935cabbc6bSPrashanth Sreenivasa 	zc.zc_guid = fnvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID);
32945cabbc6bSPrashanth Sreenivasa 
32955cabbc6bSPrashanth Sreenivasa 	if (zfs_ioctl(hdl, ZFS_IOC_VDEV_REMOVE, &zc) == 0)
32965cabbc6bSPrashanth Sreenivasa 		return (0);
32975cabbc6bSPrashanth Sreenivasa 
32985cabbc6bSPrashanth Sreenivasa 	switch (errno) {
32995cabbc6bSPrashanth Sreenivasa 
33005cabbc6bSPrashanth Sreenivasa 	case EINVAL:
33015cabbc6bSPrashanth Sreenivasa 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
33025cabbc6bSPrashanth Sreenivasa 		    "invalid config; all top-level vdevs must "
33035cabbc6bSPrashanth Sreenivasa 		    "have the same sector size and not be raidz."));
33045cabbc6bSPrashanth Sreenivasa 		(void) zfs_error(hdl, EZFS_INVALCONFIG, msg);
33055cabbc6bSPrashanth Sreenivasa 		break;
33065cabbc6bSPrashanth Sreenivasa 
33075cabbc6bSPrashanth Sreenivasa 	case EBUSY:
33085cabbc6bSPrashanth Sreenivasa 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
33095cabbc6bSPrashanth Sreenivasa 		    "Pool busy; removal may already be in progress"));
33105cabbc6bSPrashanth Sreenivasa 		(void) zfs_error(hdl, EZFS_BUSY, msg);
33115cabbc6bSPrashanth Sreenivasa 		break;
33125cabbc6bSPrashanth Sreenivasa 
33135cabbc6bSPrashanth Sreenivasa 	default:
33145cabbc6bSPrashanth Sreenivasa 		(void) zpool_standard_error(hdl, errno, msg);
33155cabbc6bSPrashanth Sreenivasa 	}
33165cabbc6bSPrashanth Sreenivasa 	return (-1);
33175cabbc6bSPrashanth Sreenivasa }
33185cabbc6bSPrashanth Sreenivasa 
33195cabbc6bSPrashanth Sreenivasa int
33205cabbc6bSPrashanth Sreenivasa zpool_vdev_remove_cancel(zpool_handle_t *zhp)
33215cabbc6bSPrashanth Sreenivasa {
33225cabbc6bSPrashanth Sreenivasa 	zfs_cmd_t zc = { 0 };
33235cabbc6bSPrashanth Sreenivasa 	char msg[1024];
33245cabbc6bSPrashanth Sreenivasa 	libzfs_handle_t *hdl = zhp->zpool_hdl;
33255cabbc6bSPrashanth Sreenivasa 
33265cabbc6bSPrashanth Sreenivasa 	(void) snprintf(msg, sizeof (msg),
33275cabbc6bSPrashanth Sreenivasa 	    dgettext(TEXT_DOMAIN, "cannot cancel removal"));
33285cabbc6bSPrashanth Sreenivasa 
33295cabbc6bSPrashanth Sreenivasa 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
33305cabbc6bSPrashanth Sreenivasa 	zc.zc_cookie = 1;
333199653d4eSeschrock 
3332ecd6cf80Smarks 	if (zfs_ioctl(hdl, ZFS_IOC_VDEV_REMOVE, &zc) == 0)
333399653d4eSeschrock 		return (0);
333499653d4eSeschrock 
333599653d4eSeschrock 	return (zpool_standard_error(hdl, errno, msg));
3336ea8dc4b6Seschrock }
3337ea8dc4b6Seschrock 
33385cabbc6bSPrashanth Sreenivasa int
33395cabbc6bSPrashanth Sreenivasa zpool_vdev_indirect_size(zpool_handle_t *zhp, const char *path,
33405cabbc6bSPrashanth Sreenivasa     uint64_t *sizep)
33415cabbc6bSPrashanth Sreenivasa {
33425cabbc6bSPrashanth Sreenivasa 	char msg[1024];
33435cabbc6bSPrashanth Sreenivasa 	nvlist_t *tgt;
33445cabbc6bSPrashanth Sreenivasa 	boolean_t avail_spare, l2cache, islog;
33455cabbc6bSPrashanth Sreenivasa 	libzfs_handle_t *hdl = zhp->zpool_hdl;
33465cabbc6bSPrashanth Sreenivasa 
33475cabbc6bSPrashanth Sreenivasa 	(void) snprintf(msg, sizeof (msg),
33485cabbc6bSPrashanth Sreenivasa 	    dgettext(TEXT_DOMAIN, "cannot determine indirect size of %s"),
33495cabbc6bSPrashanth Sreenivasa 	    path);
33505cabbc6bSPrashanth Sreenivasa 
33515cabbc6bSPrashanth Sreenivasa 	if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache,
33525cabbc6bSPrashanth Sreenivasa 	    &islog)) == NULL)
33535cabbc6bSPrashanth Sreenivasa 		return (zfs_error(hdl, EZFS_NODEVICE, msg));
33545cabbc6bSPrashanth Sreenivasa 
33555cabbc6bSPrashanth Sreenivasa 	if (avail_spare || l2cache || islog) {
33565cabbc6bSPrashanth Sreenivasa 		*sizep = 0;
33575cabbc6bSPrashanth Sreenivasa 		return (0);
33585cabbc6bSPrashanth Sreenivasa 	}
33595cabbc6bSPrashanth Sreenivasa 
33605cabbc6bSPrashanth Sreenivasa 	if (nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_INDIRECT_SIZE, sizep) != 0) {
33615cabbc6bSPrashanth Sreenivasa 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
33625cabbc6bSPrashanth Sreenivasa 		    "indirect size not available"));
33635cabbc6bSPrashanth Sreenivasa 		return (zfs_error(hdl, EINVAL, msg));
33645cabbc6bSPrashanth Sreenivasa 	}
33655cabbc6bSPrashanth Sreenivasa 	return (0);
33665cabbc6bSPrashanth Sreenivasa }
33675cabbc6bSPrashanth Sreenivasa 
3368ea8dc4b6Seschrock /*
3369ea8dc4b6Seschrock  * Clear the errors for the pool, or the particular device if specified.
3370ea8dc4b6Seschrock  */
3371ea8dc4b6Seschrock int
3372468c413aSTim Haley zpool_clear(zpool_handle_t *zhp, const char *path, nvlist_t *rewindnvl)
3373ea8dc4b6Seschrock {
3374ea8dc4b6Seschrock 	zfs_cmd_t zc = { 0 };
3375ea8dc4b6Seschrock 	char msg[1024];
337699653d4eSeschrock 	nvlist_t *tgt;
33775dafeea3SPavel Zakharov 	zpool_load_policy_t policy;
3378fa94a07fSbrendan 	boolean_t avail_spare, l2cache;
337999653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
3380468c413aSTim Haley 	nvlist_t *nvi = NULL;
33814b964adaSGeorge Wilson 	int error;
3382ea8dc4b6Seschrock 
3383ea8dc4b6Seschrock 	if (path)
3384ea8dc4b6Seschrock 		(void) snprintf(msg, sizeof (msg),
3385ea8dc4b6Seschrock 		    dgettext(TEXT_DOMAIN, "cannot clear errors for %s"),
3386e9dbad6fSeschrock 		    path);
3387ea8dc4b6Seschrock 	else
3388ea8dc4b6Seschrock 		(void) snprintf(msg, sizeof (msg),
3389ea8dc4b6Seschrock 		    dgettext(TEXT_DOMAIN, "cannot clear errors for %s"),
3390ea8dc4b6Seschrock 		    zhp->zpool_name);
3391ea8dc4b6Seschrock 
3392ea8dc4b6Seschrock 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
339399653d4eSeschrock 	if (path) {
3394fa94a07fSbrendan 		if ((tgt = zpool_find_vdev(zhp, path, &avail_spare,
33955cabbc6bSPrashanth Sreenivasa 		    &l2cache, NULL)) == NULL)
339699653d4eSeschrock 			return (zfs_error(hdl, EZFS_NODEVICE, msg));
3397ea8dc4b6Seschrock 
3398fa94a07fSbrendan 		/*
3399fa94a07fSbrendan 		 * Don't allow error clearing for hot spares.  Do allow
3400fa94a07fSbrendan 		 * error clearing for l2cache devices.
3401fa94a07fSbrendan 		 */
3402a43d325bSek 		if (avail_spare)
340399653d4eSeschrock 			return (zfs_error(hdl, EZFS_ISSPARE, msg));
3404ea8dc4b6Seschrock 
340599653d4eSeschrock 		verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID,
340699653d4eSeschrock 		    &zc.zc_guid) == 0);
3407fa9e4066Sahrens 	}
3408fa9e4066Sahrens 
34095dafeea3SPavel Zakharov 	zpool_get_load_policy(rewindnvl, &policy);
34105dafeea3SPavel Zakharov 	zc.zc_cookie = policy.zlp_rewind;
3411468c413aSTim Haley 
341257f304caSGeorge Wilson 	if (zcmd_alloc_dst_nvlist(hdl, &zc, zhp->zpool_config_size * 2) != 0)
3413468c413aSTim Haley 		return (-1);
3414468c413aSTim Haley 
3415cb04b873SMark J Musante 	if (zcmd_write_src_nvlist(hdl, &zc, rewindnvl) != 0)
3416468c413aSTim Haley 		return (-1);
3417468c413aSTim Haley 
34184b964adaSGeorge Wilson 	while ((error = zfs_ioctl(hdl, ZFS_IOC_CLEAR, &zc)) != 0 &&
34194b964adaSGeorge Wilson 	    errno == ENOMEM) {
34204b964adaSGeorge Wilson 		if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
34214b964adaSGeorge Wilson 			zcmd_free_nvlists(&zc);
34224b964adaSGeorge Wilson 			return (-1);
34234b964adaSGeorge Wilson 		}
34244b964adaSGeorge Wilson 	}
34254b964adaSGeorge Wilson 
34265dafeea3SPavel Zakharov 	if (!error || ((policy.zlp_rewind & ZPOOL_TRY_REWIND) &&
3427468c413aSTim Haley 	    errno != EPERM && errno != EACCES)) {
34285dafeea3SPavel Zakharov 		if (policy.zlp_rewind &
3429468c413aSTim Haley 		    (ZPOOL_DO_REWIND | ZPOOL_TRY_REWIND)) {
3430468c413aSTim Haley 			(void) zcmd_read_dst_nvlist(hdl, &zc, &nvi);
3431468c413aSTim Haley 			zpool_rewind_exclaim(hdl, zc.zc_name,
34325dafeea3SPavel Zakharov 			    ((policy.zlp_rewind & ZPOOL_TRY_REWIND) != 0),
3433468c413aSTim Haley 			    nvi);
3434468c413aSTim Haley 			nvlist_free(nvi);
3435468c413aSTim Haley 		}
3436468c413aSTim Haley 		zcmd_free_nvlists(&zc);
343799653d4eSeschrock 		return (0);
3438468c413aSTim Haley 	}
343999653d4eSeschrock 
3440468c413aSTim Haley 	zcmd_free_nvlists(&zc);
344199653d4eSeschrock 	return (zpool_standard_error(hdl, errno, msg));
3442fa9e4066Sahrens }
3443fa9e4066Sahrens 
34443d7072f8Seschrock /*
34453d7072f8Seschrock  * Similar to zpool_clear(), but takes a GUID (used by fmd).
34463d7072f8Seschrock  */
34473d7072f8Seschrock int
34483d7072f8Seschrock zpool_vdev_clear(zpool_handle_t *zhp, uint64_t guid)
34493d7072f8Seschrock {
34503d7072f8Seschrock 	zfs_cmd_t zc = { 0 };
34513d7072f8Seschrock 	char msg[1024];
34523d7072f8Seschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
34533d7072f8Seschrock 
34543d7072f8Seschrock 	(void) snprintf(msg, sizeof (msg),
34553d7072f8Seschrock 	    dgettext(TEXT_DOMAIN, "cannot clear errors for %llx"),
34563d7072f8Seschrock 	    guid);
34573d7072f8Seschrock 
34583d7072f8Seschrock 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
34593d7072f8Seschrock 	zc.zc_guid = guid;
346014f8ce41SVictor Latushkin 	zc.zc_cookie = ZPOOL_NO_REWIND;
34613d7072f8Seschrock 
34623d7072f8Seschrock 	if (ioctl(hdl->libzfs_fd, ZFS_IOC_CLEAR, &zc) == 0)
34633d7072f8Seschrock 		return (0);
34643d7072f8Seschrock 
34653d7072f8Seschrock 	return (zpool_standard_error(hdl, errno, msg));
34663d7072f8Seschrock }
34673d7072f8Seschrock 
3468e9103aaeSGarrett D'Amore /*
3469e9103aaeSGarrett D'Amore  * Change the GUID for a pool.
3470e9103aaeSGarrett D'Amore  */
3471e9103aaeSGarrett D'Amore int
3472e9103aaeSGarrett D'Amore zpool_reguid(zpool_handle_t *zhp)
3473e9103aaeSGarrett D'Amore {
3474e9103aaeSGarrett D'Amore 	char msg[1024];
3475e9103aaeSGarrett D'Amore 	libzfs_handle_t *hdl = zhp->zpool_hdl;
3476e9103aaeSGarrett D'Amore 	zfs_cmd_t zc = { 0 };
3477e9103aaeSGarrett D'Amore 
3478e9103aaeSGarrett D'Amore 	(void) snprintf(msg, sizeof (msg),
3479e9103aaeSGarrett D'Amore 	    dgettext(TEXT_DOMAIN, "cannot reguid '%s'"), zhp->zpool_name);
3480e9103aaeSGarrett D'Amore 
3481e9103aaeSGarrett D'Amore 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
3482e9103aaeSGarrett D'Amore 	if (zfs_ioctl(hdl, ZFS_IOC_POOL_REGUID, &zc) == 0)
3483e9103aaeSGarrett D'Amore 		return (0);
3484e9103aaeSGarrett D'Amore 
3485e9103aaeSGarrett D'Amore 	return (zpool_standard_error(hdl, errno, msg));
3486e9103aaeSGarrett D'Amore }
3487e9103aaeSGarrett D'Amore 
34884263d13fSGeorge Wilson /*
34894263d13fSGeorge Wilson  * Reopen the pool.
34904263d13fSGeorge Wilson  */
34914263d13fSGeorge Wilson int
34924263d13fSGeorge Wilson zpool_reopen(zpool_handle_t *zhp)
34934263d13fSGeorge Wilson {
34944263d13fSGeorge Wilson 	zfs_cmd_t zc = { 0 };
34954263d13fSGeorge Wilson 	char msg[1024];
34964263d13fSGeorge Wilson 	libzfs_handle_t *hdl = zhp->zpool_hdl;
34974263d13fSGeorge Wilson 
34984263d13fSGeorge Wilson 	(void) snprintf(msg, sizeof (msg),
34994263d13fSGeorge Wilson 	    dgettext(TEXT_DOMAIN, "cannot reopen '%s'"),
35004263d13fSGeorge Wilson 	    zhp->zpool_name);
35014263d13fSGeorge Wilson 
35024263d13fSGeorge Wilson 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
35034263d13fSGeorge Wilson 	if (zfs_ioctl(hdl, ZFS_IOC_POOL_REOPEN, &zc) == 0)
35044263d13fSGeorge Wilson 		return (0);
35054263d13fSGeorge Wilson 	return (zpool_standard_error(hdl, errno, msg));
35064263d13fSGeorge Wilson }
35074263d13fSGeorge Wilson 
3508c67d9675Seschrock /*
3509c67d9675Seschrock  * Convert from a devid string to a path.
3510c67d9675Seschrock  */
3511c67d9675Seschrock static char *
3512c67d9675Seschrock devid_to_path(char *devid_str)
3513c67d9675Seschrock {
3514c67d9675Seschrock 	ddi_devid_t devid;
3515c67d9675Seschrock 	char *minor;
3516c67d9675Seschrock 	char *path;
3517c67d9675Seschrock 	devid_nmlist_t *list = NULL;
3518c67d9675Seschrock 	int ret;
3519c67d9675Seschrock 
3520c67d9675Seschrock 	if (devid_str_decode(devid_str, &devid, &minor) != 0)
3521c67d9675Seschrock 		return (NULL);
3522c67d9675Seschrock 
3523c67d9675Seschrock 	ret = devid_deviceid_to_nmlist("/dev", devid, minor, &list);
3524c67d9675Seschrock 
3525c67d9675Seschrock 	devid_str_free(minor);
3526c67d9675Seschrock 	devid_free(devid);
3527c67d9675Seschrock 
3528c67d9675Seschrock 	if (ret != 0)
3529c67d9675Seschrock 		return (NULL);
3530c67d9675Seschrock 
3531078266a5SMarcel Telka 	/*
3532078266a5SMarcel Telka 	 * In a case the strdup() fails, we will just return NULL below.
3533078266a5SMarcel Telka 	 */
3534078266a5SMarcel Telka 	path = strdup(list[0].devname);
353599653d4eSeschrock 
3536c67d9675Seschrock 	devid_free_nmlist(list);
3537c67d9675Seschrock 
3538c67d9675Seschrock 	return (path);
3539c67d9675Seschrock }
3540c67d9675Seschrock 
3541c67d9675Seschrock /*
3542c67d9675Seschrock  * Convert from a path to a devid string.
3543c67d9675Seschrock  */
3544c67d9675Seschrock static char *
3545c67d9675Seschrock path_to_devid(const char *path)
3546c67d9675Seschrock {
3547c67d9675Seschrock 	int fd;
3548c67d9675Seschrock 	ddi_devid_t devid;
3549c67d9675Seschrock 	char *minor, *ret;
3550c67d9675Seschrock 
3551c67d9675Seschrock 	if ((fd = open(path, O_RDONLY)) < 0)
3552c67d9675Seschrock 		return (NULL);
3553c67d9675Seschrock 
3554c67d9675Seschrock 	minor = NULL;
3555c67d9675Seschrock 	ret = NULL;
3556c67d9675Seschrock 	if (devid_get(fd, &devid) == 0) {
3557c67d9675Seschrock 		if (devid_get_minor_name(fd, &minor) == 0)
3558c67d9675Seschrock 			ret = devid_str_encode(devid, minor);
3559c67d9675Seschrock 		if (minor != NULL)
3560c67d9675Seschrock 			devid_str_free(minor);
3561c67d9675Seschrock 		devid_free(devid);
3562c67d9675Seschrock 	}
3563c67d9675Seschrock 	(void) close(fd);
3564c67d9675Seschrock 
3565c67d9675Seschrock 	return (ret);
3566c67d9675Seschrock }
3567c67d9675Seschrock 
3568c67d9675Seschrock /*
3569c67d9675Seschrock  * Issue the necessary ioctl() to update the stored path value for the vdev.  We
3570c67d9675Seschrock  * ignore any failure here, since a common case is for an unprivileged user to
3571c67d9675Seschrock  * type 'zpool status', and we'll display the correct information anyway.
3572c67d9675Seschrock  */
3573c67d9675Seschrock static void
3574c67d9675Seschrock set_path(zpool_handle_t *zhp, nvlist_t *nv, const char *path)
3575c67d9675Seschrock {
3576c67d9675Seschrock 	zfs_cmd_t zc = { 0 };
3577c67d9675Seschrock 
3578c67d9675Seschrock 	(void) strncpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
3579e9dbad6fSeschrock 	(void) strncpy(zc.zc_value, path, sizeof (zc.zc_value));
3580c67d9675Seschrock 	verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
3581ea8dc4b6Seschrock 	    &zc.zc_guid) == 0);
3582c67d9675Seschrock 
358399653d4eSeschrock 	(void) ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SETPATH, &zc);
3584c67d9675Seschrock }
3585c67d9675Seschrock 
3586c67d9675Seschrock /*
3587c67d9675Seschrock  * Given a vdev, return the name to display in iostat.  If the vdev has a path,
3588c67d9675Seschrock  * we use that, stripping off any leading "/dev/dsk/"; if not, we use the type.
3589c67d9675Seschrock  * We also check if this is a whole disk, in which case we strip off the
3590c67d9675Seschrock  * trailing 's0' slice name.
3591c67d9675Seschrock  *
3592c67d9675Seschrock  * This routine is also responsible for identifying when disks have been
3593c67d9675Seschrock  * reconfigured in a new location.  The kernel will have opened the device by
3594c67d9675Seschrock  * devid, but the path will still refer to the old location.  To catch this, we
3595c67d9675Seschrock  * first do a path -> devid translation (which is fast for the common case).  If
3596c67d9675Seschrock  * the devid matches, we're done.  If not, we do a reverse devid -> path
3597c67d9675Seschrock  * translation and issue the appropriate ioctl() to update the path of the vdev.
3598c67d9675Seschrock  * If 'zhp' is NULL, then this is an exported pool, and we don't need to do any
3599c67d9675Seschrock  * of these checks.
3600c67d9675Seschrock  */
3601c67d9675Seschrock char *
360288ecc943SGeorge Wilson zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv,
360388ecc943SGeorge Wilson     boolean_t verbose)
3604c67d9675Seschrock {
3605c67d9675Seschrock 	char *path, *devid;
3606ea8dc4b6Seschrock 	uint64_t value;
3607ea8dc4b6Seschrock 	char buf[64];
36083d7072f8Seschrock 	vdev_stat_t *vs;
36093d7072f8Seschrock 	uint_t vsc;
3610c67d9675Seschrock 
3611ea8dc4b6Seschrock 	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT,
3612ea8dc4b6Seschrock 	    &value) == 0) {
3613ea8dc4b6Seschrock 		verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
3614ea8dc4b6Seschrock 		    &value) == 0);
36155ad82045Snd 		(void) snprintf(buf, sizeof (buf), "%llu",
36165ad82045Snd 		    (u_longlong_t)value);
3617ea8dc4b6Seschrock 		path = buf;
3618ea8dc4b6Seschrock 	} else if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) {
3619c67d9675Seschrock 
36203d7072f8Seschrock 		/*
36213d7072f8Seschrock 		 * If the device is dead (faulted, offline, etc) then don't
36223d7072f8Seschrock 		 * bother opening it.  Otherwise we may be forcing the user to
36233d7072f8Seschrock 		 * open a misbehaving device, which can have undesirable
36243d7072f8Seschrock 		 * effects.
36253d7072f8Seschrock 		 */
36263f9d6ad7SLin Ling 		if ((nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
36273d7072f8Seschrock 		    (uint64_t **)&vs, &vsc) != 0 ||
36283d7072f8Seschrock 		    vs->vs_state >= VDEV_STATE_DEGRADED) &&
36293d7072f8Seschrock 		    zhp != NULL &&
3630c67d9675Seschrock 		    nvlist_lookup_string(nv, ZPOOL_CONFIG_DEVID, &devid) == 0) {
3631c67d9675Seschrock 			/*
3632c67d9675Seschrock 			 * Determine if the current path is correct.
3633c67d9675Seschrock 			 */
3634c67d9675Seschrock 			char *newdevid = path_to_devid(path);
3635c67d9675Seschrock 
3636c67d9675Seschrock 			if (newdevid == NULL ||
3637c67d9675Seschrock 			    strcmp(devid, newdevid) != 0) {
3638c67d9675Seschrock 				char *newpath;
3639c67d9675Seschrock 
3640c67d9675Seschrock 				if ((newpath = devid_to_path(devid)) != NULL) {
3641c67d9675Seschrock 					/*
3642c67d9675Seschrock 					 * Update the path appropriately.
3643c67d9675Seschrock 					 */
3644c67d9675Seschrock 					set_path(zhp, nv, newpath);
364599653d4eSeschrock 					if (nvlist_add_string(nv,
364699653d4eSeschrock 					    ZPOOL_CONFIG_PATH, newpath) == 0)
364799653d4eSeschrock 						verify(nvlist_lookup_string(nv,
364899653d4eSeschrock 						    ZPOOL_CONFIG_PATH,
364999653d4eSeschrock 						    &path) == 0);
3650c67d9675Seschrock 					free(newpath);
3651c67d9675Seschrock 				}
3652c67d9675Seschrock 			}
3653c67d9675Seschrock 
365499653d4eSeschrock 			if (newdevid)
365599653d4eSeschrock 				devid_str_free(newdevid);
3656c67d9675Seschrock 		}
3657c67d9675Seschrock 
36586401734dSWill Andrews 		if (strncmp(path, ZFS_DISK_ROOTD, strlen(ZFS_DISK_ROOTD)) == 0)
36596401734dSWill Andrews 			path += strlen(ZFS_DISK_ROOTD);
3660c67d9675Seschrock 
3661c67d9675Seschrock 		if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK,
3662ea8dc4b6Seschrock 		    &value) == 0 && value) {
36633fdda499SJohn Harres 			int pathlen = strlen(path);
366499653d4eSeschrock 			char *tmp = zfs_strdup(hdl, path);
36653fdda499SJohn Harres 
36663fdda499SJohn Harres 			/*
36677855d95bSToomas Soome 			 * If it starts with c#, and ends with "s0" or "s1",
36687855d95bSToomas Soome 			 * chop the slice off, or if it ends with "s0/old" or
36697855d95bSToomas Soome 			 * "s1/old", remove the slice from the middle.
36703fdda499SJohn Harres 			 */
36713fdda499SJohn Harres 			if (CTD_CHECK(tmp)) {
36727855d95bSToomas Soome 				if (strcmp(&tmp[pathlen - 2], "s0") == 0 ||
36737855d95bSToomas Soome 				    strcmp(&tmp[pathlen - 2], "s1") == 0) {
36743fdda499SJohn Harres 					tmp[pathlen - 2] = '\0';
36753fdda499SJohn Harres 				} else if (pathlen > 6 &&
36767855d95bSToomas Soome 				    (strcmp(&tmp[pathlen - 6], "s0/old") == 0 ||
36777855d95bSToomas Soome 				    strcmp(&tmp[pathlen - 6], "s1/old") == 0)) {
36783fdda499SJohn Harres 					(void) strcpy(&tmp[pathlen - 6],
36793fdda499SJohn Harres 					    "/old");
36803fdda499SJohn Harres 				}
36813fdda499SJohn Harres 			}
3682c67d9675Seschrock 			return (tmp);
3683c67d9675Seschrock 		}
3684c67d9675Seschrock 	} else {
3685c67d9675Seschrock 		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &path) == 0);
368699653d4eSeschrock 
368799653d4eSeschrock 		/*
368899653d4eSeschrock 		 * If it's a raidz device, we need to stick in the parity level.
368999653d4eSeschrock 		 */
369099653d4eSeschrock 		if (strcmp(path, VDEV_TYPE_RAIDZ) == 0) {
369199653d4eSeschrock 			verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NPARITY,
369299653d4eSeschrock 			    &value) == 0);
369399653d4eSeschrock 			(void) snprintf(buf, sizeof (buf), "%s%llu", path,
36945ad82045Snd 			    (u_longlong_t)value);
369599653d4eSeschrock 			path = buf;
369699653d4eSeschrock 		}
369788ecc943SGeorge Wilson 
369888ecc943SGeorge Wilson 		/*
369988ecc943SGeorge Wilson 		 * We identify each top-level vdev by using a <type-id>
370088ecc943SGeorge Wilson 		 * naming convention.
370188ecc943SGeorge Wilson 		 */
370288ecc943SGeorge Wilson 		if (verbose) {
370388ecc943SGeorge Wilson 			uint64_t id;
370488ecc943SGeorge Wilson 
370588ecc943SGeorge Wilson 			verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_ID,
370688ecc943SGeorge Wilson 			    &id) == 0);
370788ecc943SGeorge Wilson 			(void) snprintf(buf, sizeof (buf), "%s-%llu", path,
370888ecc943SGeorge Wilson 			    (u_longlong_t)id);
370988ecc943SGeorge Wilson 			path = buf;
371088ecc943SGeorge Wilson 		}
3711c67d9675Seschrock 	}
3712c67d9675Seschrock 
371399653d4eSeschrock 	return (zfs_strdup(hdl, path));
3714c67d9675Seschrock }
3715ea8dc4b6Seschrock 
3716ea8dc4b6Seschrock static int
3717a2cdcdd2SPaul Dagnelie zbookmark_mem_compare(const void *a, const void *b)
3718ea8dc4b6Seschrock {
37197802d7bfSMatthew Ahrens 	return (memcmp(a, b, sizeof (zbookmark_phys_t)));
3720ea8dc4b6Seschrock }
3721ea8dc4b6Seschrock 
3722ea8dc4b6Seschrock /*
3723ea8dc4b6Seschrock  * Retrieve the persistent error log, uniquify the members, and return to the
3724ea8dc4b6Seschrock  * caller.
3725ea8dc4b6Seschrock  */
3726ea8dc4b6Seschrock int
372755434c77Sek zpool_get_errlog(zpool_handle_t *zhp, nvlist_t **nverrlistp)
3728ea8dc4b6Seschrock {
3729ea8dc4b6Seschrock 	zfs_cmd_t zc = { 0 };
3730ea8dc4b6Seschrock 	uint64_t count;
37317802d7bfSMatthew Ahrens 	zbookmark_phys_t *zb = NULL;
373255434c77Sek 	int i;
3733ea8dc4b6Seschrock 
3734ea8dc4b6Seschrock 	/*
3735ea8dc4b6Seschrock 	 * Retrieve the raw error list from the kernel.  If the number of errors
3736ea8dc4b6Seschrock 	 * has increased, allocate more space and continue until we get the
3737ea8dc4b6Seschrock 	 * entire list.
3738ea8dc4b6Seschrock 	 */
3739ea8dc4b6Seschrock 	verify(nvlist_lookup_uint64(zhp->zpool_config, ZPOOL_CONFIG_ERRCOUNT,
3740ea8dc4b6Seschrock 	    &count) == 0);
374175519f38Sek 	if (count == 0)
374275519f38Sek 		return (0);
3743e9dbad6fSeschrock 	if ((zc.zc_nvlist_dst = (uintptr_t)zfs_alloc(zhp->zpool_hdl,
37447802d7bfSMatthew Ahrens 	    count * sizeof (zbookmark_phys_t))) == (uintptr_t)NULL)
374599653d4eSeschrock 		return (-1);
3746e9dbad6fSeschrock 	zc.zc_nvlist_dst_size = count;
3747ea8dc4b6Seschrock 	(void) strcpy(zc.zc_name, zhp->zpool_name);
3748ea8dc4b6Seschrock 	for (;;) {
374999653d4eSeschrock 		if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_ERROR_LOG,
375099653d4eSeschrock 		    &zc) != 0) {
3751e9dbad6fSeschrock 			free((void *)(uintptr_t)zc.zc_nvlist_dst);
3752ea8dc4b6Seschrock 			if (errno == ENOMEM) {
37537802d7bfSMatthew Ahrens 				void *dst;
37547802d7bfSMatthew Ahrens 
3755bf561db0Svb 				count = zc.zc_nvlist_dst_size;
37567802d7bfSMatthew Ahrens 				dst = zfs_alloc(zhp->zpool_hdl, count *
37577802d7bfSMatthew Ahrens 				    sizeof (zbookmark_phys_t));
37587802d7bfSMatthew Ahrens 				if (dst == NULL)
375999653d4eSeschrock 					return (-1);
37607802d7bfSMatthew Ahrens 				zc.zc_nvlist_dst = (uintptr_t)dst;
3761ea8dc4b6Seschrock 			} else {
3762ea8dc4b6Seschrock 				return (-1);
3763ea8dc4b6Seschrock 			}
3764ea8dc4b6Seschrock 		} else {
3765ea8dc4b6Seschrock 			break;
3766ea8dc4b6Seschrock 		}
3767ea8dc4b6Seschrock 	}
3768ea8dc4b6Seschrock 
3769ea8dc4b6Seschrock 	/*
3770ea8dc4b6Seschrock 	 * Sort the resulting bookmarks.  This is a little confusing due to the
3771ea8dc4b6Seschrock 	 * implementation of ZFS_IOC_ERROR_LOG.  The bookmarks are copied last
3772e9dbad6fSeschrock 	 * to first, and 'zc_nvlist_dst_size' indicates the number of boomarks
3773ea8dc4b6Seschrock 	 * _not_ copied as part of the process.  So we point the start of our
3774ea8dc4b6Seschrock 	 * array appropriate and decrement the total number of elements.
3775ea8dc4b6Seschrock 	 */
37767802d7bfSMatthew Ahrens 	zb = ((zbookmark_phys_t *)(uintptr_t)zc.zc_nvlist_dst) +
3777e9dbad6fSeschrock 	    zc.zc_nvlist_dst_size;
3778e9dbad6fSeschrock 	count -= zc.zc_nvlist_dst_size;
3779ea8dc4b6Seschrock 
3780a2cdcdd2SPaul Dagnelie 	qsort(zb, count, sizeof (zbookmark_phys_t), zbookmark_mem_compare);
3781ea8dc4b6Seschrock 
378255434c77Sek 	verify(nvlist_alloc(nverrlistp, 0, KM_SLEEP) == 0);
3783ea8dc4b6Seschrock 
3784ea8dc4b6Seschrock 	/*
378555434c77Sek 	 * Fill in the nverrlistp with nvlist's of dataset and object numbers.
3786ea8dc4b6Seschrock 	 */
3787ea8dc4b6Seschrock 	for (i = 0; i < count; i++) {
3788ea8dc4b6Seschrock 		nvlist_t *nv;
3789ea8dc4b6Seschrock 
3790c0a81264Sek 		/* ignoring zb_blkid and zb_level for now */
3791c0a81264Sek 		if (i > 0 && zb[i-1].zb_objset == zb[i].zb_objset &&
3792c0a81264Sek 		    zb[i-1].zb_object == zb[i].zb_object)
3793ea8dc4b6Seschrock 			continue;
3794ea8dc4b6Seschrock 
379555434c77Sek 		if (nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP) != 0)
379655434c77Sek 			goto nomem;
379755434c77Sek 		if (nvlist_add_uint64(nv, ZPOOL_ERR_DATASET,
379855434c77Sek 		    zb[i].zb_objset) != 0) {
379955434c77Sek 			nvlist_free(nv);
380099653d4eSeschrock 			goto nomem;
3801ea8dc4b6Seschrock 		}
380255434c77Sek 		if (nvlist_add_uint64(nv, ZPOOL_ERR_OBJECT,
380355434c77Sek 		    zb[i].zb_object) != 0) {
380455434c77Sek 			nvlist_free(nv);
380555434c77Sek 			goto nomem;
380655434c77Sek 		}
380755434c77Sek 		if (nvlist_add_nvlist(*nverrlistp, "ejk", nv) != 0) {
380855434c77Sek 			nvlist_free(nv);
380955434c77Sek 			goto nomem;
381055434c77Sek 		}
381155434c77Sek 		nvlist_free(nv);
3812ea8dc4b6Seschrock 	}
3813ea8dc4b6Seschrock 
38143ccfa83cSahrens 	free((void *)(uintptr_t)zc.zc_nvlist_dst);
3815ea8dc4b6Seschrock 	return (0);
381699653d4eSeschrock 
381799653d4eSeschrock nomem:
3818e9dbad6fSeschrock 	free((void *)(uintptr_t)zc.zc_nvlist_dst);
381999653d4eSeschrock 	return (no_memory(zhp->zpool_hdl));
3820ea8dc4b6Seschrock }
3821eaca9bbdSeschrock 
3822eaca9bbdSeschrock /*
3823eaca9bbdSeschrock  * Upgrade a ZFS pool to the latest on-disk version.
3824eaca9bbdSeschrock  */
3825eaca9bbdSeschrock int
3826990b4856Slling zpool_upgrade(zpool_handle_t *zhp, uint64_t new_version)
3827eaca9bbdSeschrock {
3828eaca9bbdSeschrock 	zfs_cmd_t zc = { 0 };
382999653d4eSeschrock 	libzfs_handle_t *hdl = zhp->zpool_hdl;
3830eaca9bbdSeschrock 
3831eaca9bbdSeschrock 	(void) strcpy(zc.zc_name, zhp->zpool_name);
3832990b4856Slling 	zc.zc_cookie = new_version;
3833990b4856Slling 
3834ecd6cf80Smarks 	if (zfs_ioctl(hdl, ZFS_IOC_POOL_UPGRADE, &zc) != 0)
3835ece3d9b3Slling 		return (zpool_standard_error_fmt(hdl, errno,
383699653d4eSeschrock 		    dgettext(TEXT_DOMAIN, "cannot upgrade '%s'"),
383799653d4eSeschrock 		    zhp->zpool_name));
3838eaca9bbdSeschrock 	return (0);
3839eaca9bbdSeschrock }
384006eeb2adSek 
384106eeb2adSek void
38424445fffbSMatthew Ahrens zfs_save_arguments(int argc, char **argv, char *string, int len)
384306eeb2adSek {
38444445fffbSMatthew Ahrens 	(void) strlcpy(string, basename(argv[0]), len);
38454445fffbSMatthew Ahrens 	for (int i = 1; i < argc; i++) {
38464445fffbSMatthew Ahrens 		(void) strlcat(string, " ", len);
38474445fffbSMatthew Ahrens 		(void) strlcat(string, argv[i], len);
38482a6b87f0Sek 	}
38492a6b87f0Sek }
38502a6b87f0Sek 
38512a6b87f0Sek int
38524445fffbSMatthew Ahrens zpool_log_history(libzfs_handle_t *hdl, const char *message)
38532a6b87f0Sek {
38544445fffbSMatthew Ahrens 	zfs_cmd_t zc = { 0 };
38554445fffbSMatthew Ahrens 	nvlist_t *args;
38564445fffbSMatthew Ahrens 	int err;
38574445fffbSMatthew Ahrens 
38584445fffbSMatthew Ahrens 	args = fnvlist_alloc();
38594445fffbSMatthew Ahrens 	fnvlist_add_string(args, "message", message);
38604445fffbSMatthew Ahrens 	err = zcmd_write_src_nvlist(hdl, &zc, args);
38614445fffbSMatthew Ahrens 	if (err == 0)
38624445fffbSMatthew Ahrens 		err = ioctl(hdl->libzfs_fd, ZFS_IOC_LOG_HISTORY, &zc);
38634445fffbSMatthew Ahrens 	nvlist_free(args);
38644445fffbSMatthew Ahrens 	zcmd_free_nvlists(&zc);
38654445fffbSMatthew Ahrens 	return (err);
386606eeb2adSek }
386706eeb2adSek 
386806eeb2adSek /*
386906eeb2adSek  * Perform ioctl to get some command history of a pool.
387006eeb2adSek  *
387106eeb2adSek  * 'buf' is the buffer to fill up to 'len' bytes.  'off' is the
387206eeb2adSek  * logical offset of the history buffer to start reading from.
387306eeb2adSek  *
387406eeb2adSek  * Upon return, 'off' is the next logical offset to read from and
387506eeb2adSek  * 'len' is the actual amount of bytes read into 'buf'.
387606eeb2adSek  */
387706eeb2adSek static int
387806eeb2adSek get_history(zpool_handle_t *zhp, char *buf, uint64_t *off, uint64_t *len)
387906eeb2adSek {
388006eeb2adSek 	zfs_cmd_t zc = { 0 };
388106eeb2adSek 	libzfs_handle_t *hdl = zhp->zpool_hdl;
388206eeb2adSek 
388306eeb2adSek 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
388406eeb2adSek 
388506eeb2adSek 	zc.zc_history = (uint64_t)(uintptr_t)buf;
388606eeb2adSek 	zc.zc_history_len = *len;
388706eeb2adSek 	zc.zc_history_offset = *off;
388806eeb2adSek 
388906eeb2adSek 	if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_HISTORY, &zc) != 0) {
389006eeb2adSek 		switch (errno) {
389106eeb2adSek 		case EPERM:
3892ece3d9b3Slling 			return (zfs_error_fmt(hdl, EZFS_PERM,
3893ece3d9b3Slling 			    dgettext(TEXT_DOMAIN,
389406eeb2adSek 			    "cannot show history for pool '%s'"),
389506eeb2adSek 			    zhp->zpool_name));
389606eeb2adSek 		case ENOENT:
3897ece3d9b3Slling 			return (zfs_error_fmt(hdl, EZFS_NOHISTORY,
389806eeb2adSek 			    dgettext(TEXT_DOMAIN, "cannot get history for pool "
389906eeb2adSek 			    "'%s'"), zhp->zpool_name));
3900d7306b64Sek 		case ENOTSUP:
3901d7306b64Sek 			return (zfs_error_fmt(hdl, EZFS_BADVERSION,
3902d7306b64Sek 			    dgettext(TEXT_DOMAIN, "cannot get history for pool "
3903d7306b64Sek 			    "'%s', pool must be upgraded"), zhp->zpool_name));
390406eeb2adSek 		default:
3905ece3d9b3Slling 			return (zpool_standard_error_fmt(hdl, errno,
390606eeb2adSek 			    dgettext(TEXT_DOMAIN,
390706eeb2adSek 			    "cannot get history for '%s'"), zhp->zpool_name));
390806eeb2adSek 		}
390906eeb2adSek 	}
391006eeb2adSek 
391106eeb2adSek 	*len = zc.zc_history_len;
391206eeb2adSek 	*off = zc.zc_history_offset;
391306eeb2adSek 
391406eeb2adSek 	return (0);
391506eeb2adSek }
391606eeb2adSek 
391706eeb2adSek /*
391806eeb2adSek  * Process the buffer of nvlists, unpacking and storing each nvlist record
391906eeb2adSek  * into 'records'.  'leftover' is set to the number of bytes that weren't
392006eeb2adSek  * processed as there wasn't a complete record.
392106eeb2adSek  */
39228f18d1faSGeorge Wilson int
392306eeb2adSek zpool_history_unpack(char *buf, uint64_t bytes_read, uint64_t *leftover,
392406eeb2adSek     nvlist_t ***records, uint_t *numrecords)
392506eeb2adSek {
392606eeb2adSek 	uint64_t reclen;
392706eeb2adSek 	nvlist_t *nv;
392806eeb2adSek 	int i;
392906eeb2adSek 
393006eeb2adSek 	while (bytes_read > sizeof (reclen)) {
393106eeb2adSek 
393206eeb2adSek 		/* get length of packed record (stored as little endian) */
393306eeb2adSek 		for (i = 0, reclen = 0; i < sizeof (reclen); i++)
393406eeb2adSek 			reclen += (uint64_t)(((uchar_t *)buf)[i]) << (8*i);
393506eeb2adSek 
393606eeb2adSek 		if (bytes_read < sizeof (reclen) + reclen)
393706eeb2adSek 			break;
393806eeb2adSek 
393906eeb2adSek 		/* unpack record */
394006eeb2adSek 		if (nvlist_unpack(buf + sizeof (reclen), reclen, &nv, 0) != 0)
394106eeb2adSek 			return (ENOMEM);
394206eeb2adSek 		bytes_read -= sizeof (reclen) + reclen;
394306eeb2adSek 		buf += sizeof (reclen) + reclen;
394406eeb2adSek 
394506eeb2adSek 		/* add record to nvlist array */
394606eeb2adSek 		(*numrecords)++;
394706eeb2adSek 		if (ISP2(*numrecords + 1)) {
394806eeb2adSek 			*records = realloc(*records,
394906eeb2adSek 			    *numrecords * 2 * sizeof (nvlist_t *));
395006eeb2adSek 		}
395106eeb2adSek 		(*records)[*numrecords - 1] = nv;
395206eeb2adSek 	}
395306eeb2adSek 
395406eeb2adSek 	*leftover = bytes_read;
395506eeb2adSek 	return (0);
395606eeb2adSek }
395706eeb2adSek 
395806eeb2adSek /*
395906eeb2adSek  * Retrieve the command history of a pool.
396006eeb2adSek  */
396106eeb2adSek int
396206eeb2adSek zpool_get_history(zpool_handle_t *zhp, nvlist_t **nvhisp)
396306eeb2adSek {
39643339867aSMatthew Ahrens 	char *buf;
39653339867aSMatthew Ahrens 	int buflen = 128 * 1024;
396606eeb2adSek 	uint64_t off = 0;
396706eeb2adSek 	nvlist_t **records = NULL;
396806eeb2adSek 	uint_t numrecords = 0;
396906eeb2adSek 	int err, i;
397006eeb2adSek 
39713339867aSMatthew Ahrens 	buf = malloc(buflen);
39723339867aSMatthew Ahrens 	if (buf == NULL)
39733339867aSMatthew Ahrens 		return (ENOMEM);
397406eeb2adSek 	do {
39753339867aSMatthew Ahrens 		uint64_t bytes_read = buflen;
397606eeb2adSek 		uint64_t leftover;
397706eeb2adSek 
397806eeb2adSek 		if ((err = get_history(zhp, buf, &off, &bytes_read)) != 0)
397906eeb2adSek 			break;
398006eeb2adSek 
398106eeb2adSek 		/* if nothing else was read in, we're at EOF, just return */
398206eeb2adSek 		if (!bytes_read)
398306eeb2adSek 			break;
398406eeb2adSek 
398506eeb2adSek 		if ((err = zpool_history_unpack(buf, bytes_read,
398606eeb2adSek 		    &leftover, &records, &numrecords)) != 0)
398706eeb2adSek 			break;
398806eeb2adSek 		off -= leftover;
39893339867aSMatthew Ahrens 		if (leftover == bytes_read) {
39903339867aSMatthew Ahrens 			/*
39913339867aSMatthew Ahrens 			 * no progress made, because buffer is not big enough
39923339867aSMatthew Ahrens 			 * to hold this record; resize and retry.
39933339867aSMatthew Ahrens 			 */
39943339867aSMatthew Ahrens 			buflen *= 2;
39953339867aSMatthew Ahrens 			free(buf);
39963339867aSMatthew Ahrens 			buf = malloc(buflen);
39973339867aSMatthew Ahrens 			if (buf == NULL)
39983339867aSMatthew Ahrens 				return (ENOMEM);
39993339867aSMatthew Ahrens 		}
400006eeb2adSek 
400106eeb2adSek 		/* CONSTCOND */
400206eeb2adSek 	} while (1);
400306eeb2adSek 
40043339867aSMatthew Ahrens 	free(buf);
40053339867aSMatthew Ahrens 
400606eeb2adSek 	if (!err) {
400706eeb2adSek 		verify(nvlist_alloc(nvhisp, NV_UNIQUE_NAME, 0) == 0);
400806eeb2adSek 		verify(nvlist_add_nvlist_array(*nvhisp, ZPOOL_HIST_RECORD,
400906eeb2adSek 		    records, numrecords) == 0);
401006eeb2adSek 	}
401106eeb2adSek 	for (i = 0; i < numrecords; i++)
401206eeb2adSek 		nvlist_free(records[i]);
401306eeb2adSek 	free(records);
401406eeb2adSek 
401506eeb2adSek 	return (err);
401606eeb2adSek }
401755434c77Sek 
401855434c77Sek void
401955434c77Sek zpool_obj_to_path(zpool_handle_t *zhp, uint64_t dsobj, uint64_t obj,
402055434c77Sek     char *pathname, size_t len)
402155434c77Sek {
402255434c77Sek 	zfs_cmd_t zc = { 0 };
402355434c77Sek 	boolean_t mounted = B_FALSE;
402455434c77Sek 	char *mntpnt = NULL;
40259adfa60dSMatthew Ahrens 	char dsname[ZFS_MAX_DATASET_NAME_LEN];
402655434c77Sek 
402755434c77Sek 	if (dsobj == 0) {
402855434c77Sek 		/* special case for the MOS */
402955434c77Sek 		(void) snprintf(pathname, len, "<metadata>:<0x%llx>", obj);
403055434c77Sek 		return;
403155434c77Sek 	}
403255434c77Sek 
403355434c77Sek 	/* get the dataset's name */
403455434c77Sek 	(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
403555434c77Sek 	zc.zc_obj = dsobj;
403655434c77Sek 	if (ioctl(zhp->zpool_hdl->libzfs_fd,
403755434c77Sek 	    ZFS_IOC_DSOBJ_TO_DSNAME, &zc) != 0) {
403855434c77Sek 		/* just write out a path of two object numbers */
403955434c77Sek 		(void) snprintf(pathname, len, "<0x%llx>:<0x%llx>",
404055434c77Sek 		    dsobj, obj);
404155434c77Sek 		return;
404255434c77Sek 	}
404355434c77Sek 	(void) strlcpy(dsname, zc.zc_value, sizeof (dsname));
404455434c77Sek 
404555434c77Sek 	/* find out if the dataset is mounted */
404655434c77Sek 	mounted = is_mounted(zhp->zpool_hdl, dsname, &mntpnt);
404755434c77Sek 
404855434c77Sek 	/* get the corrupted object's path */
404955434c77Sek 	(void) strlcpy(zc.zc_name, dsname, sizeof (zc.zc_name));
405055434c77Sek 	zc.zc_obj = obj;
405155434c77Sek 	if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_OBJ_TO_PATH,
405255434c77Sek 	    &zc) == 0) {
405355434c77Sek 		if (mounted) {
405455434c77Sek 			(void) snprintf(pathname, len, "%s%s", mntpnt,
405555434c77Sek 			    zc.zc_value);
405655434c77Sek 		} else {
405755434c77Sek 			(void) snprintf(pathname, len, "%s:%s",
405855434c77Sek 			    dsname, zc.zc_value);
405955434c77Sek 		}
406055434c77Sek 	} else {
406155434c77Sek 		(void) snprintf(pathname, len, "%s:<0x%llx>", dsname, obj);
406255434c77Sek 	}
406355434c77Sek 	free(mntpnt);
406455434c77Sek }
4065b1b8ab34Slling 
406615e6edf1Sgw /*
406715e6edf1Sgw  * Read the EFI label from the config, if a label does not exist then
406815e6edf1Sgw  * pass back the error to the caller. If the caller has passed a non-NULL
406915e6edf1Sgw  * diskaddr argument then we set it to the starting address of the EFI
40707855d95bSToomas Soome  * partition. If the caller has passed a non-NULL boolean argument, then
40717855d95bSToomas Soome  * we set it to indicate if the disk does have efi system partition.
407215e6edf1Sgw  */
407315e6edf1Sgw static int
40747855d95bSToomas Soome read_efi_label(nvlist_t *config, diskaddr_t *sb, boolean_t *system)
407515e6edf1Sgw {
407615e6edf1Sgw 	char *path;
407715e6edf1Sgw 	int fd;
407815e6edf1Sgw 	char diskname[MAXPATHLEN];
40797855d95bSToomas Soome 	boolean_t boot = B_FALSE;
408015e6edf1Sgw 	int err = -1;
40817855d95bSToomas Soome 	int slice;
408215e6edf1Sgw 
408315e6edf1Sgw 	if (nvlist_lookup_string(config, ZPOOL_CONFIG_PATH, &path) != 0)
408415e6edf1Sgw 		return (err);
408515e6edf1Sgw 
40866401734dSWill Andrews 	(void) snprintf(diskname, sizeof (diskname), "%s%s", ZFS_RDISK_ROOT,
408715e6edf1Sgw 	    strrchr(path, '/'));
408815e6edf1Sgw 	if ((fd = open(diskname, O_RDONLY|O_NDELAY)) >= 0) {
408915e6edf1Sgw 		struct dk_gpt *vtoc;
409015e6edf1Sgw 
409115e6edf1Sgw 		if ((err = efi_alloc_and_read(fd, &vtoc)) >= 0) {
40927855d95bSToomas Soome 			for (slice = 0; slice < vtoc->efi_nparts; slice++) {
40937855d95bSToomas Soome 				if (vtoc->efi_parts[slice].p_tag == V_SYSTEM)
40947855d95bSToomas Soome 					boot = B_TRUE;
40957855d95bSToomas Soome 				if (vtoc->efi_parts[slice].p_tag == V_USR)
40967855d95bSToomas Soome 					break;
40977855d95bSToomas Soome 			}
40987855d95bSToomas Soome 			if (sb != NULL && vtoc->efi_parts[slice].p_tag == V_USR)
40997855d95bSToomas Soome 				*sb = vtoc->efi_parts[slice].p_start;
41007855d95bSToomas Soome 			if (system != NULL)
41017855d95bSToomas Soome 				*system = boot;
410215e6edf1Sgw 			efi_free(vtoc);
410315e6edf1Sgw 		}
410415e6edf1Sgw 		(void) close(fd);
410515e6edf1Sgw 	}
410615e6edf1Sgw 	return (err);
410715e6edf1Sgw }
410815e6edf1Sgw 
41098488aeb5Staylor /*
41108488aeb5Staylor  * determine where a partition starts on a disk in the current
41118488aeb5Staylor  * configuration
41128488aeb5Staylor  */
41138488aeb5Staylor static diskaddr_t
41148488aeb5Staylor find_start_block(nvlist_t *config)
41158488aeb5Staylor {
41168488aeb5Staylor 	nvlist_t **child;
41178488aeb5Staylor 	uint_t c, children;
41188488aeb5Staylor 	diskaddr_t sb = MAXOFFSET_T;
41198488aeb5Staylor 	uint64_t wholedisk;
41208488aeb5Staylor 
41218488aeb5Staylor 	if (nvlist_lookup_nvlist_array(config,
41228488aeb5Staylor 	    ZPOOL_CONFIG_CHILDREN, &child, &children) != 0) {
41238488aeb5Staylor 		if (nvlist_lookup_uint64(config,
41248488aeb5Staylor 		    ZPOOL_CONFIG_WHOLE_DISK,
41258488aeb5Staylor 		    &wholedisk) != 0 || !wholedisk) {
41268488aeb5Staylor 			return (MAXOFFSET_T);
41278488aeb5Staylor 		}
41287855d95bSToomas Soome 		if (read_efi_label(config, &sb, NULL) < 0)
412915e6edf1Sgw 			sb = MAXOFFSET_T;
41308488aeb5Staylor 		return (sb);
41318488aeb5Staylor 	}
41328488aeb5Staylor 
41338488aeb5Staylor 	for (c = 0; c < children; c++) {
41348488aeb5Staylor 		sb = find_start_block(child[c]);
41358488aeb5Staylor 		if (sb != MAXOFFSET_T) {
41368488aeb5Staylor 			return (sb);
41378488aeb5Staylor 		}
41388488aeb5Staylor 	}
41398488aeb5Staylor 	return (MAXOFFSET_T);
41408488aeb5Staylor }
41418488aeb5Staylor 
41428488aeb5Staylor /*
41438488aeb5Staylor  * Label an individual disk.  The name provided is the short name,
41448488aeb5Staylor  * stripped of any leading /dev path.
41458488aeb5Staylor  */
41468488aeb5Staylor int
41477855d95bSToomas Soome zpool_label_disk(libzfs_handle_t *hdl, zpool_handle_t *zhp, const char *name,
41487855d95bSToomas Soome     zpool_boot_label_t boot_type, uint64_t boot_size, int *slice)
41498488aeb5Staylor {
41508488aeb5Staylor 	char path[MAXPATHLEN];
41518488aeb5Staylor 	struct dk_gpt *vtoc;
41528488aeb5Staylor 	int fd;
41538488aeb5Staylor 	size_t resv = EFI_MIN_RESV_SIZE;
41548488aeb5Staylor 	uint64_t slice_size;
41558488aeb5Staylor 	diskaddr_t start_block;
41568488aeb5Staylor 	char errbuf[1024];
41578488aeb5Staylor 
4158c6ef114fSmmusante 	/* prepare an error message just in case */
4159c6ef114fSmmusante 	(void) snprintf(errbuf, sizeof (errbuf),
4160c6ef114fSmmusante 	    dgettext(TEXT_DOMAIN, "cannot label '%s'"), name);
4161c6ef114fSmmusante 
41628488aeb5Staylor 	if (zhp) {
41638488aeb5Staylor 		nvlist_t *nvroot;
41648488aeb5Staylor 
41658488aeb5Staylor 		verify(nvlist_lookup_nvlist(zhp->zpool_config,
41668488aeb5Staylor 		    ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
41678488aeb5Staylor 
41688488aeb5Staylor 		if (zhp->zpool_start_block == 0)
41698488aeb5Staylor 			start_block = find_start_block(nvroot);
41708488aeb5Staylor 		else
41718488aeb5Staylor 			start_block = zhp->zpool_start_block;
41728488aeb5Staylor 		zhp->zpool_start_block = start_block;
41738488aeb5Staylor 	} else {
41748488aeb5Staylor 		/* new pool */
41758488aeb5Staylor 		start_block = NEW_START_BLOCK;
41768488aeb5Staylor 	}
41778488aeb5Staylor 
41786401734dSWill Andrews 	(void) snprintf(path, sizeof (path), "%s/%s%s", ZFS_RDISK_ROOT, name,
41798488aeb5Staylor 	    BACKUP_SLICE);
41808488aeb5Staylor 
41818488aeb5Staylor 	if ((fd = open(path, O_RDWR | O_NDELAY)) < 0) {
41828488aeb5Staylor 		/*
41838488aeb5Staylor 		 * This shouldn't happen.  We've long since verified that this
41848488aeb5Staylor 		 * is a valid device.
41858488aeb5Staylor 		 */
4186c6ef114fSmmusante 		zfs_error_aux(hdl,
4187c6ef114fSmmusante 		    dgettext(TEXT_DOMAIN, "unable to open device"));
41888488aeb5Staylor 		return (zfs_error(hdl, EZFS_OPENFAILED, errbuf));
41898488aeb5Staylor 	}
41908488aeb5Staylor 
41918488aeb5Staylor 	if (efi_alloc_and_init(fd, EFI_NUMPAR, &vtoc) != 0) {
41928488aeb5Staylor 		/*
41938488aeb5Staylor 		 * The only way this can fail is if we run out of memory, or we
41948488aeb5Staylor 		 * were unable to read the disk's capacity
41958488aeb5Staylor 		 */
41968488aeb5Staylor 		if (errno == ENOMEM)
41978488aeb5Staylor 			(void) no_memory(hdl);
41988488aeb5Staylor 
41998488aeb5Staylor 		(void) close(fd);
4200c6ef114fSmmusante 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4201c6ef114fSmmusante 		    "unable to read disk capacity"), name);
42028488aeb5Staylor 
42038488aeb5Staylor 		return (zfs_error(hdl, EZFS_NOCAP, errbuf));
42048488aeb5Staylor 	}
42058488aeb5Staylor 
42068488aeb5Staylor 	/*
42078488aeb5Staylor 	 * Why we use V_USR: V_BACKUP confuses users, and is considered
42088488aeb5Staylor 	 * disposable by some EFI utilities (since EFI doesn't have a backup
42098488aeb5Staylor 	 * slice).  V_UNASSIGNED is supposed to be used only for zero size
42108488aeb5Staylor 	 * partitions, and efi_write() will fail if we use it.  V_ROOT, V_BOOT,
42118488aeb5Staylor 	 * etc. were all pretty specific.  V_USR is as close to reality as we
42128488aeb5Staylor 	 * can get, in the absence of V_OTHER.
42138488aeb5Staylor 	 */
42147855d95bSToomas Soome 	/* first fix the partition start block */
42157855d95bSToomas Soome 	if (start_block == MAXOFFSET_T)
42167855d95bSToomas Soome 		start_block = NEW_START_BLOCK;
42178488aeb5Staylor 
42187855d95bSToomas Soome 	/*
42197855d95bSToomas Soome 	 * EFI System partition is using slice 0.
42207855d95bSToomas Soome 	 * ZFS is on slice 1 and slice 8 is reserved.
42217855d95bSToomas Soome 	 * We assume the GPT partition table without system
42227855d95bSToomas Soome 	 * partition has zfs p_start == NEW_START_BLOCK.
42237855d95bSToomas Soome 	 * If start_block != NEW_START_BLOCK, it means we have
42247855d95bSToomas Soome 	 * system partition. Correct solution would be to query/cache vtoc
42257855d95bSToomas Soome 	 * from existing vdev member.
42267855d95bSToomas Soome 	 */
42277855d95bSToomas Soome 	if (boot_type == ZPOOL_CREATE_BOOT_LABEL) {
42287855d95bSToomas Soome 		if (boot_size % vtoc->efi_lbasize != 0) {
42297855d95bSToomas Soome 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
42307855d95bSToomas Soome 			    "boot partition size must be a multiple of %d"),
42317855d95bSToomas Soome 			    vtoc->efi_lbasize);
42327855d95bSToomas Soome 			(void) close(fd);
42337855d95bSToomas Soome 			efi_free(vtoc);
42347855d95bSToomas Soome 			return (zfs_error(hdl, EZFS_LABELFAILED, errbuf));
42357855d95bSToomas Soome 		}
42367855d95bSToomas Soome 		/*
42377855d95bSToomas Soome 		 * System partition size checks.
42387855d95bSToomas Soome 		 * Note the 1MB is quite arbitrary value, since we
42397855d95bSToomas Soome 		 * are creating dedicated pool, it should be enough
42407855d95bSToomas Soome 		 * to hold fat + efi bootloader. May need to be
42417855d95bSToomas Soome 		 * adjusted if the bootloader size will grow.
42427855d95bSToomas Soome 		 */
42437855d95bSToomas Soome 		if (boot_size < 1024 * 1024) {
42447855d95bSToomas Soome 			char buf[64];
42457855d95bSToomas Soome 			zfs_nicenum(boot_size, buf, sizeof (buf));
42467855d95bSToomas Soome 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
42477855d95bSToomas Soome 			    "Specified size %s for EFI System partition is too "
42487855d95bSToomas Soome 			    "small, the minimum size is 1MB."), buf);
42497855d95bSToomas Soome 			(void) close(fd);
42507855d95bSToomas Soome 			efi_free(vtoc);
42517855d95bSToomas Soome 			return (zfs_error(hdl, EZFS_LABELFAILED, errbuf));
42527855d95bSToomas Soome 		}
42537855d95bSToomas Soome 		/* 33MB is tested with mkfs -F pcfs */
42547855d95bSToomas Soome 		if (hdl->libzfs_printerr &&
42557855d95bSToomas Soome 		    ((vtoc->efi_lbasize == 512 &&
42567855d95bSToomas Soome 		    boot_size < 33 * 1024 * 1024) ||
42577855d95bSToomas Soome 		    (vtoc->efi_lbasize == 4096 &&
42587855d95bSToomas Soome 		    boot_size < 256 * 1024 * 1024)))  {
42597855d95bSToomas Soome 			char buf[64];
42607855d95bSToomas Soome 			zfs_nicenum(boot_size, buf, sizeof (buf));
42617855d95bSToomas Soome 			(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
42627855d95bSToomas Soome 			    "Warning: EFI System partition size %s is "
42637855d95bSToomas Soome 			    "not allowing to create FAT32 file\nsystem, which "
42647855d95bSToomas Soome 			    "may result in unbootable system.\n"), buf);
42657855d95bSToomas Soome 		}
42667855d95bSToomas Soome 		/* Adjust zfs partition start by size of system partition. */
42677855d95bSToomas Soome 		start_block += boot_size / vtoc->efi_lbasize;
42687855d95bSToomas Soome 	}
42697855d95bSToomas Soome 
42707855d95bSToomas Soome 	if (start_block == NEW_START_BLOCK) {
42717855d95bSToomas Soome 		/*
42727855d95bSToomas Soome 		 * Use default layout.
42737855d95bSToomas Soome 		 * ZFS is on slice 0 and slice 8 is reserved.
42747855d95bSToomas Soome 		 */
42757855d95bSToomas Soome 		slice_size = vtoc->efi_last_u_lba + 1;
42767855d95bSToomas Soome 		slice_size -= EFI_MIN_RESV_SIZE;
42777855d95bSToomas Soome 		slice_size -= start_block;
42787855d95bSToomas Soome 		if (slice != NULL)
42797855d95bSToomas Soome 			*slice = 0;
42807855d95bSToomas Soome 
42817855d95bSToomas Soome 		vtoc->efi_parts[0].p_start = start_block;
42827855d95bSToomas Soome 		vtoc->efi_parts[0].p_size = slice_size;
42837855d95bSToomas Soome 
42847855d95bSToomas Soome 		vtoc->efi_parts[0].p_tag = V_USR;
42857855d95bSToomas Soome 		(void) strcpy(vtoc->efi_parts[0].p_name, "zfs");
42867855d95bSToomas Soome 
42877855d95bSToomas Soome 		vtoc->efi_parts[8].p_start = slice_size + start_block;
42887855d95bSToomas Soome 		vtoc->efi_parts[8].p_size = resv;
42897855d95bSToomas Soome 		vtoc->efi_parts[8].p_tag = V_RESERVED;
42907855d95bSToomas Soome 	} else {
42917855d95bSToomas Soome 		slice_size = start_block - NEW_START_BLOCK;
42927855d95bSToomas Soome 		vtoc->efi_parts[0].p_start = NEW_START_BLOCK;
42937855d95bSToomas Soome 		vtoc->efi_parts[0].p_size = slice_size;
42947855d95bSToomas Soome 		vtoc->efi_parts[0].p_tag = V_SYSTEM;
42957855d95bSToomas Soome 		(void) strcpy(vtoc->efi_parts[0].p_name, "loader");
42967855d95bSToomas Soome 		if (slice != NULL)
42977855d95bSToomas Soome 			*slice = 1;
42987855d95bSToomas Soome 		/* prepare slice 1 */
42997855d95bSToomas Soome 		slice_size = vtoc->efi_last_u_lba + 1 - slice_size;
43007855d95bSToomas Soome 		slice_size -= resv;
43017855d95bSToomas Soome 		slice_size -= NEW_START_BLOCK;
43027855d95bSToomas Soome 		vtoc->efi_parts[1].p_start = start_block;
43037855d95bSToomas Soome 		vtoc->efi_parts[1].p_size = slice_size;
43047855d95bSToomas Soome 		vtoc->efi_parts[1].p_tag = V_USR;
43057855d95bSToomas Soome 		(void) strcpy(vtoc->efi_parts[1].p_name, "zfs");
43067855d95bSToomas Soome 
43077855d95bSToomas Soome 		vtoc->efi_parts[8].p_start = slice_size + start_block;
43087855d95bSToomas Soome 		vtoc->efi_parts[8].p_size = resv;
43097855d95bSToomas Soome 		vtoc->efi_parts[8].p_tag = V_RESERVED;
43107855d95bSToomas Soome 	}
43118488aeb5Staylor 
43128488aeb5Staylor 	if (efi_write(fd, vtoc) != 0) {
43138488aeb5Staylor 		/*
43148488aeb5Staylor 		 * Some block drivers (like pcata) may not support EFI
43158488aeb5Staylor 		 * GPT labels.  Print out a helpful error message dir-
43168488aeb5Staylor 		 * ecting the user to manually label the disk and give
43178488aeb5Staylor 		 * a specific slice.
43188488aeb5Staylor 		 */
43198488aeb5Staylor 		(void) close(fd);
43208488aeb5Staylor 		efi_free(vtoc);
43218488aeb5Staylor 
43228488aeb5Staylor 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4323c6ef114fSmmusante 		    "try using fdisk(1M) and then provide a specific slice"));
43248488aeb5Staylor 		return (zfs_error(hdl, EZFS_LABELFAILED, errbuf));
43258488aeb5Staylor 	}
43268488aeb5Staylor 
43278488aeb5Staylor 	(void) close(fd);
43288488aeb5Staylor 	efi_free(vtoc);
43298488aeb5Staylor 	return (0);
43308488aeb5Staylor }
4331e7cbe64fSgw 
4332e7cbe64fSgw static boolean_t
4333e7cbe64fSgw supported_dump_vdev_type(libzfs_handle_t *hdl, nvlist_t *config, char *errbuf)
4334e7cbe64fSgw {
4335e7cbe64fSgw 	char *type;
4336e7cbe64fSgw 	nvlist_t **child;
4337e7cbe64fSgw 	uint_t children, c;
4338e7cbe64fSgw 
4339e7cbe64fSgw 	verify(nvlist_lookup_string(config, ZPOOL_CONFIG_TYPE, &type) == 0);
4340810e43b2SBill Pijewski 	if (strcmp(type, VDEV_TYPE_FILE) == 0 ||
434188ecc943SGeorge Wilson 	    strcmp(type, VDEV_TYPE_HOLE) == 0 ||
4342e7cbe64fSgw 	    strcmp(type, VDEV_TYPE_MISSING) == 0) {
4343e7cbe64fSgw 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4344e7cbe64fSgw 		    "vdev type '%s' is not supported"), type);
4345e7cbe64fSgw 		(void) zfs_error(hdl, EZFS_VDEVNOTSUP, errbuf);
4346e7cbe64fSgw 		return (B_FALSE);
4347e7cbe64fSgw 	}
4348e7cbe64fSgw 	if (nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_CHILDREN,
4349e7cbe64fSgw 	    &child, &children) == 0) {
4350e7cbe64fSgw 		for (c = 0; c < children; c++) {
4351e7cbe64fSgw 			if (!supported_dump_vdev_type(hdl, child[c], errbuf))
4352e7cbe64fSgw 				return (B_FALSE);
4353e7cbe64fSgw 		}
4354e7cbe64fSgw 	}
4355e7cbe64fSgw 	return (B_TRUE);
4356e7cbe64fSgw }
4357e7cbe64fSgw 
4358e7cbe64fSgw /*
4359810e43b2SBill Pijewski  * Check if this zvol is allowable for use as a dump device; zero if
4360810e43b2SBill Pijewski  * it is, > 0 if it isn't, < 0 if it isn't a zvol.
4361810e43b2SBill Pijewski  *
4362810e43b2SBill Pijewski  * Allowable storage configurations include mirrors, all raidz variants, and
4363810e43b2SBill Pijewski  * pools with log, cache, and spare devices.  Pools which are backed by files or
4364810e43b2SBill Pijewski  * have missing/hole vdevs are not suitable.
4365e7cbe64fSgw  */
4366e7cbe64fSgw int
4367e7cbe64fSgw zvol_check_dump_config(char *arg)
4368e7cbe64fSgw {
4369e7cbe64fSgw 	zpool_handle_t *zhp = NULL;
4370e7cbe64fSgw 	nvlist_t *config, *nvroot;
4371e7cbe64fSgw 	char *p, *volname;
4372e7cbe64fSgw 	nvlist_t **top;
4373e7cbe64fSgw 	uint_t toplevels;
4374e7cbe64fSgw 	libzfs_handle_t *hdl;
4375e7cbe64fSgw 	char errbuf[1024];
43769adfa60dSMatthew Ahrens 	char poolname[ZFS_MAX_DATASET_NAME_LEN];
4377e7cbe64fSgw 	int pathlen = strlen(ZVOL_FULL_DEV_DIR);
4378e7cbe64fSgw 	int ret = 1;
4379e7cbe64fSgw 
4380e7cbe64fSgw 	if (strncmp(arg, ZVOL_FULL_DEV_DIR, pathlen)) {
4381e7cbe64fSgw 		return (-1);
4382e7cbe64fSgw 	}
4383e7cbe64fSgw 
4384e7cbe64fSgw 	(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
4385e7cbe64fSgw 	    "dump is not supported on device '%s'"), arg);
4386e7cbe64fSgw 
4387e7cbe64fSgw 	if ((hdl = libzfs_init()) == NULL)
4388e7cbe64fSgw 		return (1);
4389e7cbe64fSgw 	libzfs_print_on_error(hdl, B_TRUE);
4390e7cbe64fSgw 
4391e7cbe64fSgw 	volname = arg + pathlen;
4392e7cbe64fSgw 
4393e7cbe64fSgw 	/* check the configuration of the pool */
4394e7cbe64fSgw 	if ((p = strchr(volname, '/')) == NULL) {
4395e7cbe64fSgw 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4396e7cbe64fSgw 		    "malformed dataset name"));
4397e7cbe64fSgw 		(void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf);
4398e7cbe64fSgw 		return (1);
43999adfa60dSMatthew Ahrens 	} else if (p - volname >= ZFS_MAX_DATASET_NAME_LEN) {
4400e7cbe64fSgw 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4401e7cbe64fSgw 		    "dataset name is too long"));
4402e7cbe64fSgw 		(void) zfs_error(hdl, EZFS_NAMETOOLONG, errbuf);
4403e7cbe64fSgw 		return (1);
4404e7cbe64fSgw 	} else {
4405e7cbe64fSgw 		(void) strncpy(poolname, volname, p - volname);
4406e7cbe64fSgw 		poolname[p - volname] = '\0';
4407e7cbe64fSgw 	}
4408e7cbe64fSgw 
4409e7cbe64fSgw 	if ((zhp = zpool_open(hdl, poolname)) == NULL) {
4410e7cbe64fSgw 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4411e7cbe64fSgw 		    "could not open pool '%s'"), poolname);
4412e7cbe64fSgw 		(void) zfs_error(hdl, EZFS_OPENFAILED, errbuf);
4413e7cbe64fSgw 		goto out;
4414e7cbe64fSgw 	}
4415e7cbe64fSgw 	config = zpool_get_config(zhp, NULL);
4416e7cbe64fSgw 	if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
4417e7cbe64fSgw 	    &nvroot) != 0) {
4418e7cbe64fSgw 		zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4419e7cbe64fSgw 		    "could not obtain vdev configuration for  '%s'"), poolname);
4420e7cbe64fSgw 		(void) zfs_error(hdl, EZFS_INVALCONFIG, errbuf);
4421e7cbe64fSgw 		goto out;
4422e7cbe64fSgw 	}
4423e7cbe64fSgw 
4424e7cbe64fSgw 	verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
4425e7cbe64fSgw 	    &top, &toplevels) == 0);
4426e7cbe64fSgw 
4427e7cbe64fSgw 	if (!supported_dump_vdev_type(hdl, top[0], errbuf)) {
4428e7cbe64fSgw 		goto out;
4429e7cbe64fSgw 	}
4430e7cbe64fSgw 	ret = 0;
4431e7cbe64fSgw 
4432e7cbe64fSgw out:
4433e7cbe64fSgw 	if (zhp)
4434e7cbe64fSgw 		zpool_close(zhp);
4435e7cbe64fSgw 	libzfs_fini(hdl);
4436e7cbe64fSgw 	return (ret);
4437e7cbe64fSgw }
4438