1f169c0eaSGlenn Lagasse /*
2f169c0eaSGlenn Lagasse  * CDDL HEADER START
3f169c0eaSGlenn Lagasse  *
4f169c0eaSGlenn Lagasse  * The contents of this file are subject to the terms of the
5f169c0eaSGlenn Lagasse  * Common Development and Distribution License (the "License").
6f169c0eaSGlenn Lagasse  * You may not use this file except in compliance with the License.
7f169c0eaSGlenn Lagasse  *
8f169c0eaSGlenn Lagasse  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9f169c0eaSGlenn Lagasse  * or http://www.opensolaris.org/os/licensing.
10f169c0eaSGlenn Lagasse  * See the License for the specific language governing permissions
11f169c0eaSGlenn Lagasse  * and limitations under the License.
12f169c0eaSGlenn Lagasse  *
13f169c0eaSGlenn Lagasse  * When distributing Covered Code, include this CDDL HEADER in each
14f169c0eaSGlenn Lagasse  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15f169c0eaSGlenn Lagasse  * If applicable, add the following below this CDDL HEADER, with the
16f169c0eaSGlenn Lagasse  * fields enclosed by brackets "[]" replaced with your own identifying
17f169c0eaSGlenn Lagasse  * information: Portions Copyright [yyyy] [name of copyright owner]
18f169c0eaSGlenn Lagasse  *
19f169c0eaSGlenn Lagasse  * CDDL HEADER END
20f169c0eaSGlenn Lagasse  */
21f169c0eaSGlenn Lagasse 
22f169c0eaSGlenn Lagasse /*
23f169c0eaSGlenn Lagasse  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24f169c0eaSGlenn Lagasse  */
25f169c0eaSGlenn Lagasse 
26de1ab35cSAlexander Eremin /*
27*7e0e2549SAlexander Eremin  * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
28de1ab35cSAlexander Eremin  */
29de1ab35cSAlexander Eremin 
30f169c0eaSGlenn Lagasse /*
31f169c0eaSGlenn Lagasse  * System includes
32f169c0eaSGlenn Lagasse  */
33f169c0eaSGlenn Lagasse 
34f169c0eaSGlenn Lagasse #include <assert.h>
35f169c0eaSGlenn Lagasse #include <ctype.h>
36f169c0eaSGlenn Lagasse #include <errno.h>
37f169c0eaSGlenn Lagasse #include <libgen.h>
38f169c0eaSGlenn Lagasse #include <libintl.h>
39f169c0eaSGlenn Lagasse #include <libnvpair.h>
40f169c0eaSGlenn Lagasse #include <libzfs.h>
41f169c0eaSGlenn Lagasse #include <stdio.h>
42f169c0eaSGlenn Lagasse #include <stdlib.h>
43f169c0eaSGlenn Lagasse #include <string.h>
44f169c0eaSGlenn Lagasse #include <sys/mnttab.h>
45f169c0eaSGlenn Lagasse #include <sys/mount.h>
46f169c0eaSGlenn Lagasse #include <sys/stat.h>
47f169c0eaSGlenn Lagasse #include <sys/types.h>
48f169c0eaSGlenn Lagasse #include <sys/wait.h>
49f169c0eaSGlenn Lagasse #include <unistd.h>
50f169c0eaSGlenn Lagasse 
51f169c0eaSGlenn Lagasse #include <libbe.h>
52f169c0eaSGlenn Lagasse #include <libbe_priv.h>
53f169c0eaSGlenn Lagasse 
54f169c0eaSGlenn Lagasse /* Library wide variables */
55f169c0eaSGlenn Lagasse libzfs_handle_t *g_zfs = NULL;
56f169c0eaSGlenn Lagasse 
57f169c0eaSGlenn Lagasse /* Private function prototypes */
58f169c0eaSGlenn Lagasse static int _be_destroy(const char *, be_destroy_data_t *);
59f169c0eaSGlenn Lagasse static int be_destroy_zones(char *, char *, be_destroy_data_t *);
60f169c0eaSGlenn Lagasse static int be_destroy_zone_roots(char *, be_destroy_data_t *);
61f169c0eaSGlenn Lagasse static int be_destroy_zone_roots_callback(zfs_handle_t *, void *);
62f169c0eaSGlenn Lagasse static int be_copy_zones(char *, char *, char *);
63f169c0eaSGlenn Lagasse static int be_clone_fs_callback(zfs_handle_t *, void *);
64f169c0eaSGlenn Lagasse static int be_destroy_callback(zfs_handle_t *, void *);
65f169c0eaSGlenn Lagasse static int be_send_fs_callback(zfs_handle_t *, void *);
66f169c0eaSGlenn Lagasse static int be_demote_callback(zfs_handle_t *, void *);
67f169c0eaSGlenn Lagasse static int be_demote_find_clone_callback(zfs_handle_t *, void *);
685ee7c793SAlexander Eremin static int be_has_snapshot_callback(zfs_handle_t *, void *);
69f169c0eaSGlenn Lagasse static int be_demote_get_one_clone(zfs_handle_t *, void *);
70f169c0eaSGlenn Lagasse static int be_get_snap(char *, char **);
71f169c0eaSGlenn Lagasse static int be_prep_clone_send_fs(zfs_handle_t *, be_transaction_data_t *,
72f169c0eaSGlenn Lagasse     char *, int);
73f169c0eaSGlenn Lagasse static boolean_t be_create_container_ds(char *);
74f169c0eaSGlenn Lagasse static char *be_get_zone_be_name(char *root_ds, char *container_ds);
75f169c0eaSGlenn Lagasse static int be_zone_root_exists_callback(zfs_handle_t *, void *);
76f169c0eaSGlenn Lagasse 
77f169c0eaSGlenn Lagasse /* ********************************************************************	*/
78f169c0eaSGlenn Lagasse /*			Public Functions				*/
79f169c0eaSGlenn Lagasse /* ********************************************************************	*/
80f169c0eaSGlenn Lagasse 
81f169c0eaSGlenn Lagasse /*
82f169c0eaSGlenn Lagasse  * Function:	be_init
83f169c0eaSGlenn Lagasse  * Description:	Creates the initial datasets for a BE and leaves them
84f169c0eaSGlenn Lagasse  *		unpopulated.  The resultant BE can be mounted but can't
85f169c0eaSGlenn Lagasse  *		yet be activated or booted.
86f169c0eaSGlenn Lagasse  * Parameters:
87f169c0eaSGlenn Lagasse  *		be_attrs - pointer to nvlist_t of attributes being passed in.
88f169c0eaSGlenn Lagasse  *			The following attributes are used by this function:
89f169c0eaSGlenn Lagasse  *
90f169c0eaSGlenn Lagasse  *			BE_ATTR_NEW_BE_NAME		*required
91f169c0eaSGlenn Lagasse  *			BE_ATTR_NEW_BE_POOL		*required
92f169c0eaSGlenn Lagasse  *			BE_ATTR_ZFS_PROPERTIES		*optional
93f169c0eaSGlenn Lagasse  *			BE_ATTR_FS_NAMES		*optional
94f169c0eaSGlenn Lagasse  *			BE_ATTR_FS_NUM			*optional
95f169c0eaSGlenn Lagasse  *			BE_ATTR_SHARED_FS_NAMES		*optional
96f169c0eaSGlenn Lagasse  *			BE_ATTR_SHARED_FS_NUM		*optional
97f169c0eaSGlenn Lagasse  * Return:
98f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
99f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
100f169c0eaSGlenn Lagasse  * Scope:
101f169c0eaSGlenn Lagasse  *		Public
102f169c0eaSGlenn Lagasse  */
103f169c0eaSGlenn Lagasse int
104f169c0eaSGlenn Lagasse be_init(nvlist_t *be_attrs)
105f169c0eaSGlenn Lagasse {
106f169c0eaSGlenn Lagasse 	be_transaction_data_t	bt = { 0 };
107f169c0eaSGlenn Lagasse 	zpool_handle_t	*zlp;
108f169c0eaSGlenn Lagasse 	nvlist_t	*zfs_props = NULL;
109f169c0eaSGlenn Lagasse 	char		nbe_root_ds[MAXPATHLEN];
110f169c0eaSGlenn Lagasse 	char		child_fs[MAXPATHLEN];
111f169c0eaSGlenn Lagasse 	char		**fs_names = NULL;
112f169c0eaSGlenn Lagasse 	char		**shared_fs_names = NULL;
113f169c0eaSGlenn Lagasse 	uint16_t	fs_num = 0;
114f169c0eaSGlenn Lagasse 	uint16_t	shared_fs_num = 0;
115f169c0eaSGlenn Lagasse 	int		nelem;
116f169c0eaSGlenn Lagasse 	int		i;
117f169c0eaSGlenn Lagasse 	int		zret = 0, ret = BE_SUCCESS;
118f169c0eaSGlenn Lagasse 
119f169c0eaSGlenn Lagasse 	/* Initialize libzfs handle */
120f169c0eaSGlenn Lagasse 	if (!be_zfs_init())
121f169c0eaSGlenn Lagasse 		return (BE_ERR_INIT);
122f169c0eaSGlenn Lagasse 
123f169c0eaSGlenn Lagasse 	/* Get new BE name */
124f169c0eaSGlenn Lagasse 	if (nvlist_lookup_string(be_attrs, BE_ATTR_NEW_BE_NAME, &bt.nbe_name)
125f169c0eaSGlenn Lagasse 	    != 0) {
126f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_init: failed to lookup "
127f169c0eaSGlenn Lagasse 		    "BE_ATTR_NEW_BE_NAME attribute\n"));
128f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
129f169c0eaSGlenn Lagasse 	}
130f169c0eaSGlenn Lagasse 
131f169c0eaSGlenn Lagasse 	/* Validate new BE name */
132f169c0eaSGlenn Lagasse 	if (!be_valid_be_name(bt.nbe_name)) {
133f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_init: invalid BE name %s\n"),
134f169c0eaSGlenn Lagasse 		    bt.nbe_name);
135f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
136f169c0eaSGlenn Lagasse 	}
137f169c0eaSGlenn Lagasse 
138f169c0eaSGlenn Lagasse 	/* Get zpool name */
139f169c0eaSGlenn Lagasse 	if (nvlist_lookup_string(be_attrs, BE_ATTR_NEW_BE_POOL, &bt.nbe_zpool)
140f169c0eaSGlenn Lagasse 	    != 0) {
141f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_init: failed to lookup "
142f169c0eaSGlenn Lagasse 		    "BE_ATTR_NEW_BE_POOL attribute\n"));
143f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
144f169c0eaSGlenn Lagasse 	}
145f169c0eaSGlenn Lagasse 
146f169c0eaSGlenn Lagasse 	/* Get file system attributes */
147f169c0eaSGlenn Lagasse 	nelem = 0;
148f169c0eaSGlenn Lagasse 	if (nvlist_lookup_pairs(be_attrs, 0,
149f169c0eaSGlenn Lagasse 	    BE_ATTR_FS_NUM, DATA_TYPE_UINT16, &fs_num,
150f169c0eaSGlenn Lagasse 	    BE_ATTR_FS_NAMES, DATA_TYPE_STRING_ARRAY, &fs_names, &nelem,
151f169c0eaSGlenn Lagasse 	    NULL) != 0) {
152f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_init: failed to lookup fs "
153f169c0eaSGlenn Lagasse 		    "attributes\n"));
154f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
155f169c0eaSGlenn Lagasse 	}
156f169c0eaSGlenn Lagasse 	if (nelem != fs_num) {
157f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_init: size of FS_NAMES array (%d) "
158f169c0eaSGlenn Lagasse 		    "does not match FS_NUM (%d)\n"), nelem, fs_num);
159f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
160f169c0eaSGlenn Lagasse 	}
161f169c0eaSGlenn Lagasse 
162f169c0eaSGlenn Lagasse 	/* Get shared file system attributes */
163f169c0eaSGlenn Lagasse 	nelem = 0;
164f169c0eaSGlenn Lagasse 	if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
165f169c0eaSGlenn Lagasse 	    BE_ATTR_SHARED_FS_NUM, DATA_TYPE_UINT16, &shared_fs_num,
166f169c0eaSGlenn Lagasse 	    BE_ATTR_SHARED_FS_NAMES, DATA_TYPE_STRING_ARRAY, &shared_fs_names,
167f169c0eaSGlenn Lagasse 	    &nelem, NULL) != 0) {
168f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_init: failed to lookup "
169f169c0eaSGlenn Lagasse 		    "shared fs attributes\n"));
170f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
171f169c0eaSGlenn Lagasse 	}
172f169c0eaSGlenn Lagasse 	if (nelem != shared_fs_num) {
173f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_init: size of SHARED_FS_NAMES "
174f169c0eaSGlenn Lagasse 		    "array does not match SHARED_FS_NUM\n"));
175f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
176f169c0eaSGlenn Lagasse 	}
177f169c0eaSGlenn Lagasse 
178f169c0eaSGlenn Lagasse 	/* Verify that nbe_zpool exists */
179f169c0eaSGlenn Lagasse 	if ((zlp = zpool_open(g_zfs, bt.nbe_zpool)) == NULL) {
180f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_init: failed to "
181f169c0eaSGlenn Lagasse 		    "find existing zpool (%s): %s\n"), bt.nbe_zpool,
182f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
183f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
184f169c0eaSGlenn Lagasse 	}
185f169c0eaSGlenn Lagasse 	zpool_close(zlp);
186f169c0eaSGlenn Lagasse 
187f169c0eaSGlenn Lagasse 	/*
188f169c0eaSGlenn Lagasse 	 * Verify BE container dataset in nbe_zpool exists.
189f169c0eaSGlenn Lagasse 	 * If not, create it.
190f169c0eaSGlenn Lagasse 	 */
191f169c0eaSGlenn Lagasse 	if (!be_create_container_ds(bt.nbe_zpool))
192f169c0eaSGlenn Lagasse 		return (BE_ERR_CREATDS);
193f169c0eaSGlenn Lagasse 
194f169c0eaSGlenn Lagasse 	/*
195f169c0eaSGlenn Lagasse 	 * Verify that nbe_name doesn't already exist in some pool.
196f169c0eaSGlenn Lagasse 	 */
197f169c0eaSGlenn Lagasse 	if ((zret = zpool_iter(g_zfs, be_exists_callback, bt.nbe_name)) > 0) {
198f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_init: BE (%s) already exists\n"),
199f169c0eaSGlenn Lagasse 		    bt.nbe_name);
200f169c0eaSGlenn Lagasse 		return (BE_ERR_BE_EXISTS);
201f169c0eaSGlenn Lagasse 	} else if (zret < 0) {
202f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_init: zpool_iter failed: %s\n"),
203f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
204f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
205f169c0eaSGlenn Lagasse 	}
206f169c0eaSGlenn Lagasse 
207f169c0eaSGlenn Lagasse 	/* Generate string for BE's root dataset */
208f169c0eaSGlenn Lagasse 	be_make_root_ds(bt.nbe_zpool, bt.nbe_name, nbe_root_ds,
209f169c0eaSGlenn Lagasse 	    sizeof (nbe_root_ds));
210f169c0eaSGlenn Lagasse 
211f169c0eaSGlenn Lagasse 	/*
212f169c0eaSGlenn Lagasse 	 * Create property list for new BE root dataset.  If some
213f169c0eaSGlenn Lagasse 	 * zfs properties were already provided by the caller, dup
214f169c0eaSGlenn Lagasse 	 * that list.  Otherwise initialize a new property list.
215f169c0eaSGlenn Lagasse 	 */
216f169c0eaSGlenn Lagasse 	if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
217f169c0eaSGlenn Lagasse 	    BE_ATTR_ZFS_PROPERTIES, DATA_TYPE_NVLIST, &zfs_props, NULL)
218f169c0eaSGlenn Lagasse 	    != 0) {
219f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_init: failed to lookup "
220f169c0eaSGlenn Lagasse 		    "BE_ATTR_ZFS_PROPERTIES attribute\n"));
221f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
222f169c0eaSGlenn Lagasse 	}
223f169c0eaSGlenn Lagasse 	if (zfs_props != NULL) {
224f169c0eaSGlenn Lagasse 		/* Make sure its a unique nvlist */
225f169c0eaSGlenn Lagasse 		if (!(zfs_props->nvl_nvflag & NV_UNIQUE_NAME) &&
226f169c0eaSGlenn Lagasse 		    !(zfs_props->nvl_nvflag & NV_UNIQUE_NAME_TYPE)) {
227f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_init: ZFS property list "
228f169c0eaSGlenn Lagasse 			    "not unique\n"));
229f169c0eaSGlenn Lagasse 			return (BE_ERR_INVAL);
230f169c0eaSGlenn Lagasse 		}
231f169c0eaSGlenn Lagasse 
232f169c0eaSGlenn Lagasse 		/* Dup the list */
233f169c0eaSGlenn Lagasse 		if (nvlist_dup(zfs_props, &bt.nbe_zfs_props, 0) != 0) {
234f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_init: failed to dup ZFS "
235f169c0eaSGlenn Lagasse 			    "property list\n"));
236f169c0eaSGlenn Lagasse 			return (BE_ERR_NOMEM);
237f169c0eaSGlenn Lagasse 		}
238f169c0eaSGlenn Lagasse 	} else {
239f169c0eaSGlenn Lagasse 		/* Initialize new nvlist */
240f169c0eaSGlenn Lagasse 		if (nvlist_alloc(&bt.nbe_zfs_props, NV_UNIQUE_NAME, 0) != 0) {
241f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_init: internal "
242f169c0eaSGlenn Lagasse 			    "error: out of memory\n"));
243f169c0eaSGlenn Lagasse 			return (BE_ERR_NOMEM);
244f169c0eaSGlenn Lagasse 		}
245f169c0eaSGlenn Lagasse 	}
246f169c0eaSGlenn Lagasse 
247f169c0eaSGlenn Lagasse 	/* Set the mountpoint property for the root dataset */
248f169c0eaSGlenn Lagasse 	if (nvlist_add_string(bt.nbe_zfs_props,
249f169c0eaSGlenn Lagasse 	    zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), "/") != 0) {
250f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_init: internal error "
251f169c0eaSGlenn Lagasse 		    "out of memory\n"));
252f169c0eaSGlenn Lagasse 		ret = BE_ERR_NOMEM;
253f169c0eaSGlenn Lagasse 		goto done;
254f169c0eaSGlenn Lagasse 	}
255f169c0eaSGlenn Lagasse 
256f169c0eaSGlenn Lagasse 	/* Set the 'canmount' property */
257f169c0eaSGlenn Lagasse 	if (nvlist_add_string(bt.nbe_zfs_props,
258f169c0eaSGlenn Lagasse 	    zfs_prop_to_name(ZFS_PROP_CANMOUNT), "noauto") != 0) {
259f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_init: internal error "
260f169c0eaSGlenn Lagasse 		    "out of memory\n"));
261f169c0eaSGlenn Lagasse 		ret = BE_ERR_NOMEM;
262f169c0eaSGlenn Lagasse 		goto done;
263f169c0eaSGlenn Lagasse 	}
264f169c0eaSGlenn Lagasse 
265f169c0eaSGlenn Lagasse 	/* Create BE root dataset for the new BE */
266f169c0eaSGlenn Lagasse 	if (zfs_create(g_zfs, nbe_root_ds, ZFS_TYPE_FILESYSTEM,
267f169c0eaSGlenn Lagasse 	    bt.nbe_zfs_props) != 0) {
268f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_init: failed to "
269f169c0eaSGlenn Lagasse 		    "create BE root dataset (%s): %s\n"), nbe_root_ds,
270f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
271f169c0eaSGlenn Lagasse 		ret = zfs_err_to_be_err(g_zfs);
272f169c0eaSGlenn Lagasse 		goto done;
273f169c0eaSGlenn Lagasse 	}
274f169c0eaSGlenn Lagasse 
275f169c0eaSGlenn Lagasse 	/* Set UUID for new BE */
276f169c0eaSGlenn Lagasse 	if ((ret = be_set_uuid(nbe_root_ds)) != BE_SUCCESS) {
277f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_init: failed to "
278f169c0eaSGlenn Lagasse 		    "set uuid for new BE\n"));
279f169c0eaSGlenn Lagasse 	}
280f169c0eaSGlenn Lagasse 
281f169c0eaSGlenn Lagasse 	/*
282f169c0eaSGlenn Lagasse 	 * Clear the mountpoint property so that the non-shared
283f169c0eaSGlenn Lagasse 	 * file systems created below inherit their mountpoints.
284f169c0eaSGlenn Lagasse 	 */
285f169c0eaSGlenn Lagasse 	(void) nvlist_remove(bt.nbe_zfs_props,
286f169c0eaSGlenn Lagasse 	    zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), DATA_TYPE_STRING);
287f169c0eaSGlenn Lagasse 
288f169c0eaSGlenn Lagasse 	/* Create the new BE's non-shared file systems */
289f169c0eaSGlenn Lagasse 	for (i = 0; i < fs_num && fs_names[i]; i++) {
290f169c0eaSGlenn Lagasse 		/*
291f169c0eaSGlenn Lagasse 		 * If fs == "/", skip it;
292f169c0eaSGlenn Lagasse 		 * we already created the root dataset
293f169c0eaSGlenn Lagasse 		 */
294f169c0eaSGlenn Lagasse 		if (strcmp(fs_names[i], "/") == 0)
295f169c0eaSGlenn Lagasse 			continue;
296f169c0eaSGlenn Lagasse 
297f169c0eaSGlenn Lagasse 		/* Generate string for file system */
298f169c0eaSGlenn Lagasse 		(void) snprintf(child_fs, sizeof (child_fs), "%s%s",
299f169c0eaSGlenn Lagasse 		    nbe_root_ds, fs_names[i]);
300f169c0eaSGlenn Lagasse 
301f169c0eaSGlenn Lagasse 		/* Create file system */
302f169c0eaSGlenn Lagasse 		if (zfs_create(g_zfs, child_fs, ZFS_TYPE_FILESYSTEM,
303f169c0eaSGlenn Lagasse 		    bt.nbe_zfs_props) != 0) {
304f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_init: failed to create "
305f169c0eaSGlenn Lagasse 			    "BE's child dataset (%s): %s\n"), child_fs,
306f169c0eaSGlenn Lagasse 			    libzfs_error_description(g_zfs));
307f169c0eaSGlenn Lagasse 			ret = zfs_err_to_be_err(g_zfs);
308f169c0eaSGlenn Lagasse 			goto done;
309f169c0eaSGlenn Lagasse 		}
310f169c0eaSGlenn Lagasse 	}
311f169c0eaSGlenn Lagasse 
312f169c0eaSGlenn Lagasse 	/* Create the new BE's shared file systems */
313f169c0eaSGlenn Lagasse 	if (shared_fs_num > 0) {
314f169c0eaSGlenn Lagasse 		nvlist_t	*props = NULL;
315f169c0eaSGlenn Lagasse 
316f169c0eaSGlenn Lagasse 		if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) {
317f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_init: nvlist_alloc failed\n"));
318f169c0eaSGlenn Lagasse 			ret = BE_ERR_NOMEM;
319f169c0eaSGlenn Lagasse 			goto done;
320f169c0eaSGlenn Lagasse 		}
321f169c0eaSGlenn Lagasse 
322f169c0eaSGlenn Lagasse 		for (i = 0; i < shared_fs_num; i++) {
323f169c0eaSGlenn Lagasse 			/* Generate string for shared file system */
324f169c0eaSGlenn Lagasse 			(void) snprintf(child_fs, sizeof (child_fs), "%s%s",
325f169c0eaSGlenn Lagasse 			    bt.nbe_zpool, shared_fs_names[i]);
326f169c0eaSGlenn Lagasse 
327f169c0eaSGlenn Lagasse 			if (nvlist_add_string(props,
328f169c0eaSGlenn Lagasse 			    zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
329f169c0eaSGlenn Lagasse 			    shared_fs_names[i]) != 0) {
330f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_init: "
331f169c0eaSGlenn Lagasse 				    "internal error: out of memory\n"));
332f169c0eaSGlenn Lagasse 				nvlist_free(props);
333f169c0eaSGlenn Lagasse 				ret = BE_ERR_NOMEM;
334f169c0eaSGlenn Lagasse 				goto done;
335f169c0eaSGlenn Lagasse 			}
336f169c0eaSGlenn Lagasse 
337f169c0eaSGlenn Lagasse 			/* Create file system if it doesn't already exist */
338f169c0eaSGlenn Lagasse 			if (zfs_dataset_exists(g_zfs, child_fs,
339f169c0eaSGlenn Lagasse 			    ZFS_TYPE_FILESYSTEM)) {
340f169c0eaSGlenn Lagasse 				continue;
341f169c0eaSGlenn Lagasse 			}
342f169c0eaSGlenn Lagasse 			if (zfs_create(g_zfs, child_fs, ZFS_TYPE_FILESYSTEM,
343f169c0eaSGlenn Lagasse 			    props) != 0) {
344f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_init: failed to "
345f169c0eaSGlenn Lagasse 				    "create BE's shared dataset (%s): %s\n"),
346f169c0eaSGlenn Lagasse 				    child_fs, libzfs_error_description(g_zfs));
347f169c0eaSGlenn Lagasse 				ret = zfs_err_to_be_err(g_zfs);
348f169c0eaSGlenn Lagasse 				nvlist_free(props);
349f169c0eaSGlenn Lagasse 				goto done;
350f169c0eaSGlenn Lagasse 			}
351f169c0eaSGlenn Lagasse 		}
352f169c0eaSGlenn Lagasse 
353f169c0eaSGlenn Lagasse 		nvlist_free(props);
354f169c0eaSGlenn Lagasse 	}
355f169c0eaSGlenn Lagasse 
356f169c0eaSGlenn Lagasse done:
357f169c0eaSGlenn Lagasse 	if (bt.nbe_zfs_props != NULL)
358f169c0eaSGlenn Lagasse 		nvlist_free(bt.nbe_zfs_props);
359f169c0eaSGlenn Lagasse 
360f169c0eaSGlenn Lagasse 	be_zfs_fini();
361f169c0eaSGlenn Lagasse 
362f169c0eaSGlenn Lagasse 	return (ret);
363f169c0eaSGlenn Lagasse }
364f169c0eaSGlenn Lagasse 
365f169c0eaSGlenn Lagasse /*
366f169c0eaSGlenn Lagasse  * Function:	be_destroy
367f169c0eaSGlenn Lagasse  * Description:	Destroy a BE and all of its children datasets, snapshots and
368f169c0eaSGlenn Lagasse  *		zones that belong to the parent BE.
369f169c0eaSGlenn Lagasse  * Parameters:
370f169c0eaSGlenn Lagasse  *		be_attrs - pointer to nvlist_t of attributes being passed in.
371f169c0eaSGlenn Lagasse  *			The following attributes are used by this function:
372f169c0eaSGlenn Lagasse  *
373f169c0eaSGlenn Lagasse  *			BE_ATTR_ORIG_BE_NAME		*required
374f169c0eaSGlenn Lagasse  *			BE_ATTR_DESTROY_FLAGS		*optional
375f169c0eaSGlenn Lagasse  * Return:
376f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
377f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
378f169c0eaSGlenn Lagasse  * Scope:
379f169c0eaSGlenn Lagasse  *		Public
380f169c0eaSGlenn Lagasse  */
381f169c0eaSGlenn Lagasse int
382f169c0eaSGlenn Lagasse be_destroy(nvlist_t *be_attrs)
383f169c0eaSGlenn Lagasse {
384f169c0eaSGlenn Lagasse 	zfs_handle_t		*zhp = NULL;
385f169c0eaSGlenn Lagasse 	be_transaction_data_t	bt = { 0 };
386f169c0eaSGlenn Lagasse 	be_transaction_data_t	cur_bt = { 0 };
387f169c0eaSGlenn Lagasse 	be_destroy_data_t	dd = { 0 };
388f169c0eaSGlenn Lagasse 	int			ret = BE_SUCCESS;
389f169c0eaSGlenn Lagasse 	uint16_t		flags = 0;
3905ee7c793SAlexander Eremin 	boolean_t		bs_found = B_FALSE;
391f169c0eaSGlenn Lagasse 	int			zret;
392f169c0eaSGlenn Lagasse 	char			obe_root_ds[MAXPATHLEN];
393f169c0eaSGlenn Lagasse 	char			*mp = NULL;
394f169c0eaSGlenn Lagasse 
395f169c0eaSGlenn Lagasse 	/* Initialize libzfs handle */
396f169c0eaSGlenn Lagasse 	if (!be_zfs_init())
397f169c0eaSGlenn Lagasse 		return (BE_ERR_INIT);
398f169c0eaSGlenn Lagasse 
399f169c0eaSGlenn Lagasse 	/* Get name of BE to delete */
400f169c0eaSGlenn Lagasse 	if (nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_NAME, &bt.obe_name)
401f169c0eaSGlenn Lagasse 	    != 0) {
402f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_destroy: failed to lookup "
403f169c0eaSGlenn Lagasse 		    "BE_ATTR_ORIG_BE_NAME attribute\n"));
404f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
405f169c0eaSGlenn Lagasse 	}
406f169c0eaSGlenn Lagasse 
407f169c0eaSGlenn Lagasse 	/*
408f169c0eaSGlenn Lagasse 	 * Validate BE name. If valid, then check that the original BE is not
409f169c0eaSGlenn Lagasse 	 * the active BE. If it is the 'active' BE then return an error code
410f169c0eaSGlenn Lagasse 	 * since we can't destroy the active BE.
411f169c0eaSGlenn Lagasse 	 */
412f169c0eaSGlenn Lagasse 	if (!be_valid_be_name(bt.obe_name)) {
413f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_destroy: invalid BE name %s\n"),
414f169c0eaSGlenn Lagasse 		    bt.obe_name);
415f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
416f169c0eaSGlenn Lagasse 	} else if (bt.obe_name != NULL) {
417f169c0eaSGlenn Lagasse 		if ((ret = be_find_current_be(&cur_bt)) != BE_SUCCESS) {
418f169c0eaSGlenn Lagasse 			return (ret);
419f169c0eaSGlenn Lagasse 		}
420f169c0eaSGlenn Lagasse 		if (strcmp(cur_bt.obe_name, bt.obe_name) == 0) {
421f169c0eaSGlenn Lagasse 			return (BE_ERR_DESTROY_CURR_BE);
422f169c0eaSGlenn Lagasse 		}
423f169c0eaSGlenn Lagasse 	}
424f169c0eaSGlenn Lagasse 
425f169c0eaSGlenn Lagasse 	/* Get destroy flags if provided */
426f169c0eaSGlenn Lagasse 	if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
427f169c0eaSGlenn Lagasse 	    BE_ATTR_DESTROY_FLAGS, DATA_TYPE_UINT16, &flags, NULL)
428f169c0eaSGlenn Lagasse 	    != 0) {
429f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_destroy: failed to lookup "
430f169c0eaSGlenn Lagasse 		    "BE_ATTR_DESTROY_FLAGS attribute\n"));
431f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
432f169c0eaSGlenn Lagasse 	}
433f169c0eaSGlenn Lagasse 
434f169c0eaSGlenn Lagasse 	dd.destroy_snaps = flags & BE_DESTROY_FLAG_SNAPSHOTS;
435f169c0eaSGlenn Lagasse 	dd.force_unmount = flags & BE_DESTROY_FLAG_FORCE_UNMOUNT;
436f169c0eaSGlenn Lagasse 
437f169c0eaSGlenn Lagasse 	/* Find which zpool obe_name lives in */
438f169c0eaSGlenn Lagasse 	if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) == 0) {
439f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_destroy: failed to find zpool "
440f169c0eaSGlenn Lagasse 		    "for BE (%s)\n"), bt.obe_name);
441f169c0eaSGlenn Lagasse 		return (BE_ERR_BE_NOENT);
442f169c0eaSGlenn Lagasse 	} else if (zret < 0) {
443f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_destroy: zpool_iter failed: %s\n"),
444f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
445f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
446f169c0eaSGlenn Lagasse 	}
447f169c0eaSGlenn Lagasse 
448f169c0eaSGlenn Lagasse 	/* Generate string for obe_name's root dataset */
449f169c0eaSGlenn Lagasse 	be_make_root_ds(bt.obe_zpool, bt.obe_name, obe_root_ds,
450f169c0eaSGlenn Lagasse 	    sizeof (obe_root_ds));
451f169c0eaSGlenn Lagasse 	bt.obe_root_ds = obe_root_ds;
452f169c0eaSGlenn Lagasse 
453*7e0e2549SAlexander Eremin 	if (getzoneid() != GLOBAL_ZONEID) {
454*7e0e2549SAlexander Eremin 		if (!be_zone_compare_uuids(bt.obe_root_ds)) {
455*7e0e2549SAlexander Eremin 			if (be_is_active_on_boot(bt.obe_name)) {
456*7e0e2549SAlexander Eremin 				be_print_err(gettext("be_destroy: destroying "
457*7e0e2549SAlexander Eremin 				    "active zone root dataset from non-active "
458*7e0e2549SAlexander Eremin 				    "global BE is not supported\n"));
459*7e0e2549SAlexander Eremin 				return (BE_ERR_NOTSUP);
460*7e0e2549SAlexander Eremin 			}
461*7e0e2549SAlexander Eremin 		}
462*7e0e2549SAlexander Eremin 	}
463*7e0e2549SAlexander Eremin 
464f169c0eaSGlenn Lagasse 	/*
465f169c0eaSGlenn Lagasse 	 * Detect if the BE to destroy has the 'active on boot' property set.
466f169c0eaSGlenn Lagasse 	 * If so, set the 'active on boot' property on the the 'active' BE.
467f169c0eaSGlenn Lagasse 	 */
468f169c0eaSGlenn Lagasse 	if (be_is_active_on_boot(bt.obe_name)) {
469f169c0eaSGlenn Lagasse 		if ((ret = be_activate_current_be()) != BE_SUCCESS) {
470f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_destroy: failed to "
471f169c0eaSGlenn Lagasse 			    "make the current BE 'active on boot'\n"));
472f169c0eaSGlenn Lagasse 			return (ret);
473f169c0eaSGlenn Lagasse 		}
474f169c0eaSGlenn Lagasse 	}
475f169c0eaSGlenn Lagasse 
476f169c0eaSGlenn Lagasse 	/* Get handle to BE's root dataset */
477f169c0eaSGlenn Lagasse 	if ((zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
478f169c0eaSGlenn Lagasse 	    NULL) {
479f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_destroy: failed to "
480f169c0eaSGlenn Lagasse 		    "open BE root dataset (%s): %s\n"), bt.obe_root_ds,
481f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
482f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
483f169c0eaSGlenn Lagasse 	}
484f169c0eaSGlenn Lagasse 
4855ee7c793SAlexander Eremin 	/*
4865ee7c793SAlexander Eremin 	 * Check if BE has snapshots and BE_DESTROY_FLAG_SNAPSHOTS
4875ee7c793SAlexander Eremin 	 * is not set.
4885ee7c793SAlexander Eremin 	 */
4895ee7c793SAlexander Eremin 	(void) zfs_iter_snapshots(zhp, be_has_snapshot_callback, &bs_found);
4905ee7c793SAlexander Eremin 	if (!dd.destroy_snaps && bs_found) {
4915ee7c793SAlexander Eremin 		ZFS_CLOSE(zhp);
4925ee7c793SAlexander Eremin 		return (BE_ERR_SS_EXISTS);
4935ee7c793SAlexander Eremin 	}
4945ee7c793SAlexander Eremin 
495f169c0eaSGlenn Lagasse 	/* Get the UUID of the global BE */
496*7e0e2549SAlexander Eremin 	if (getzoneid() == GLOBAL_ZONEID) {
497*7e0e2549SAlexander Eremin 		if (be_get_uuid(zfs_get_name(zhp),
498*7e0e2549SAlexander Eremin 		    &dd.gz_be_uuid) != BE_SUCCESS) {
499*7e0e2549SAlexander Eremin 			be_print_err(gettext("be_destroy: BE has no "
500*7e0e2549SAlexander Eremin 			"UUID (%s)\n"), zfs_get_name(zhp));
501*7e0e2549SAlexander Eremin 		}
502f169c0eaSGlenn Lagasse 	}
503f169c0eaSGlenn Lagasse 
504f169c0eaSGlenn Lagasse 	/*
505f169c0eaSGlenn Lagasse 	 * If the global BE is mounted, make sure we've been given the
506f169c0eaSGlenn Lagasse 	 * flag to forcibly unmount it.
507f169c0eaSGlenn Lagasse 	 */
508f169c0eaSGlenn Lagasse 	if (zfs_is_mounted(zhp, &mp)) {
509f169c0eaSGlenn Lagasse 		if (!(dd.force_unmount)) {
510f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_destroy: "
511f169c0eaSGlenn Lagasse 			    "%s is currently mounted at %s, cannot destroy\n"),
512f169c0eaSGlenn Lagasse 			    bt.obe_name, mp != NULL ? mp : "<unknown>");
513f169c0eaSGlenn Lagasse 
514f169c0eaSGlenn Lagasse 			free(mp);
515f169c0eaSGlenn Lagasse 			ZFS_CLOSE(zhp);
516f169c0eaSGlenn Lagasse 			return (BE_ERR_MOUNTED);
517f169c0eaSGlenn Lagasse 		}
518f169c0eaSGlenn Lagasse 		free(mp);
519f169c0eaSGlenn Lagasse 	}
520f169c0eaSGlenn Lagasse 
521f169c0eaSGlenn Lagasse 	/*
522f169c0eaSGlenn Lagasse 	 * Destroy the non-global zone BE's if we are in the global zone
523f169c0eaSGlenn Lagasse 	 * and there is a UUID associated with the global zone BE
524f169c0eaSGlenn Lagasse 	 */
525f169c0eaSGlenn Lagasse 	if (getzoneid() == GLOBAL_ZONEID && !uuid_is_null(dd.gz_be_uuid)) {
526f169c0eaSGlenn Lagasse 		if ((ret = be_destroy_zones(bt.obe_name, bt.obe_root_ds, &dd))
527f169c0eaSGlenn Lagasse 		    != BE_SUCCESS) {
528f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_destroy: failed to "
529f169c0eaSGlenn Lagasse 			    "destroy one or more zones for BE %s\n"),
530f169c0eaSGlenn Lagasse 			    bt.obe_name);
531f169c0eaSGlenn Lagasse 			goto done;
532f169c0eaSGlenn Lagasse 		}
533f169c0eaSGlenn Lagasse 	}
534f169c0eaSGlenn Lagasse 
535f169c0eaSGlenn Lagasse 	/* Unmount the BE if it was mounted */
536f169c0eaSGlenn Lagasse 	if (zfs_is_mounted(zhp, NULL)) {
537f169c0eaSGlenn Lagasse 		if ((ret = _be_unmount(bt.obe_name, BE_UNMOUNT_FLAG_FORCE))
538f169c0eaSGlenn Lagasse 		    != BE_SUCCESS) {
539f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_destroy: "
540f169c0eaSGlenn Lagasse 			    "failed to unmount %s\n"), bt.obe_name);
541f169c0eaSGlenn Lagasse 			ZFS_CLOSE(zhp);
542f169c0eaSGlenn Lagasse 			return (ret);
543f169c0eaSGlenn Lagasse 		}
544f169c0eaSGlenn Lagasse 	}
545f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
546f169c0eaSGlenn Lagasse 
547f169c0eaSGlenn Lagasse 	/* Destroy this BE */
548f169c0eaSGlenn Lagasse 	if ((ret = _be_destroy((const char *)bt.obe_root_ds, &dd))
549f169c0eaSGlenn Lagasse 	    != BE_SUCCESS) {
550f169c0eaSGlenn Lagasse 		goto done;
551f169c0eaSGlenn Lagasse 	}
552f169c0eaSGlenn Lagasse 
553f169c0eaSGlenn Lagasse 	/* Remove BE's entry from the boot menu */
554f169c0eaSGlenn Lagasse 	if (getzoneid() == GLOBAL_ZONEID) {
555f169c0eaSGlenn Lagasse 		if ((ret = be_remove_menu(bt.obe_name, bt.obe_zpool, NULL))
556f169c0eaSGlenn Lagasse 		    != BE_SUCCESS) {
557f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_destroy: failed to "
558f169c0eaSGlenn Lagasse 			    "remove BE %s from the boot menu\n"),
559f169c0eaSGlenn Lagasse 			    bt.obe_root_ds);
560f169c0eaSGlenn Lagasse 			goto done;
561f169c0eaSGlenn Lagasse 		}
562f169c0eaSGlenn Lagasse 	}
563f169c0eaSGlenn Lagasse 
564f169c0eaSGlenn Lagasse done:
565f169c0eaSGlenn Lagasse 	be_zfs_fini();
566f169c0eaSGlenn Lagasse 
567f169c0eaSGlenn Lagasse 	return (ret);
568f169c0eaSGlenn Lagasse }
569f169c0eaSGlenn Lagasse 
570f169c0eaSGlenn Lagasse /*
571f169c0eaSGlenn Lagasse  * Function:	be_copy
572f169c0eaSGlenn Lagasse  * Description:	This function makes a copy of an existing BE.  If the original
573f169c0eaSGlenn Lagasse  *		BE and the new BE are in the same pool, it uses zfs cloning to
574f169c0eaSGlenn Lagasse  *		create the new BE, otherwise it does a physical copy.
575f169c0eaSGlenn Lagasse  *		If the original BE name isn't provided, it uses the currently
576f169c0eaSGlenn Lagasse  *		booted BE.  If the new BE name isn't provided, it creates an
577f169c0eaSGlenn Lagasse  *		auto named BE and returns that name to the caller.
578f169c0eaSGlenn Lagasse  * Parameters:
579f169c0eaSGlenn Lagasse  *		be_attrs - pointer to nvlist_t of attributes being passed in.
580f169c0eaSGlenn Lagasse  *			The following attributes are used by this function:
581f169c0eaSGlenn Lagasse  *
582f169c0eaSGlenn Lagasse  *			BE_ATTR_ORIG_BE_NAME		*optional
583f169c0eaSGlenn Lagasse  *			BE_ATTR_SNAP_NAME		*optional
584f169c0eaSGlenn Lagasse  *			BE_ATTR_NEW_BE_NAME		*optional
585f169c0eaSGlenn Lagasse  *			BE_ATTR_NEW_BE_POOL		*optional
586f169c0eaSGlenn Lagasse  *			BE_ATTR_NEW_BE_DESC		*optional
587f169c0eaSGlenn Lagasse  *			BE_ATTR_ZFS_PROPERTIES		*optional
588f169c0eaSGlenn Lagasse  *			BE_ATTR_POLICY			*optional
589f169c0eaSGlenn Lagasse  *
590f169c0eaSGlenn Lagasse  *			If the BE_ATTR_NEW_BE_NAME was not passed in, upon
591f169c0eaSGlenn Lagasse  *			successful BE creation, the following attribute values
592f169c0eaSGlenn Lagasse  *			will be returned to the caller by setting them in the
593f169c0eaSGlenn Lagasse  *			be_attrs parameter passed in:
594f169c0eaSGlenn Lagasse  *
595f169c0eaSGlenn Lagasse  *			BE_ATTR_SNAP_NAME
596f169c0eaSGlenn Lagasse  *			BE_ATTR_NEW_BE_NAME
597f169c0eaSGlenn Lagasse  * Return:
598f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
599f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
600f169c0eaSGlenn Lagasse  * Scope:
601f169c0eaSGlenn Lagasse  *		Public
602f169c0eaSGlenn Lagasse  */
603f169c0eaSGlenn Lagasse int
604f169c0eaSGlenn Lagasse be_copy(nvlist_t *be_attrs)
605f169c0eaSGlenn Lagasse {
606f169c0eaSGlenn Lagasse 	be_transaction_data_t	bt = { 0 };
607f169c0eaSGlenn Lagasse 	be_fs_list_data_t	fld = { 0 };
608f169c0eaSGlenn Lagasse 	zfs_handle_t	*zhp = NULL;
609de1ab35cSAlexander Eremin 	zpool_handle_t	*zphp = NULL;
610f169c0eaSGlenn Lagasse 	nvlist_t	*zfs_props = NULL;
611f169c0eaSGlenn Lagasse 	uuid_t		uu = { 0 };
612*7e0e2549SAlexander Eremin 	uuid_t		parent_uu = { 0 };
613f169c0eaSGlenn Lagasse 	char		obe_root_ds[MAXPATHLEN];
614f169c0eaSGlenn Lagasse 	char		nbe_root_ds[MAXPATHLEN];
615f169c0eaSGlenn Lagasse 	char		ss[MAXPATHLEN];
616f169c0eaSGlenn Lagasse 	char		*new_mp = NULL;
617de1ab35cSAlexander Eremin 	char		*obe_name = NULL;
618f169c0eaSGlenn Lagasse 	boolean_t	autoname = B_FALSE;
619f169c0eaSGlenn Lagasse 	boolean_t	be_created = B_FALSE;
620f169c0eaSGlenn Lagasse 	int		i;
621f169c0eaSGlenn Lagasse 	int		zret;
622f169c0eaSGlenn Lagasse 	int		ret = BE_SUCCESS;
623de1ab35cSAlexander Eremin 	struct be_defaults be_defaults;
624f169c0eaSGlenn Lagasse 
625f169c0eaSGlenn Lagasse 	/* Initialize libzfs handle */
626f169c0eaSGlenn Lagasse 	if (!be_zfs_init())
627f169c0eaSGlenn Lagasse 		return (BE_ERR_INIT);
628f169c0eaSGlenn Lagasse 
629f169c0eaSGlenn Lagasse 	/* Get original BE name */
630f169c0eaSGlenn Lagasse 	if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
631de1ab35cSAlexander Eremin 	    BE_ATTR_ORIG_BE_NAME, DATA_TYPE_STRING, &obe_name, NULL) != 0) {
632f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_copy: failed to lookup "
633f169c0eaSGlenn Lagasse 		    "BE_ATTR_ORIG_BE_NAME attribute\n"));
634f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
635f169c0eaSGlenn Lagasse 	}
636f169c0eaSGlenn Lagasse 
637de1ab35cSAlexander Eremin 	if ((ret = be_find_current_be(&bt)) != BE_SUCCESS) {
638de1ab35cSAlexander Eremin 		return (ret);
639de1ab35cSAlexander Eremin 	}
640de1ab35cSAlexander Eremin 
641de1ab35cSAlexander Eremin 	be_get_defaults(&be_defaults);
642de1ab35cSAlexander Eremin 
643f169c0eaSGlenn Lagasse 	/* If original BE name not provided, use current BE */
644de1ab35cSAlexander Eremin 	if (obe_name != NULL) {
645de1ab35cSAlexander Eremin 		bt.obe_name = obe_name;
646f169c0eaSGlenn Lagasse 		/* Validate original BE name */
647f169c0eaSGlenn Lagasse 		if (!be_valid_be_name(bt.obe_name)) {
648f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy: "
649f169c0eaSGlenn Lagasse 			    "invalid BE name %s\n"), bt.obe_name);
650f169c0eaSGlenn Lagasse 			return (BE_ERR_INVAL);
651f169c0eaSGlenn Lagasse 		}
652f169c0eaSGlenn Lagasse 	}
653f169c0eaSGlenn Lagasse 
654de1ab35cSAlexander Eremin 	if (be_defaults.be_deflt_rpool_container) {
655de1ab35cSAlexander Eremin 		if ((zphp = zpool_open(g_zfs, bt.obe_zpool)) == NULL) {
656de1ab35cSAlexander Eremin 			be_print_err(gettext("be_get_node_data: failed to "
657de1ab35cSAlexander Eremin 			    "open rpool (%s): %s\n"), bt.obe_zpool,
658de1ab35cSAlexander Eremin 			    libzfs_error_description(g_zfs));
659de1ab35cSAlexander Eremin 			return (zfs_err_to_be_err(g_zfs));
660de1ab35cSAlexander Eremin 		}
661de1ab35cSAlexander Eremin 		if (be_find_zpool_callback(zphp, &bt) == 0) {
662de1ab35cSAlexander Eremin 			return (BE_ERR_BE_NOENT);
663de1ab35cSAlexander Eremin 		}
664de1ab35cSAlexander Eremin 	} else {
665de1ab35cSAlexander Eremin 		/* Find which zpool obe_name lives in */
666de1ab35cSAlexander Eremin 		if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) ==
667de1ab35cSAlexander Eremin 		    0) {
668de1ab35cSAlexander Eremin 			be_print_err(gettext("be_copy: failed to "
669de1ab35cSAlexander Eremin 			    "find zpool for BE (%s)\n"), bt.obe_name);
670de1ab35cSAlexander Eremin 			return (BE_ERR_BE_NOENT);
671de1ab35cSAlexander Eremin 		} else if (zret < 0) {
672de1ab35cSAlexander Eremin 			be_print_err(gettext("be_copy: "
673de1ab35cSAlexander Eremin 			    "zpool_iter failed: %s\n"),
674de1ab35cSAlexander Eremin 			    libzfs_error_description(g_zfs));
675de1ab35cSAlexander Eremin 			return (zfs_err_to_be_err(g_zfs));
676de1ab35cSAlexander Eremin 		}
677f169c0eaSGlenn Lagasse 	}
678f169c0eaSGlenn Lagasse 
679f169c0eaSGlenn Lagasse 	/* Get snapshot name of original BE if one was provided */
680f169c0eaSGlenn Lagasse 	if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
681f169c0eaSGlenn Lagasse 	    BE_ATTR_SNAP_NAME, DATA_TYPE_STRING, &bt.obe_snap_name, NULL)
682f169c0eaSGlenn Lagasse 	    != 0) {
683f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_copy: failed to lookup "
684f169c0eaSGlenn Lagasse 		    "BE_ATTR_SNAP_NAME attribute\n"));
685f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
686f169c0eaSGlenn Lagasse 	}
687f169c0eaSGlenn Lagasse 
688f169c0eaSGlenn Lagasse 	/* Get new BE name */
689f169c0eaSGlenn Lagasse 	if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
690f169c0eaSGlenn Lagasse 	    BE_ATTR_NEW_BE_NAME, DATA_TYPE_STRING, &bt.nbe_name, NULL)
691f169c0eaSGlenn Lagasse 	    != 0) {
692f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_copy: failed to lookup "
693f169c0eaSGlenn Lagasse 		    "BE_ATTR_NEW_BE_NAME attribute\n"));
694f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
695f169c0eaSGlenn Lagasse 	}
696f169c0eaSGlenn Lagasse 
697f169c0eaSGlenn Lagasse 	/* Get zpool name to create new BE in */
698f169c0eaSGlenn Lagasse 	if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
699f169c0eaSGlenn Lagasse 	    BE_ATTR_NEW_BE_POOL, DATA_TYPE_STRING, &bt.nbe_zpool, NULL) != 0) {
700f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_copy: failed to lookup "
701f169c0eaSGlenn Lagasse 		    "BE_ATTR_NEW_BE_POOL attribute\n"));
702f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
703f169c0eaSGlenn Lagasse 	}
704f169c0eaSGlenn Lagasse 
705f169c0eaSGlenn Lagasse 	/* Get new BE's description if one was provided */
706f169c0eaSGlenn Lagasse 	if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
707f169c0eaSGlenn Lagasse 	    BE_ATTR_NEW_BE_DESC, DATA_TYPE_STRING, &bt.nbe_desc, NULL) != 0) {
708f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_copy: failed to lookup "
709f169c0eaSGlenn Lagasse 		    "BE_ATTR_NEW_BE_DESC attribute\n"));
710f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
711f169c0eaSGlenn Lagasse 	}
712f169c0eaSGlenn Lagasse 
713f169c0eaSGlenn Lagasse 	/* Get BE policy to create this snapshot under */
714f169c0eaSGlenn Lagasse 	if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
715f169c0eaSGlenn Lagasse 	    BE_ATTR_POLICY, DATA_TYPE_STRING, &bt.policy, NULL) != 0) {
716f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_copy: failed to lookup "
717f169c0eaSGlenn Lagasse 		    "BE_ATTR_POLICY attribute\n"));
718f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
719f169c0eaSGlenn Lagasse 	}
720f169c0eaSGlenn Lagasse 
721f169c0eaSGlenn Lagasse 	/*
722f169c0eaSGlenn Lagasse 	 * Create property list for new BE root dataset.  If some
723f169c0eaSGlenn Lagasse 	 * zfs properties were already provided by the caller, dup
724f169c0eaSGlenn Lagasse 	 * that list.  Otherwise initialize a new property list.
725f169c0eaSGlenn Lagasse 	 */
726f169c0eaSGlenn Lagasse 	if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
727f169c0eaSGlenn Lagasse 	    BE_ATTR_ZFS_PROPERTIES, DATA_TYPE_NVLIST, &zfs_props, NULL)
728f169c0eaSGlenn Lagasse 	    != 0) {
729f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_copy: failed to lookup "
730f169c0eaSGlenn Lagasse 		    "BE_ATTR_ZFS_PROPERTIES attribute\n"));
731f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
732f169c0eaSGlenn Lagasse 	}
733f169c0eaSGlenn Lagasse 	if (zfs_props != NULL) {
734f169c0eaSGlenn Lagasse 		/* Make sure its a unique nvlist */
735f169c0eaSGlenn Lagasse 		if (!(zfs_props->nvl_nvflag & NV_UNIQUE_NAME) &&
736f169c0eaSGlenn Lagasse 		    !(zfs_props->nvl_nvflag & NV_UNIQUE_NAME_TYPE)) {
737f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy: ZFS property list "
738f169c0eaSGlenn Lagasse 			    "not unique\n"));
739f169c0eaSGlenn Lagasse 			return (BE_ERR_INVAL);
740f169c0eaSGlenn Lagasse 		}
741f169c0eaSGlenn Lagasse 
742f169c0eaSGlenn Lagasse 		/* Dup the list */
743f169c0eaSGlenn Lagasse 		if (nvlist_dup(zfs_props, &bt.nbe_zfs_props, 0) != 0) {
744f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy: "
745f169c0eaSGlenn Lagasse 			    "failed to dup ZFS property list\n"));
746f169c0eaSGlenn Lagasse 			return (BE_ERR_NOMEM);
747f169c0eaSGlenn Lagasse 		}
748f169c0eaSGlenn Lagasse 	} else {
749f169c0eaSGlenn Lagasse 		/* Initialize new nvlist */
750f169c0eaSGlenn Lagasse 		if (nvlist_alloc(&bt.nbe_zfs_props, NV_UNIQUE_NAME, 0) != 0) {
751f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy: internal "
752f169c0eaSGlenn Lagasse 			    "error: out of memory\n"));
753f169c0eaSGlenn Lagasse 			return (BE_ERR_NOMEM);
754f169c0eaSGlenn Lagasse 		}
755f169c0eaSGlenn Lagasse 	}
756f169c0eaSGlenn Lagasse 
757f169c0eaSGlenn Lagasse 	/*
758f169c0eaSGlenn Lagasse 	 * If new BE name provided, validate the BE name and then verify
759f169c0eaSGlenn Lagasse 	 * that new BE name doesn't already exist in some pool.
760f169c0eaSGlenn Lagasse 	 */
761f169c0eaSGlenn Lagasse 	if (bt.nbe_name) {
762f169c0eaSGlenn Lagasse 		/* Validate original BE name */
763f169c0eaSGlenn Lagasse 		if (!be_valid_be_name(bt.nbe_name)) {
764f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy: "
765f169c0eaSGlenn Lagasse 			    "invalid BE name %s\n"), bt.nbe_name);
766f169c0eaSGlenn Lagasse 			ret = BE_ERR_INVAL;
767f169c0eaSGlenn Lagasse 			goto done;
768f169c0eaSGlenn Lagasse 		}
769f169c0eaSGlenn Lagasse 
770f169c0eaSGlenn Lagasse 		/* Verify it doesn't already exist */
771*7e0e2549SAlexander Eremin 		if (getzoneid() == GLOBAL_ZONEID) {
772*7e0e2549SAlexander Eremin 			if ((zret = zpool_iter(g_zfs, be_exists_callback,
773*7e0e2549SAlexander Eremin 			    bt.nbe_name)) > 0) {
774*7e0e2549SAlexander Eremin 				be_print_err(gettext("be_copy: BE (%s) already "
775*7e0e2549SAlexander Eremin 				    "exists\n"), bt.nbe_name);
776*7e0e2549SAlexander Eremin 				ret = BE_ERR_BE_EXISTS;
777*7e0e2549SAlexander Eremin 				goto done;
778*7e0e2549SAlexander Eremin 			} else if (zret < 0) {
779*7e0e2549SAlexander Eremin 				be_print_err(gettext("be_copy: zpool_iter "
780*7e0e2549SAlexander Eremin 				    "failed: %s\n"),
781*7e0e2549SAlexander Eremin 				    libzfs_error_description(g_zfs));
782*7e0e2549SAlexander Eremin 				ret = zfs_err_to_be_err(g_zfs);
783*7e0e2549SAlexander Eremin 				goto done;
784*7e0e2549SAlexander Eremin 			}
785*7e0e2549SAlexander Eremin 		} else {
786*7e0e2549SAlexander Eremin 			be_make_root_ds(bt.nbe_zpool, bt.nbe_name, nbe_root_ds,
787*7e0e2549SAlexander Eremin 			    sizeof (nbe_root_ds));
788*7e0e2549SAlexander Eremin 			if (zfs_dataset_exists(g_zfs, nbe_root_ds,
789*7e0e2549SAlexander Eremin 			    ZFS_TYPE_FILESYSTEM)) {
790*7e0e2549SAlexander Eremin 				be_print_err(gettext("be_copy: BE (%s) already "
791*7e0e2549SAlexander Eremin 				    "exists\n"), bt.nbe_name);
792*7e0e2549SAlexander Eremin 				ret = BE_ERR_BE_EXISTS;
793*7e0e2549SAlexander Eremin 				goto done;
794*7e0e2549SAlexander Eremin 			}
795f169c0eaSGlenn Lagasse 		}
796f169c0eaSGlenn Lagasse 	} else {
797f169c0eaSGlenn Lagasse 		/*
798f169c0eaSGlenn Lagasse 		 * If an auto named BE is desired, it must be in the same
799f169c0eaSGlenn Lagasse 		 * pool is the original BE.
800f169c0eaSGlenn Lagasse 		 */
801f169c0eaSGlenn Lagasse 		if (bt.nbe_zpool != NULL) {
802f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy: cannot specify pool "
803f169c0eaSGlenn Lagasse 			    "name when creating an auto named BE\n"));
804f169c0eaSGlenn Lagasse 			ret = BE_ERR_INVAL;
805f169c0eaSGlenn Lagasse 			goto done;
806f169c0eaSGlenn Lagasse 		}
807f169c0eaSGlenn Lagasse 
808f169c0eaSGlenn Lagasse 		/*
809f169c0eaSGlenn Lagasse 		 * Generate auto named BE
810f169c0eaSGlenn Lagasse 		 */
811f169c0eaSGlenn Lagasse 		if ((bt.nbe_name = be_auto_be_name(bt.obe_name))
812f169c0eaSGlenn Lagasse 		    == NULL) {
813f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy: "
814f169c0eaSGlenn Lagasse 			    "failed to generate auto BE name\n"));
815f169c0eaSGlenn Lagasse 			ret = BE_ERR_AUTONAME;
816f169c0eaSGlenn Lagasse 			goto done;
817f169c0eaSGlenn Lagasse 		}
818f169c0eaSGlenn Lagasse 
819f169c0eaSGlenn Lagasse 		autoname = B_TRUE;
820f169c0eaSGlenn Lagasse 	}
821f169c0eaSGlenn Lagasse 
822f169c0eaSGlenn Lagasse 	/*
823f169c0eaSGlenn Lagasse 	 * If zpool name to create new BE in is not provided,
824f169c0eaSGlenn Lagasse 	 * create new BE in original BE's pool.
825f169c0eaSGlenn Lagasse 	 */
826f169c0eaSGlenn Lagasse 	if (bt.nbe_zpool == NULL) {
827f169c0eaSGlenn Lagasse 		bt.nbe_zpool = bt.obe_zpool;
828f169c0eaSGlenn Lagasse 	}
829f169c0eaSGlenn Lagasse 
830f169c0eaSGlenn Lagasse 	/* Get root dataset names for obe_name and nbe_name */
831f169c0eaSGlenn Lagasse 	be_make_root_ds(bt.obe_zpool, bt.obe_name, obe_root_ds,
832f169c0eaSGlenn Lagasse 	    sizeof (obe_root_ds));
833f169c0eaSGlenn Lagasse 	be_make_root_ds(bt.nbe_zpool, bt.nbe_name, nbe_root_ds,
834f169c0eaSGlenn Lagasse 	    sizeof (nbe_root_ds));
835f169c0eaSGlenn Lagasse 
836f169c0eaSGlenn Lagasse 	bt.obe_root_ds = obe_root_ds;
837f169c0eaSGlenn Lagasse 	bt.nbe_root_ds = nbe_root_ds;
838f169c0eaSGlenn Lagasse 
839f169c0eaSGlenn Lagasse 	/*
840f169c0eaSGlenn Lagasse 	 * If an existing snapshot name has been provided to create from,
841f169c0eaSGlenn Lagasse 	 * verify that it exists for the original BE's root dataset.
842f169c0eaSGlenn Lagasse 	 */
843f169c0eaSGlenn Lagasse 	if (bt.obe_snap_name != NULL) {
844f169c0eaSGlenn Lagasse 
845f169c0eaSGlenn Lagasse 		/* Generate dataset name for snapshot to use. */
846f169c0eaSGlenn Lagasse 		(void) snprintf(ss, sizeof (ss), "%s@%s", bt.obe_root_ds,
847f169c0eaSGlenn Lagasse 		    bt.obe_snap_name);
848f169c0eaSGlenn Lagasse 
849f169c0eaSGlenn Lagasse 		/* Verify snapshot exists */
850f169c0eaSGlenn Lagasse 		if (!zfs_dataset_exists(g_zfs, ss, ZFS_TYPE_SNAPSHOT)) {
851f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy: "
852f169c0eaSGlenn Lagasse 			    "snapshot does not exist (%s): %s\n"), ss,
853f169c0eaSGlenn Lagasse 			    libzfs_error_description(g_zfs));
854f169c0eaSGlenn Lagasse 			ret = BE_ERR_SS_NOENT;
855f169c0eaSGlenn Lagasse 			goto done;
856f169c0eaSGlenn Lagasse 		}
857f169c0eaSGlenn Lagasse 	} else {
858f169c0eaSGlenn Lagasse 		/*
859f169c0eaSGlenn Lagasse 		 * Else snapshot name was not provided, generate an
860f169c0eaSGlenn Lagasse 		 * auto named snapshot to use as its origin.
861f169c0eaSGlenn Lagasse 		 */
862f169c0eaSGlenn Lagasse 		if ((ret = _be_create_snapshot(bt.obe_name,
863f169c0eaSGlenn Lagasse 		    &bt.obe_snap_name, bt.policy)) != BE_SUCCESS) {
864f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy: "
865f169c0eaSGlenn Lagasse 			    "failed to create auto named snapshot\n"));
866f169c0eaSGlenn Lagasse 			goto done;
867f169c0eaSGlenn Lagasse 		}
868f169c0eaSGlenn Lagasse 
869f169c0eaSGlenn Lagasse 		if (nvlist_add_string(be_attrs, BE_ATTR_SNAP_NAME,
870f169c0eaSGlenn Lagasse 		    bt.obe_snap_name) != 0) {
871f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy: "
872f169c0eaSGlenn Lagasse 			    "failed to add snap name to be_attrs\n"));
873f169c0eaSGlenn Lagasse 			ret = BE_ERR_NOMEM;
874f169c0eaSGlenn Lagasse 			goto done;
875f169c0eaSGlenn Lagasse 		}
876f169c0eaSGlenn Lagasse 	}
877f169c0eaSGlenn Lagasse 
878f169c0eaSGlenn Lagasse 	/* Get handle to original BE's root dataset. */
879f169c0eaSGlenn Lagasse 	if ((zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_FILESYSTEM))
880f169c0eaSGlenn Lagasse 	    == NULL) {
881f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_copy: failed to "
882f169c0eaSGlenn Lagasse 		    "open BE root dataset (%s): %s\n"), bt.obe_root_ds,
883f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
884f169c0eaSGlenn Lagasse 		ret = zfs_err_to_be_err(g_zfs);
885f169c0eaSGlenn Lagasse 		goto done;
886f169c0eaSGlenn Lagasse 	}
887f169c0eaSGlenn Lagasse 
888f169c0eaSGlenn Lagasse 	/* If original BE is currently mounted, record its altroot. */
889f169c0eaSGlenn Lagasse 	if (zfs_is_mounted(zhp, &bt.obe_altroot) && bt.obe_altroot == NULL) {
890f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_copy: failed to "
891f169c0eaSGlenn Lagasse 		    "get altroot of mounted BE %s: %s\n"),
892f169c0eaSGlenn Lagasse 		    bt.obe_name, libzfs_error_description(g_zfs));
893f169c0eaSGlenn Lagasse 		ret = zfs_err_to_be_err(g_zfs);
894f169c0eaSGlenn Lagasse 		goto done;
895f169c0eaSGlenn Lagasse 	}
896f169c0eaSGlenn Lagasse 
897f169c0eaSGlenn Lagasse 	if (strcmp(bt.obe_zpool, bt.nbe_zpool) == 0) {
898f169c0eaSGlenn Lagasse 
899f169c0eaSGlenn Lagasse 		/* Do clone */
900f169c0eaSGlenn Lagasse 
901f169c0eaSGlenn Lagasse 		/*
902f169c0eaSGlenn Lagasse 		 * Iterate through original BE's datasets and clone
903f169c0eaSGlenn Lagasse 		 * them to create new BE.  This call will end up closing
904f169c0eaSGlenn Lagasse 		 * the zfs handle passed in whether it succeeds for fails.
905f169c0eaSGlenn Lagasse 		 */
906f169c0eaSGlenn Lagasse 		if ((ret = be_clone_fs_callback(zhp, &bt)) != 0) {
907f169c0eaSGlenn Lagasse 			zhp = NULL;
908f169c0eaSGlenn Lagasse 			/* Creating clone BE failed */
909f169c0eaSGlenn Lagasse 			if (!autoname || ret != BE_ERR_BE_EXISTS) {
910f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_copy: "
911f169c0eaSGlenn Lagasse 				    "failed to clone new BE (%s) from "
912f169c0eaSGlenn Lagasse 				    "orig BE (%s)\n"),
913f169c0eaSGlenn Lagasse 				    bt.nbe_name, bt.obe_name);
914f169c0eaSGlenn Lagasse 				ret = BE_ERR_CLONE;
915f169c0eaSGlenn Lagasse 				goto done;
916f169c0eaSGlenn Lagasse 			}
917f169c0eaSGlenn Lagasse 
918f169c0eaSGlenn Lagasse 			/*
919f169c0eaSGlenn Lagasse 			 * We failed to create the new BE because a BE with
920f169c0eaSGlenn Lagasse 			 * the auto-name we generated above has since come
921f169c0eaSGlenn Lagasse 			 * into existence.  Regenerate a new auto-name
922f169c0eaSGlenn Lagasse 			 * and retry.
923f169c0eaSGlenn Lagasse 			 */
924f169c0eaSGlenn Lagasse 			for (i = 1; i < BE_AUTO_NAME_MAX_TRY; i++) {
925f169c0eaSGlenn Lagasse 
926f169c0eaSGlenn Lagasse 				/* Sleep 1 before retrying */
927f169c0eaSGlenn Lagasse 				(void) sleep(1);
928f169c0eaSGlenn Lagasse 
929f169c0eaSGlenn Lagasse 				/* Generate new auto BE name */
930f169c0eaSGlenn Lagasse 				free(bt.nbe_name);
931f169c0eaSGlenn Lagasse 				if ((bt.nbe_name = be_auto_be_name(bt.obe_name))
932f169c0eaSGlenn Lagasse 				    == NULL) {
933f169c0eaSGlenn Lagasse 					be_print_err(gettext("be_copy: "
934f169c0eaSGlenn Lagasse 					    "failed to generate auto "
935f169c0eaSGlenn Lagasse 					    "BE name\n"));
936f169c0eaSGlenn Lagasse 					ret = BE_ERR_AUTONAME;
937f169c0eaSGlenn Lagasse 					goto done;
938f169c0eaSGlenn Lagasse 				}
939f169c0eaSGlenn Lagasse 
940f169c0eaSGlenn Lagasse 				/*
941f169c0eaSGlenn Lagasse 				 * Regenerate string for new BE's
942f169c0eaSGlenn Lagasse 				 * root dataset name
943f169c0eaSGlenn Lagasse 				 */
944f169c0eaSGlenn Lagasse 				be_make_root_ds(bt.nbe_zpool, bt.nbe_name,
945f169c0eaSGlenn Lagasse 				    nbe_root_ds, sizeof (nbe_root_ds));
946f169c0eaSGlenn Lagasse 				bt.nbe_root_ds = nbe_root_ds;
947f169c0eaSGlenn Lagasse 
948f169c0eaSGlenn Lagasse 				/*
949f169c0eaSGlenn Lagasse 				 * Get handle to original BE's root dataset.
950f169c0eaSGlenn Lagasse 				 */
951f169c0eaSGlenn Lagasse 				if ((zhp = zfs_open(g_zfs, bt.obe_root_ds,
952f169c0eaSGlenn Lagasse 				    ZFS_TYPE_FILESYSTEM)) == NULL) {
953f169c0eaSGlenn Lagasse 					be_print_err(gettext("be_copy: "
954f169c0eaSGlenn Lagasse 					    "failed to open BE root dataset "
955f169c0eaSGlenn Lagasse 					    "(%s): %s\n"), bt.obe_root_ds,
956f169c0eaSGlenn Lagasse 					    libzfs_error_description(g_zfs));
957f169c0eaSGlenn Lagasse 					ret = zfs_err_to_be_err(g_zfs);
958f169c0eaSGlenn Lagasse 					goto done;
959f169c0eaSGlenn Lagasse 				}
960f169c0eaSGlenn Lagasse 
961f169c0eaSGlenn Lagasse 				/*
962f169c0eaSGlenn Lagasse 				 * Try to clone the BE again.  This
963f169c0eaSGlenn Lagasse 				 * call will end up closing the zfs
964f169c0eaSGlenn Lagasse 				 * handle passed in whether it
965f169c0eaSGlenn Lagasse 				 * succeeds or fails.
966f169c0eaSGlenn Lagasse 				 */
967f169c0eaSGlenn Lagasse 				ret = be_clone_fs_callback(zhp, &bt);
968f169c0eaSGlenn Lagasse 				zhp = NULL;
969f169c0eaSGlenn Lagasse 				if (ret == 0) {
970f169c0eaSGlenn Lagasse 					break;
971f169c0eaSGlenn Lagasse 				} else if (ret != BE_ERR_BE_EXISTS) {
972f169c0eaSGlenn Lagasse 					be_print_err(gettext("be_copy: "
973f169c0eaSGlenn Lagasse 					    "failed to clone new BE "
974f169c0eaSGlenn Lagasse 					    "(%s) from orig BE (%s)\n"),
975f169c0eaSGlenn Lagasse 					    bt.nbe_name, bt.obe_name);
976f169c0eaSGlenn Lagasse 					ret = BE_ERR_CLONE;
977f169c0eaSGlenn Lagasse 					goto done;
978f169c0eaSGlenn Lagasse 				}
979f169c0eaSGlenn Lagasse 			}
980f169c0eaSGlenn Lagasse 
981f169c0eaSGlenn Lagasse 			/*
982f169c0eaSGlenn Lagasse 			 * If we've exhausted the maximum number of
983f169c0eaSGlenn Lagasse 			 * tries, free the auto BE name and return
984f169c0eaSGlenn Lagasse 			 * error.
985f169c0eaSGlenn Lagasse 			 */
986f169c0eaSGlenn Lagasse 			if (i == BE_AUTO_NAME_MAX_TRY) {
987f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_copy: failed "
988f169c0eaSGlenn Lagasse 				    "to create unique auto BE name\n"));
989f169c0eaSGlenn Lagasse 				free(bt.nbe_name);
990f169c0eaSGlenn Lagasse 				bt.nbe_name = NULL;
991f169c0eaSGlenn Lagasse 				ret = BE_ERR_AUTONAME;
992f169c0eaSGlenn Lagasse 				goto done;
993f169c0eaSGlenn Lagasse 			}
994f169c0eaSGlenn Lagasse 		}
995f169c0eaSGlenn Lagasse 		zhp = NULL;
996f169c0eaSGlenn Lagasse 
997f169c0eaSGlenn Lagasse 	} else {
998f169c0eaSGlenn Lagasse 
999f169c0eaSGlenn Lagasse 		/* Do copy (i.e. send BE datasets via zfs_send/recv) */
1000f169c0eaSGlenn Lagasse 
1001f169c0eaSGlenn Lagasse 		/*
1002f169c0eaSGlenn Lagasse 		 * Verify BE container dataset in nbe_zpool exists.
1003f169c0eaSGlenn Lagasse 		 * If not, create it.
1004f169c0eaSGlenn Lagasse 		 */
1005f169c0eaSGlenn Lagasse 		if (!be_create_container_ds(bt.nbe_zpool)) {
1006f169c0eaSGlenn Lagasse 			ret = BE_ERR_CREATDS;
1007f169c0eaSGlenn Lagasse 			goto done;
1008f169c0eaSGlenn Lagasse 		}
1009f169c0eaSGlenn Lagasse 
1010f169c0eaSGlenn Lagasse 		/*
1011f169c0eaSGlenn Lagasse 		 * Iterate through original BE's datasets and send
1012f169c0eaSGlenn Lagasse 		 * them to the other pool.  This call will end up closing
1013f169c0eaSGlenn Lagasse 		 * the zfs handle passed in whether it succeeds or fails.
1014f169c0eaSGlenn Lagasse 		 */
1015f169c0eaSGlenn Lagasse 		if ((ret = be_send_fs_callback(zhp, &bt)) != 0) {
1016f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy: failed to "
1017f169c0eaSGlenn Lagasse 			    "send BE (%s) to pool (%s)\n"), bt.obe_name,
1018f169c0eaSGlenn Lagasse 			    bt.nbe_zpool);
1019f169c0eaSGlenn Lagasse 			ret = BE_ERR_COPY;
1020f169c0eaSGlenn Lagasse 			zhp = NULL;
1021f169c0eaSGlenn Lagasse 			goto done;
1022f169c0eaSGlenn Lagasse 		}
1023f169c0eaSGlenn Lagasse 		zhp = NULL;
1024f169c0eaSGlenn Lagasse 	}
1025f169c0eaSGlenn Lagasse 
1026f169c0eaSGlenn Lagasse 	/*
1027f169c0eaSGlenn Lagasse 	 * Set flag to note that the dataset(s) for the new BE have been
1028f169c0eaSGlenn Lagasse 	 * successfully created so that if a failure happens from this point
1029f169c0eaSGlenn Lagasse 	 * on, we know to cleanup these datasets.
1030f169c0eaSGlenn Lagasse 	 */
1031f169c0eaSGlenn Lagasse 	be_created = B_TRUE;
1032f169c0eaSGlenn Lagasse 
1033f169c0eaSGlenn Lagasse 	/*
1034f169c0eaSGlenn Lagasse 	 * Validate that the new BE is mountable.
1035f169c0eaSGlenn Lagasse 	 * Do not attempt to mount non-global zone datasets
1036f169c0eaSGlenn Lagasse 	 * since they are not cloned yet.
1037f169c0eaSGlenn Lagasse 	 */
1038f169c0eaSGlenn Lagasse 	if ((ret = _be_mount(bt.nbe_name, &new_mp, BE_MOUNT_FLAG_NO_ZONES))
1039f169c0eaSGlenn Lagasse 	    != BE_SUCCESS) {
1040f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_copy: failed to "
1041f169c0eaSGlenn Lagasse 		    "mount newly created BE\n"));
1042f169c0eaSGlenn Lagasse 		(void) _be_unmount(bt.nbe_name, 0);
1043f169c0eaSGlenn Lagasse 		goto done;
1044f169c0eaSGlenn Lagasse 	}
1045f169c0eaSGlenn Lagasse 
1046f169c0eaSGlenn Lagasse 	/* Set UUID for new BE */
1047*7e0e2549SAlexander Eremin 	if (getzoneid() == GLOBAL_ZONEID) {
1048*7e0e2549SAlexander Eremin 		if (be_set_uuid(bt.nbe_root_ds) != BE_SUCCESS) {
1049*7e0e2549SAlexander Eremin 			be_print_err(gettext("be_copy: failed to "
1050*7e0e2549SAlexander Eremin 			    "set uuid for new BE\n"));
1051*7e0e2549SAlexander Eremin 		}
1052*7e0e2549SAlexander Eremin 	} else {
1053*7e0e2549SAlexander Eremin 		if ((ret = be_zone_get_parent_uuid(bt.obe_root_ds,
1054*7e0e2549SAlexander Eremin 		    &parent_uu)) != BE_SUCCESS) {
1055*7e0e2549SAlexander Eremin 			be_print_err(gettext("be_copy: failed to get "
1056*7e0e2549SAlexander Eremin 			    "parentbe uuid from orig BE\n"));
1057*7e0e2549SAlexander Eremin 			ret = BE_ERR_ZONE_NO_PARENTBE;
1058*7e0e2549SAlexander Eremin 			goto done;
1059*7e0e2549SAlexander Eremin 		} else if ((ret = be_zone_set_parent_uuid(bt.nbe_root_ds,
1060*7e0e2549SAlexander Eremin 		    parent_uu)) != BE_SUCCESS) {
1061*7e0e2549SAlexander Eremin 			be_print_err(gettext("be_copy: failed to set "
1062*7e0e2549SAlexander Eremin 			    "parentbe uuid for newly created BE\n"));
1063*7e0e2549SAlexander Eremin 			goto done;
1064*7e0e2549SAlexander Eremin 		}
1065f169c0eaSGlenn Lagasse 	}
1066f169c0eaSGlenn Lagasse 
1067f169c0eaSGlenn Lagasse 	/*
1068f169c0eaSGlenn Lagasse 	 * Process zones outside of the private BE namespace.
1069f169c0eaSGlenn Lagasse 	 * This has to be done here because we need the uuid set in the
1070f169c0eaSGlenn Lagasse 	 * root dataset of the new BE. The uuid is use to set the parentbe
1071f169c0eaSGlenn Lagasse 	 * property for the new zones datasets.
1072f169c0eaSGlenn Lagasse 	 */
1073f169c0eaSGlenn Lagasse 	if (getzoneid() == GLOBAL_ZONEID &&
1074f169c0eaSGlenn Lagasse 	    be_get_uuid(bt.obe_root_ds, &uu) == BE_SUCCESS) {
1075f169c0eaSGlenn Lagasse 		if ((ret = be_copy_zones(bt.obe_name, bt.obe_root_ds,
1076f169c0eaSGlenn Lagasse 		    bt.nbe_root_ds)) != BE_SUCCESS) {
1077f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy: failed to process "
1078f169c0eaSGlenn Lagasse 			    "zones\n"));
1079f169c0eaSGlenn Lagasse 			goto done;
1080f169c0eaSGlenn Lagasse 		}
1081f169c0eaSGlenn Lagasse 	}
1082f169c0eaSGlenn Lagasse 
1083f169c0eaSGlenn Lagasse 	/*
1084f169c0eaSGlenn Lagasse 	 * Generate a list of file systems from the original BE that are
1085f169c0eaSGlenn Lagasse 	 * legacy mounted.  We use this list to determine which entries in
1086f169c0eaSGlenn Lagasse 	 * vfstab we need to update for the new BE we've just created.
1087f169c0eaSGlenn Lagasse 	 */
1088f169c0eaSGlenn Lagasse 	if ((ret = be_get_legacy_fs(bt.obe_name, bt.obe_root_ds, NULL, NULL,
1089f169c0eaSGlenn Lagasse 	    &fld)) != BE_SUCCESS) {
1090f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_copy: failed to "
1091f169c0eaSGlenn Lagasse 		    "get legacy mounted file system list for %s\n"),
1092f169c0eaSGlenn Lagasse 		    bt.obe_name);
1093f169c0eaSGlenn Lagasse 		goto done;
1094f169c0eaSGlenn Lagasse 	}
1095f169c0eaSGlenn Lagasse 
1096f169c0eaSGlenn Lagasse 	/*
1097f169c0eaSGlenn Lagasse 	 * Update new BE's vfstab.
1098f169c0eaSGlenn Lagasse 	 */
1099f169c0eaSGlenn Lagasse 	if ((ret = be_update_vfstab(bt.nbe_name, bt.obe_zpool, bt.nbe_zpool,
1100f169c0eaSGlenn Lagasse 	    &fld, new_mp)) != BE_SUCCESS) {
1101f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_copy: failed to "
1102f169c0eaSGlenn Lagasse 		    "update new BE's vfstab (%s)\n"), bt.nbe_name);
1103f169c0eaSGlenn Lagasse 		goto done;
1104f169c0eaSGlenn Lagasse 	}
1105f169c0eaSGlenn Lagasse 
1106f169c0eaSGlenn Lagasse 	/* Unmount the new BE */
1107f169c0eaSGlenn Lagasse 	if ((ret = _be_unmount(bt.nbe_name, 0)) != BE_SUCCESS) {
1108f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_copy: failed to "
1109f169c0eaSGlenn Lagasse 		    "unmount newly created BE\n"));
1110f169c0eaSGlenn Lagasse 		goto done;
1111f169c0eaSGlenn Lagasse 	}
1112f169c0eaSGlenn Lagasse 
1113f169c0eaSGlenn Lagasse 	/*
1114f169c0eaSGlenn Lagasse 	 * Add boot menu entry for newly created clone
1115f169c0eaSGlenn Lagasse 	 */
1116f169c0eaSGlenn Lagasse 	if (getzoneid() == GLOBAL_ZONEID &&
1117f169c0eaSGlenn Lagasse 	    (ret = be_append_menu(bt.nbe_name, bt.nbe_zpool,
1118f169c0eaSGlenn Lagasse 	    NULL, bt.obe_root_ds, bt.nbe_desc)) != BE_SUCCESS) {
1119f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_copy: failed to "
1120f169c0eaSGlenn Lagasse 		    "add BE (%s) to boot menu\n"), bt.nbe_name);
1121f169c0eaSGlenn Lagasse 		goto done;
1122f169c0eaSGlenn Lagasse 	}
1123f169c0eaSGlenn Lagasse 
1124f169c0eaSGlenn Lagasse 	/*
1125f169c0eaSGlenn Lagasse 	 * If we succeeded in creating an auto named BE, set its policy
1126f169c0eaSGlenn Lagasse 	 * type and return the auto generated name to the caller by storing
1127f169c0eaSGlenn Lagasse 	 * it in the nvlist passed in by the caller.
1128f169c0eaSGlenn Lagasse 	 */
1129f169c0eaSGlenn Lagasse 	if (autoname) {
1130f169c0eaSGlenn Lagasse 		/* Get handle to new BE's root dataset. */
1131f169c0eaSGlenn Lagasse 		if ((zhp = zfs_open(g_zfs, bt.nbe_root_ds,
1132f169c0eaSGlenn Lagasse 		    ZFS_TYPE_FILESYSTEM)) == NULL) {
1133f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy: failed to "
1134f169c0eaSGlenn Lagasse 			    "open BE root dataset (%s): %s\n"), bt.nbe_root_ds,
1135f169c0eaSGlenn Lagasse 			    libzfs_error_description(g_zfs));
1136f169c0eaSGlenn Lagasse 			ret = zfs_err_to_be_err(g_zfs);
1137f169c0eaSGlenn Lagasse 			goto done;
1138f169c0eaSGlenn Lagasse 		}
1139f169c0eaSGlenn Lagasse 
1140f169c0eaSGlenn Lagasse 		/*
1141f169c0eaSGlenn Lagasse 		 * Set the policy type property into the new BE's root dataset
1142f169c0eaSGlenn Lagasse 		 */
1143f169c0eaSGlenn Lagasse 		if (bt.policy == NULL) {
1144f169c0eaSGlenn Lagasse 			/* If no policy type provided, use default type */
1145f169c0eaSGlenn Lagasse 			bt.policy = be_default_policy();
1146f169c0eaSGlenn Lagasse 		}
1147f169c0eaSGlenn Lagasse 
1148f169c0eaSGlenn Lagasse 		if (zfs_prop_set(zhp, BE_POLICY_PROPERTY, bt.policy) != 0) {
1149f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy: failed to "
1150f169c0eaSGlenn Lagasse 			    "set BE policy for %s: %s\n"), bt.nbe_name,
1151f169c0eaSGlenn Lagasse 			    libzfs_error_description(g_zfs));
1152f169c0eaSGlenn Lagasse 			ret = zfs_err_to_be_err(g_zfs);
1153f169c0eaSGlenn Lagasse 			goto done;
1154f169c0eaSGlenn Lagasse 		}
1155f169c0eaSGlenn Lagasse 
1156f169c0eaSGlenn Lagasse 		/*
1157f169c0eaSGlenn Lagasse 		 * Return the auto generated name to the caller
1158f169c0eaSGlenn Lagasse 		 */
1159f169c0eaSGlenn Lagasse 		if (bt.nbe_name) {
1160f169c0eaSGlenn Lagasse 			if (nvlist_add_string(be_attrs, BE_ATTR_NEW_BE_NAME,
1161f169c0eaSGlenn Lagasse 			    bt.nbe_name) != 0) {
1162f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_copy: failed to "
1163f169c0eaSGlenn Lagasse 				    "add snap name to be_attrs\n"));
1164f169c0eaSGlenn Lagasse 			}
1165f169c0eaSGlenn Lagasse 		}
1166f169c0eaSGlenn Lagasse 	}
1167f169c0eaSGlenn Lagasse 
1168f169c0eaSGlenn Lagasse done:
1169f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
1170f169c0eaSGlenn Lagasse 	be_free_fs_list(&fld);
1171f169c0eaSGlenn Lagasse 
1172f169c0eaSGlenn Lagasse 	if (bt.nbe_zfs_props != NULL)
1173f169c0eaSGlenn Lagasse 		nvlist_free(bt.nbe_zfs_props);
1174f169c0eaSGlenn Lagasse 
1175f169c0eaSGlenn Lagasse 	free(bt.obe_altroot);
1176f169c0eaSGlenn Lagasse 	free(new_mp);
1177f169c0eaSGlenn Lagasse 
1178f169c0eaSGlenn Lagasse 	/*
1179f169c0eaSGlenn Lagasse 	 * If a failure occurred and we already created the datasets for
1180f169c0eaSGlenn Lagasse 	 * the new boot environment, destroy them.
1181f169c0eaSGlenn Lagasse 	 */
1182f169c0eaSGlenn Lagasse 	if (ret != BE_SUCCESS && be_created) {
1183f169c0eaSGlenn Lagasse 		be_destroy_data_t	cdd = { 0 };
1184f169c0eaSGlenn Lagasse 
1185f169c0eaSGlenn Lagasse 		cdd.force_unmount = B_TRUE;
1186f169c0eaSGlenn Lagasse 
1187f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_copy: "
1188f169c0eaSGlenn Lagasse 		    "destroying partially created boot environment\n"));
1189f169c0eaSGlenn Lagasse 
1190f169c0eaSGlenn Lagasse 		if (getzoneid() == GLOBAL_ZONEID && be_get_uuid(bt.nbe_root_ds,
1191f169c0eaSGlenn Lagasse 		    &cdd.gz_be_uuid) == 0)
1192f169c0eaSGlenn Lagasse 			(void) be_destroy_zones(bt.nbe_name, bt.nbe_root_ds,
1193f169c0eaSGlenn Lagasse 			    &cdd);
1194f169c0eaSGlenn Lagasse 
1195f169c0eaSGlenn Lagasse 		(void) _be_destroy(bt.nbe_root_ds, &cdd);
1196f169c0eaSGlenn Lagasse 	}
1197f169c0eaSGlenn Lagasse 
1198f169c0eaSGlenn Lagasse 	be_zfs_fini();
1199f169c0eaSGlenn Lagasse 
1200f169c0eaSGlenn Lagasse 	return (ret);
1201f169c0eaSGlenn Lagasse }
1202f169c0eaSGlenn Lagasse 
1203f169c0eaSGlenn Lagasse /* ********************************************************************	*/
1204f169c0eaSGlenn Lagasse /*			Semi-Private Functions				*/
1205f169c0eaSGlenn Lagasse /* ******************************************************************** */
1206f169c0eaSGlenn Lagasse 
1207f169c0eaSGlenn Lagasse /*
1208f169c0eaSGlenn Lagasse  * Function:	be_find_zpool_callback
1209f169c0eaSGlenn Lagasse  * Description:	Callback function used to find the pool that a BE lives in.
1210f169c0eaSGlenn Lagasse  * Parameters:
1211f169c0eaSGlenn Lagasse  *		zlp - zpool_handle_t pointer for the current pool being
1212f169c0eaSGlenn Lagasse  *			looked at.
1213f169c0eaSGlenn Lagasse  *		data - be_transaction_data_t pointer providing information
1214f169c0eaSGlenn Lagasse  *			about the BE that's being searched for.
1215f169c0eaSGlenn Lagasse  *			This function uses the obe_name member of this
1216f169c0eaSGlenn Lagasse  *			parameter to use as the BE name to search for.
1217f169c0eaSGlenn Lagasse  *			Upon successfully locating the BE, it populates
1218f169c0eaSGlenn Lagasse  *			obe_zpool with the pool name that the BE is found in.
1219f169c0eaSGlenn Lagasse  * Returns:
1220f169c0eaSGlenn Lagasse  *		1 - BE exists in this pool.
1221f169c0eaSGlenn Lagasse  *		0 - BE does not exist in this pool.
1222f169c0eaSGlenn Lagasse  * Scope:
1223f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
1224f169c0eaSGlenn Lagasse  */
1225f169c0eaSGlenn Lagasse int
1226f169c0eaSGlenn Lagasse be_find_zpool_callback(zpool_handle_t *zlp, void *data)
1227f169c0eaSGlenn Lagasse {
1228f169c0eaSGlenn Lagasse 	be_transaction_data_t	*bt = data;
1229f169c0eaSGlenn Lagasse 	const char		*zpool =  zpool_get_name(zlp);
1230f169c0eaSGlenn Lagasse 	char			be_root_ds[MAXPATHLEN];
1231f169c0eaSGlenn Lagasse 
1232f169c0eaSGlenn Lagasse 	/*
1233f169c0eaSGlenn Lagasse 	 * Generate string for the BE's root dataset
1234f169c0eaSGlenn Lagasse 	 */
1235f169c0eaSGlenn Lagasse 	be_make_root_ds(zpool, bt->obe_name, be_root_ds, sizeof (be_root_ds));
1236f169c0eaSGlenn Lagasse 
1237f169c0eaSGlenn Lagasse 	/*
1238f169c0eaSGlenn Lagasse 	 * Check if dataset exists
1239f169c0eaSGlenn Lagasse 	 */
1240f169c0eaSGlenn Lagasse 	if (zfs_dataset_exists(g_zfs, be_root_ds, ZFS_TYPE_FILESYSTEM)) {
1241f169c0eaSGlenn Lagasse 		/* BE's root dataset exists in zpool */
1242f169c0eaSGlenn Lagasse 		bt->obe_zpool = strdup(zpool);
1243f169c0eaSGlenn Lagasse 		zpool_close(zlp);
1244f169c0eaSGlenn Lagasse 		return (1);
1245f169c0eaSGlenn Lagasse 	}
1246f169c0eaSGlenn Lagasse 
1247f169c0eaSGlenn Lagasse 	zpool_close(zlp);
1248f169c0eaSGlenn Lagasse 	return (0);
1249f169c0eaSGlenn Lagasse }
1250f169c0eaSGlenn Lagasse 
1251f169c0eaSGlenn Lagasse /*
1252f169c0eaSGlenn Lagasse  * Function:	be_exists_callback
1253f169c0eaSGlenn Lagasse  * Description:	Callback function used to find out if a BE exists.
1254f169c0eaSGlenn Lagasse  * Parameters:
1255f169c0eaSGlenn Lagasse  *		zlp - zpool_handle_t pointer to the current pool being
1256f169c0eaSGlenn Lagasse  *			looked at.
1257f169c0eaSGlenn Lagasse  *		data - BE name to look for.
1258f169c0eaSGlenn Lagasse  * Return:
1259f169c0eaSGlenn Lagasse  *		1 - BE exists in this pool.
1260f169c0eaSGlenn Lagasse  *		0 - BE does not exist in this pool.
1261f169c0eaSGlenn Lagasse  * Scope:
1262f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
1263f169c0eaSGlenn Lagasse  */
1264f169c0eaSGlenn Lagasse int
1265f169c0eaSGlenn Lagasse be_exists_callback(zpool_handle_t *zlp, void *data)
1266f169c0eaSGlenn Lagasse {
1267f169c0eaSGlenn Lagasse 	const char	*zpool = zpool_get_name(zlp);
1268f169c0eaSGlenn Lagasse 	char		*be_name = data;
1269f169c0eaSGlenn Lagasse 	char		be_root_ds[MAXPATHLEN];
1270f169c0eaSGlenn Lagasse 
1271f169c0eaSGlenn Lagasse 	/*
1272f169c0eaSGlenn Lagasse 	 * Generate string for the BE's root dataset
1273f169c0eaSGlenn Lagasse 	 */
1274f169c0eaSGlenn Lagasse 	be_make_root_ds(zpool, be_name, be_root_ds, sizeof (be_root_ds));
1275f169c0eaSGlenn Lagasse 
1276f169c0eaSGlenn Lagasse 	/*
1277f169c0eaSGlenn Lagasse 	 * Check if dataset exists
1278f169c0eaSGlenn Lagasse 	 */
1279f169c0eaSGlenn Lagasse 	if (zfs_dataset_exists(g_zfs, be_root_ds, ZFS_TYPE_FILESYSTEM)) {
1280f169c0eaSGlenn Lagasse 		/* BE's root dataset exists in zpool */
1281f169c0eaSGlenn Lagasse 		zpool_close(zlp);
1282f169c0eaSGlenn Lagasse 		return (1);
1283f169c0eaSGlenn Lagasse 	}
1284f169c0eaSGlenn Lagasse 
1285f169c0eaSGlenn Lagasse 	zpool_close(zlp);
1286f169c0eaSGlenn Lagasse 	return (0);
1287f169c0eaSGlenn Lagasse }
1288f169c0eaSGlenn Lagasse 
12895ee7c793SAlexander Eremin /*
12905ee7c793SAlexander Eremin  * Function:	be_has_snapshots_callback
12915ee7c793SAlexander Eremin  * Description:	Callback function used to find out if a BE has snapshots.
12925ee7c793SAlexander Eremin  * Parameters:
12935ee7c793SAlexander Eremin  *		zlp - zpool_handle_t pointer to the current pool being
12945ee7c793SAlexander Eremin  *			looked at.
12955ee7c793SAlexander Eremin  *		data - be_snap_found_t pointer.
12965ee7c793SAlexander Eremin  * Return:
12975ee7c793SAlexander Eremin  *		1 - BE has no snapshots.
12985ee7c793SAlexander Eremin  *		0 - BE has snapshots.
12995ee7c793SAlexander Eremin  * Scope:
13005ee7c793SAlexander Eremin  *		Private
13015ee7c793SAlexander Eremin  */
13025ee7c793SAlexander Eremin static int
13035ee7c793SAlexander Eremin be_has_snapshot_callback(zfs_handle_t *zhp, void *data)
13045ee7c793SAlexander Eremin {
13055ee7c793SAlexander Eremin 	boolean_t *bs = data;
13065ee7c793SAlexander Eremin 	if (zfs_get_name(zhp) == NULL) {
13075ee7c793SAlexander Eremin 		zfs_close(zhp);
13085ee7c793SAlexander Eremin 		return (1);
13095ee7c793SAlexander Eremin 	}
13105ee7c793SAlexander Eremin 	*bs = B_TRUE;
13115ee7c793SAlexander Eremin 	zfs_close(zhp);
13125ee7c793SAlexander Eremin 	return (0);
13135ee7c793SAlexander Eremin }
13145ee7c793SAlexander Eremin 
1315f169c0eaSGlenn Lagasse /*
1316f169c0eaSGlenn Lagasse  * Function:	be_set_uuid
1317f169c0eaSGlenn Lagasse  * Description:	This function generates a uuid, unparses it into
1318f169c0eaSGlenn Lagasse  *		string representation, and sets that string into
1319f169c0eaSGlenn Lagasse  *		a zfs user property for a root dataset of a BE.
1320f169c0eaSGlenn Lagasse  *		The name of the user property used to store the
1321f169c0eaSGlenn Lagasse  *		uuid is org.opensolaris.libbe:uuid
1322f169c0eaSGlenn Lagasse  *
1323f169c0eaSGlenn Lagasse  * Parameters:
1324f169c0eaSGlenn Lagasse  *		root_ds - Root dataset of the BE to set a uuid on.
1325f169c0eaSGlenn Lagasse  * Return:
1326f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
1327f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
1328f169c0eaSGlenn Lagasse  * Scope:
1329f169c0eaSGlenn Lagasse  *		Semi-private (library wide ues only)
1330f169c0eaSGlenn Lagasse  */
1331f169c0eaSGlenn Lagasse int
1332f169c0eaSGlenn Lagasse be_set_uuid(char *root_ds)
1333f169c0eaSGlenn Lagasse {
1334f169c0eaSGlenn Lagasse 	zfs_handle_t	*zhp = NULL;
1335f169c0eaSGlenn Lagasse 	uuid_t		uu = { 0 };
1336f169c0eaSGlenn Lagasse 	char		uu_string[UUID_PRINTABLE_STRING_LENGTH] = { 0 };
1337f169c0eaSGlenn Lagasse 	int		ret = BE_SUCCESS;
1338f169c0eaSGlenn Lagasse 
1339f169c0eaSGlenn Lagasse 	/* Generate a UUID and unparse it into string form */
1340f169c0eaSGlenn Lagasse 	uuid_generate(uu);
1341f169c0eaSGlenn Lagasse 	if (uuid_is_null(uu) != 0) {
1342f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_set_uuid: failed to "
1343f169c0eaSGlenn Lagasse 		    "generate uuid\n"));
1344f169c0eaSGlenn Lagasse 		return (BE_ERR_GEN_UUID);
1345f169c0eaSGlenn Lagasse 	}
1346f169c0eaSGlenn Lagasse 	uuid_unparse(uu, uu_string);
1347f169c0eaSGlenn Lagasse 
1348f169c0eaSGlenn Lagasse 	/* Get handle to the BE's root dataset. */
1349f169c0eaSGlenn Lagasse 	if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) == NULL) {
1350f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_set_uuid: failed to "
1351f169c0eaSGlenn Lagasse 		    "open BE root dataset (%s): %s\n"), root_ds,
1352f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
1353f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
1354f169c0eaSGlenn Lagasse 	}
1355f169c0eaSGlenn Lagasse 
1356f169c0eaSGlenn Lagasse 	/* Set uuid property for the BE */
1357f169c0eaSGlenn Lagasse 	if (zfs_prop_set(zhp, BE_UUID_PROPERTY, uu_string) != 0) {
1358f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_set_uuid: failed to "
1359f169c0eaSGlenn Lagasse 		    "set uuid property for BE: %s\n"),
1360f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
1361f169c0eaSGlenn Lagasse 		ret = zfs_err_to_be_err(g_zfs);
1362f169c0eaSGlenn Lagasse 	}
1363f169c0eaSGlenn Lagasse 
1364f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
1365f169c0eaSGlenn Lagasse 
1366f169c0eaSGlenn Lagasse 	return (ret);
1367f169c0eaSGlenn Lagasse }
1368f169c0eaSGlenn Lagasse 
1369f169c0eaSGlenn Lagasse /*
1370f169c0eaSGlenn Lagasse  * Function:	be_get_uuid
1371f169c0eaSGlenn Lagasse  * Description:	This function gets the uuid string from a BE root
1372f169c0eaSGlenn Lagasse  *		dataset, parses it into internal format, and returns
1373f169c0eaSGlenn Lagasse  *		it the caller via a reference pointer passed in.
1374f169c0eaSGlenn Lagasse  *
1375f169c0eaSGlenn Lagasse  * Parameters:
1376f169c0eaSGlenn Lagasse  *		rootds - Root dataset of the BE to get the uuid from.
1377f169c0eaSGlenn Lagasse  *		uu - reference pointer to a uuid_t to return uuid in.
1378f169c0eaSGlenn Lagasse  * Return:
1379f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
1380f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
1381f169c0eaSGlenn Lagasse  * Scope:
1382f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
1383f169c0eaSGlenn Lagasse  */
1384f169c0eaSGlenn Lagasse int
1385f169c0eaSGlenn Lagasse be_get_uuid(const char *root_ds, uuid_t *uu)
1386f169c0eaSGlenn Lagasse {
1387f169c0eaSGlenn Lagasse 	zfs_handle_t	*zhp = NULL;
1388f169c0eaSGlenn Lagasse 	nvlist_t	*userprops = NULL;
1389f169c0eaSGlenn Lagasse 	nvlist_t	*propname = NULL;
1390f169c0eaSGlenn Lagasse 	char		*uu_string = NULL;
1391f169c0eaSGlenn Lagasse 	int		ret = BE_SUCCESS;
1392f169c0eaSGlenn Lagasse 
1393f169c0eaSGlenn Lagasse 	/* Get handle to the BE's root dataset. */
1394f169c0eaSGlenn Lagasse 	if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) == NULL) {
1395f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_get_uuid: failed to "
1396f169c0eaSGlenn Lagasse 		    "open BE root dataset (%s): %s\n"), root_ds,
1397f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
1398f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
1399f169c0eaSGlenn Lagasse 	}
1400f169c0eaSGlenn Lagasse 
1401f169c0eaSGlenn Lagasse 	/* Get user properties for BE's root dataset */
1402f169c0eaSGlenn Lagasse 	if ((userprops = zfs_get_user_props(zhp)) == NULL) {
1403f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_get_uuid: failed to "
1404f169c0eaSGlenn Lagasse 		    "get user properties for BE root dataset (%s): %s\n"),
1405f169c0eaSGlenn Lagasse 		    root_ds, libzfs_error_description(g_zfs));
1406f169c0eaSGlenn Lagasse 		ret = zfs_err_to_be_err(g_zfs);
1407f169c0eaSGlenn Lagasse 		goto done;
1408f169c0eaSGlenn Lagasse 	}
1409f169c0eaSGlenn Lagasse 
1410f169c0eaSGlenn Lagasse 	/* Get UUID string from BE's root dataset user properties */
1411f169c0eaSGlenn Lagasse 	if (nvlist_lookup_nvlist(userprops, BE_UUID_PROPERTY, &propname) != 0 ||
1412f169c0eaSGlenn Lagasse 	    nvlist_lookup_string(propname, ZPROP_VALUE, &uu_string) != 0) {
1413f169c0eaSGlenn Lagasse 		/*
1414f169c0eaSGlenn Lagasse 		 * This probably just means that the BE is simply too old
1415f169c0eaSGlenn Lagasse 		 * to have a uuid or that we haven't created a uuid for
1416f169c0eaSGlenn Lagasse 		 * this BE yet.
1417f169c0eaSGlenn Lagasse 		 */
1418f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_get_uuid: failed to "
1419f169c0eaSGlenn Lagasse 		    "get uuid property from BE root dataset user "
1420f169c0eaSGlenn Lagasse 		    "properties.\n"));
1421f169c0eaSGlenn Lagasse 		ret = BE_ERR_NO_UUID;
1422f169c0eaSGlenn Lagasse 		goto done;
1423f169c0eaSGlenn Lagasse 	}
1424f169c0eaSGlenn Lagasse 	/* Parse uuid string into internal format */
1425f169c0eaSGlenn Lagasse 	if (uuid_parse(uu_string, *uu) != 0 || uuid_is_null(*uu)) {
1426f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_get_uuid: failed to "
1427f169c0eaSGlenn Lagasse 		    "parse uuid\n"));
1428f169c0eaSGlenn Lagasse 		ret = BE_ERR_PARSE_UUID;
1429f169c0eaSGlenn Lagasse 		goto done;
1430f169c0eaSGlenn Lagasse 	}
1431f169c0eaSGlenn Lagasse 
1432f169c0eaSGlenn Lagasse done:
1433f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
1434f169c0eaSGlenn Lagasse 	return (ret);
1435f169c0eaSGlenn Lagasse }
1436f169c0eaSGlenn Lagasse 
1437f169c0eaSGlenn Lagasse /* ********************************************************************	*/
1438f169c0eaSGlenn Lagasse /*			Private Functions				*/
1439f169c0eaSGlenn Lagasse /* ********************************************************************	*/
1440f169c0eaSGlenn Lagasse 
1441f169c0eaSGlenn Lagasse /*
1442f169c0eaSGlenn Lagasse  * Function:	_be_destroy
1443f169c0eaSGlenn Lagasse  * Description:	Destroy a BE and all of its children datasets and snapshots.
1444f169c0eaSGlenn Lagasse  *		This function is called for both global BEs and non-global BEs.
1445f169c0eaSGlenn Lagasse  *		The root dataset of either the global BE or non-global BE to be
1446f169c0eaSGlenn Lagasse  *		destroyed is passed in.
1447f169c0eaSGlenn Lagasse  * Parameters:
1448f169c0eaSGlenn Lagasse  *		root_ds - pointer to the name of the root dataset of the
1449f169c0eaSGlenn Lagasse  *			BE to destroy.
1450f169c0eaSGlenn Lagasse  *		dd - pointer to a be_destroy_data_t structure.
1451f169c0eaSGlenn Lagasse  *
1452f169c0eaSGlenn Lagasse  * Return:
1453f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
1454f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
1455f169c0eaSGlenn Lagasse  * Scope:
1456f169c0eaSGlenn Lagasse  *		Private
1457f169c0eaSGlenn Lagasse  */
1458f169c0eaSGlenn Lagasse static int
1459f169c0eaSGlenn Lagasse _be_destroy(const char *root_ds, be_destroy_data_t *dd)
1460f169c0eaSGlenn Lagasse {
1461f169c0eaSGlenn Lagasse 	zfs_handle_t	*zhp = NULL;
1462f169c0eaSGlenn Lagasse 	char		origin[MAXPATHLEN];
1463f169c0eaSGlenn Lagasse 	char		parent[MAXPATHLEN];
1464f169c0eaSGlenn Lagasse 	char		*snap = NULL;
1465f169c0eaSGlenn Lagasse 	boolean_t	has_origin = B_FALSE;
1466f169c0eaSGlenn Lagasse 	int		ret = BE_SUCCESS;
1467f169c0eaSGlenn Lagasse 
1468f169c0eaSGlenn Lagasse 	/* Get handle to BE's root dataset */
1469f169c0eaSGlenn Lagasse 	if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) ==
1470f169c0eaSGlenn Lagasse 	    NULL) {
1471f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_destroy: failed to "
1472f169c0eaSGlenn Lagasse 		    "open BE root dataset (%s): %s\n"), root_ds,
1473f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
1474f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
1475f169c0eaSGlenn Lagasse 	}
1476f169c0eaSGlenn Lagasse 
1477f169c0eaSGlenn Lagasse 	/*
1478f169c0eaSGlenn Lagasse 	 * Demote this BE in case it has dependent clones.  This call
1479f169c0eaSGlenn Lagasse 	 * will end up closing the zfs handle passed in whether it
1480f169c0eaSGlenn Lagasse 	 * succeeds or fails.
1481f169c0eaSGlenn Lagasse 	 */
1482f169c0eaSGlenn Lagasse 	if (be_demote_callback(zhp, NULL) != 0) {
1483f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_destroy: "
1484f169c0eaSGlenn Lagasse 		    "failed to demote BE %s\n"), root_ds);
1485f169c0eaSGlenn Lagasse 		return (BE_ERR_DEMOTE);
1486f169c0eaSGlenn Lagasse 	}
1487f169c0eaSGlenn Lagasse 
1488f169c0eaSGlenn Lagasse 	/* Get handle to BE's root dataset */
1489f169c0eaSGlenn Lagasse 	if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) ==
1490f169c0eaSGlenn Lagasse 	    NULL) {
1491f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_destroy: failed to "
1492f169c0eaSGlenn Lagasse 		    "open BE root dataset (%s): %s\n"), root_ds,
1493f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
1494f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
1495f169c0eaSGlenn Lagasse 	}
1496f169c0eaSGlenn Lagasse 
1497f169c0eaSGlenn Lagasse 	/*
1498f169c0eaSGlenn Lagasse 	 * Get the origin of this BE's root dataset.  This will be used
1499f169c0eaSGlenn Lagasse 	 * later to destroy the snapshots originally used to create this BE.
1500f169c0eaSGlenn Lagasse 	 */
1501f169c0eaSGlenn Lagasse 	if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin, sizeof (origin), NULL,
1502f169c0eaSGlenn Lagasse 	    NULL, 0, B_FALSE) == 0) {
1503f169c0eaSGlenn Lagasse 		(void) strlcpy(parent, origin, sizeof (parent));
1504f169c0eaSGlenn Lagasse 		if (be_get_snap(parent, &snap) != BE_SUCCESS) {
1505f169c0eaSGlenn Lagasse 			ZFS_CLOSE(zhp);
1506f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_destroy: failed to "
1507f169c0eaSGlenn Lagasse 			    "get snapshot name from origin %s\n"), origin);
1508f169c0eaSGlenn Lagasse 			return (BE_ERR_INVAL);
1509f169c0eaSGlenn Lagasse 		}
1510f169c0eaSGlenn Lagasse 		has_origin = B_TRUE;
1511f169c0eaSGlenn Lagasse 	}
1512f169c0eaSGlenn Lagasse 
1513f169c0eaSGlenn Lagasse 	/*
1514f169c0eaSGlenn Lagasse 	 * Destroy the BE's root and its hierarchical children.  This call
1515f169c0eaSGlenn Lagasse 	 * will end up closing the zfs handle passed in whether it succeeds
1516f169c0eaSGlenn Lagasse 	 * or fails.
1517f169c0eaSGlenn Lagasse 	 */
1518f169c0eaSGlenn Lagasse 	if (be_destroy_callback(zhp, dd) != 0) {
1519f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_destroy: failed to "
1520f169c0eaSGlenn Lagasse 		    "destroy BE %s\n"), root_ds);
1521de1ab35cSAlexander Eremin 		ret = zfs_err_to_be_err(g_zfs);
1522de1ab35cSAlexander Eremin 		return (ret);
1523f169c0eaSGlenn Lagasse 	}
1524f169c0eaSGlenn Lagasse 
1525f169c0eaSGlenn Lagasse 	/* If BE has an origin */
1526f169c0eaSGlenn Lagasse 	if (has_origin) {
1527f169c0eaSGlenn Lagasse 
1528f169c0eaSGlenn Lagasse 		/*
1529f169c0eaSGlenn Lagasse 		 * If origin snapshot doesn't have any other
1530f169c0eaSGlenn Lagasse 		 * dependents, delete the origin.
1531f169c0eaSGlenn Lagasse 		 */
1532f169c0eaSGlenn Lagasse 		if ((zhp = zfs_open(g_zfs, origin, ZFS_TYPE_SNAPSHOT)) ==
1533f169c0eaSGlenn Lagasse 		    NULL) {
1534f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_destroy: failed to "
1535f169c0eaSGlenn Lagasse 			    "open BE's origin (%s): %s\n"), origin,
1536f169c0eaSGlenn Lagasse 			    libzfs_error_description(g_zfs));
1537f169c0eaSGlenn Lagasse 			ret = zfs_err_to_be_err(g_zfs);
1538f169c0eaSGlenn Lagasse 			return (ret);
1539f169c0eaSGlenn Lagasse 		}
1540f169c0eaSGlenn Lagasse 
1541f169c0eaSGlenn Lagasse 		/* If origin has dependents, don't delete it. */
1542f169c0eaSGlenn Lagasse 		if (zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES) != 0) {
1543f169c0eaSGlenn Lagasse 			ZFS_CLOSE(zhp);
1544f169c0eaSGlenn Lagasse 			return (ret);
1545f169c0eaSGlenn Lagasse 		}
1546f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
1547f169c0eaSGlenn Lagasse 
1548f169c0eaSGlenn Lagasse 		/* Get handle to BE's parent's root dataset */
1549f169c0eaSGlenn Lagasse 		if ((zhp = zfs_open(g_zfs, parent, ZFS_TYPE_FILESYSTEM)) ==
1550f169c0eaSGlenn Lagasse 		    NULL) {
1551f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_destroy: failed to "
1552f169c0eaSGlenn Lagasse 			    "open BE's parent root dataset (%s): %s\n"), parent,
1553f169c0eaSGlenn Lagasse 			    libzfs_error_description(g_zfs));
1554f169c0eaSGlenn Lagasse 			ret = zfs_err_to_be_err(g_zfs);
1555f169c0eaSGlenn Lagasse 			return (ret);
1556f169c0eaSGlenn Lagasse 		}
1557f169c0eaSGlenn Lagasse 
1558f169c0eaSGlenn Lagasse 		/* Destroy the snapshot origin used to create this BE. */
1559f169c0eaSGlenn Lagasse 		/*
1560f169c0eaSGlenn Lagasse 		 * The boolean set to B_FALSE and passed to zfs_destroy_snaps()
1561f169c0eaSGlenn Lagasse 		 * tells zfs to process and destroy the snapshots now.
1562f169c0eaSGlenn Lagasse 		 * Otherwise the call will potentially return where the
1563f169c0eaSGlenn Lagasse 		 * snapshot isn't actually destroyed yet, and ZFS is waiting
1564f169c0eaSGlenn Lagasse 		 * until all the references to the snapshot have been
1565f169c0eaSGlenn Lagasse 		 * released before actually destroying the snapshot.
1566f169c0eaSGlenn Lagasse 		 */
1567f169c0eaSGlenn Lagasse 		if (zfs_destroy_snaps(zhp, snap, B_FALSE) != 0) {
1568f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_destroy: failed to "
1569f169c0eaSGlenn Lagasse 			    "destroy original snapshots used to create "
1570f169c0eaSGlenn Lagasse 			    "BE: %s\n"), libzfs_error_description(g_zfs));
1571f169c0eaSGlenn Lagasse 
1572f169c0eaSGlenn Lagasse 			/*
1573f169c0eaSGlenn Lagasse 			 * If a failure happened because a clone exists,
1574f169c0eaSGlenn Lagasse 			 * don't return a failure to the user.  Above, we're
1575f169c0eaSGlenn Lagasse 			 * only checking that the root dataset's origin
1576f169c0eaSGlenn Lagasse 			 * snapshot doesn't have dependent clones, but its
1577f169c0eaSGlenn Lagasse 			 * possible that a subordinate dataset origin snapshot
1578f169c0eaSGlenn Lagasse 			 * has a clone.  We really need to check for that
1579f169c0eaSGlenn Lagasse 			 * before trying to destroy the origin snapshot.
1580f169c0eaSGlenn Lagasse 			 */
1581f169c0eaSGlenn Lagasse 			if (libzfs_errno(g_zfs) != EZFS_EXISTS) {
1582f169c0eaSGlenn Lagasse 				ret = zfs_err_to_be_err(g_zfs);
1583f169c0eaSGlenn Lagasse 				ZFS_CLOSE(zhp);
1584f169c0eaSGlenn Lagasse 				return (ret);
1585f169c0eaSGlenn Lagasse 			}
1586f169c0eaSGlenn Lagasse 		}
1587f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
1588f169c0eaSGlenn Lagasse 	}
1589f169c0eaSGlenn Lagasse 
1590f169c0eaSGlenn Lagasse 	return (ret);
1591f169c0eaSGlenn Lagasse }
1592f169c0eaSGlenn Lagasse 
1593f169c0eaSGlenn Lagasse /*
1594f169c0eaSGlenn Lagasse  * Function:	be_destroy_zones
1595f169c0eaSGlenn Lagasse  * Description:	Find valid zone's and call be_destroy_zone_roots to destroy its
1596f169c0eaSGlenn Lagasse  *		corresponding dataset and all of its children datasets
1597f169c0eaSGlenn Lagasse  *		and snapshots.
1598f169c0eaSGlenn Lagasse  * Parameters:
1599f169c0eaSGlenn Lagasse  *		be_name - name of global boot environment being destroyed
1600f169c0eaSGlenn Lagasse  *		be_root_ds - root dataset of global boot environment being
1601f169c0eaSGlenn Lagasse  *			destroyed.
1602f169c0eaSGlenn Lagasse  *		dd - be_destroy_data_t pointer
1603f169c0eaSGlenn Lagasse  * Return:
1604f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
1605f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
1606f169c0eaSGlenn Lagasse  * Scope:
1607f169c0eaSGlenn Lagasse  *		Private
1608f169c0eaSGlenn Lagasse  *
1609f169c0eaSGlenn Lagasse  * NOTES - Requires that the BE being deleted has no dependent BEs.  If it
1610f169c0eaSGlenn Lagasse  *	   does, the destroy will fail.
1611f169c0eaSGlenn Lagasse  */
1612f169c0eaSGlenn Lagasse static int
1613f169c0eaSGlenn Lagasse be_destroy_zones(char *be_name, char *be_root_ds, be_destroy_data_t *dd)
1614f169c0eaSGlenn Lagasse {
1615f169c0eaSGlenn Lagasse 	int		i;
1616f169c0eaSGlenn Lagasse 	int		ret = BE_SUCCESS;
1617f169c0eaSGlenn Lagasse 	int		force_umnt = BE_UNMOUNT_FLAG_NULL;
1618f169c0eaSGlenn Lagasse 	char		*zonepath = NULL;
1619f169c0eaSGlenn Lagasse 	char		*zonename = NULL;
1620f169c0eaSGlenn Lagasse 	char		*zonepath_ds = NULL;
1621f169c0eaSGlenn Lagasse 	char		*mp = NULL;
1622f169c0eaSGlenn Lagasse 	zoneList_t	zlist = NULL;
1623f169c0eaSGlenn Lagasse 	zoneBrandList_t	*brands = NULL;
1624f169c0eaSGlenn Lagasse 	zfs_handle_t	*zhp = NULL;
1625f169c0eaSGlenn Lagasse 
1626f169c0eaSGlenn Lagasse 	/* If zones are not implemented, then get out. */
1627f169c0eaSGlenn Lagasse 	if (!z_zones_are_implemented()) {
1628f169c0eaSGlenn Lagasse 		return (BE_SUCCESS);
1629f169c0eaSGlenn Lagasse 	}
1630f169c0eaSGlenn Lagasse 
1631f169c0eaSGlenn Lagasse 	/* Get list of supported brands */
1632f169c0eaSGlenn Lagasse 	if ((brands = be_get_supported_brandlist()) == NULL) {
1633f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_destroy_zones: "
1634f169c0eaSGlenn Lagasse 		    "no supported brands\n"));
1635f169c0eaSGlenn Lagasse 		return (BE_SUCCESS);
1636f169c0eaSGlenn Lagasse 	}
1637f169c0eaSGlenn Lagasse 
1638f169c0eaSGlenn Lagasse 	/* Get handle to BE's root dataset */
1639f169c0eaSGlenn Lagasse 	if ((zhp = zfs_open(g_zfs, be_root_ds, ZFS_TYPE_FILESYSTEM)) ==
1640f169c0eaSGlenn Lagasse 	    NULL) {
1641f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_destroy_zones: failed to "
1642f169c0eaSGlenn Lagasse 		    "open BE root dataset (%s): %s\n"), be_root_ds,
1643f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
1644f169c0eaSGlenn Lagasse 		z_free_brand_list(brands);
1645f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
1646f169c0eaSGlenn Lagasse 	}
1647f169c0eaSGlenn Lagasse 
1648f169c0eaSGlenn Lagasse 	/*
1649f169c0eaSGlenn Lagasse 	 * If the global BE is not mounted, we must mount it here to
1650f169c0eaSGlenn Lagasse 	 * gather data about the non-global zones in it.
1651f169c0eaSGlenn Lagasse 	 */
1652f169c0eaSGlenn Lagasse 	if (!zfs_is_mounted(zhp, &mp)) {
1653f169c0eaSGlenn Lagasse 		if ((ret = _be_mount(be_name, &mp,
1654f169c0eaSGlenn Lagasse 		    BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
1655f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_destroy_zones: failed to "
1656f169c0eaSGlenn Lagasse 			    "mount the BE (%s) for zones processing.\n"),
1657f169c0eaSGlenn Lagasse 			    be_name);
1658f169c0eaSGlenn Lagasse 			ZFS_CLOSE(zhp);
1659f169c0eaSGlenn Lagasse 			z_free_brand_list(brands);
1660f169c0eaSGlenn Lagasse 			return (ret);
1661f169c0eaSGlenn Lagasse 		}
1662f169c0eaSGlenn Lagasse 	}
1663f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
1664f169c0eaSGlenn Lagasse 
1665f169c0eaSGlenn Lagasse 	z_set_zone_root(mp);
1666f169c0eaSGlenn Lagasse 	free(mp);
1667f169c0eaSGlenn Lagasse 
1668f169c0eaSGlenn Lagasse 	/* Get list of supported zones. */
1669f169c0eaSGlenn Lagasse 	if ((zlist = z_get_nonglobal_zone_list_by_brand(brands)) == NULL) {
1670f169c0eaSGlenn Lagasse 		z_free_brand_list(brands);
1671f169c0eaSGlenn Lagasse 		return (BE_SUCCESS);
1672f169c0eaSGlenn Lagasse 	}
1673f169c0eaSGlenn Lagasse 
1674f169c0eaSGlenn Lagasse 	/* Unmount the BE before destroying the zones in it. */
1675f169c0eaSGlenn Lagasse 	if (dd->force_unmount)
1676f169c0eaSGlenn Lagasse 		force_umnt = BE_UNMOUNT_FLAG_FORCE;
1677f169c0eaSGlenn Lagasse 	if ((ret = _be_unmount(be_name, force_umnt)) != BE_SUCCESS) {
1678f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_destroy_zones: failed to "
1679f169c0eaSGlenn Lagasse 		    "unmount the BE (%s)\n"), be_name);
1680f169c0eaSGlenn Lagasse 		goto done;
1681f169c0eaSGlenn Lagasse 	}
1682f169c0eaSGlenn Lagasse 
1683f169c0eaSGlenn Lagasse 	/* Iterate through the zones and destroy them. */
1684f169c0eaSGlenn Lagasse 	for (i = 0; (zonename = z_zlist_get_zonename(zlist, i)) != NULL; i++) {
1685f169c0eaSGlenn Lagasse 
1686f169c0eaSGlenn Lagasse 		/* Skip zones that aren't at least installed */
1687f169c0eaSGlenn Lagasse 		if (z_zlist_get_current_state(zlist, i) < ZONE_STATE_INSTALLED)
1688f169c0eaSGlenn Lagasse 			continue;
1689f169c0eaSGlenn Lagasse 
1690f169c0eaSGlenn Lagasse 		zonepath = z_zlist_get_zonepath(zlist, i);
1691f169c0eaSGlenn Lagasse 
1692f169c0eaSGlenn Lagasse 		/*
1693f169c0eaSGlenn Lagasse 		 * Get the dataset of this zonepath.  If its not
1694f169c0eaSGlenn Lagasse 		 * a dataset, skip it.
1695f169c0eaSGlenn Lagasse 		 */
1696f169c0eaSGlenn Lagasse 		if ((zonepath_ds = be_get_ds_from_dir(zonepath)) == NULL)
1697f169c0eaSGlenn Lagasse 			continue;
1698f169c0eaSGlenn Lagasse 
1699f169c0eaSGlenn Lagasse 		/*
1700f169c0eaSGlenn Lagasse 		 * Check if this zone is supported based on the
1701f169c0eaSGlenn Lagasse 		 * dataset of its zonepath.
1702f169c0eaSGlenn Lagasse 		 */
1703f169c0eaSGlenn Lagasse 		if (!be_zone_supported(zonepath_ds)) {
1704f169c0eaSGlenn Lagasse 			free(zonepath_ds);
1705f169c0eaSGlenn Lagasse 			continue;
1706f169c0eaSGlenn Lagasse 		}
1707f169c0eaSGlenn Lagasse 
1708f169c0eaSGlenn Lagasse 		/* Find the zone BE root datasets for this zone. */
1709f169c0eaSGlenn Lagasse 		if ((ret = be_destroy_zone_roots(zonepath_ds, dd))
1710f169c0eaSGlenn Lagasse 		    != BE_SUCCESS) {
1711f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_destroy_zones: failed to "
1712f169c0eaSGlenn Lagasse 			    "find and destroy zone roots for zone %s\n"),
1713f169c0eaSGlenn Lagasse 			    zonename);
1714f169c0eaSGlenn Lagasse 			free(zonepath_ds);
1715f169c0eaSGlenn Lagasse 			goto done;
1716f169c0eaSGlenn Lagasse 		}
1717f169c0eaSGlenn Lagasse 		free(zonepath_ds);
1718f169c0eaSGlenn Lagasse 	}
1719f169c0eaSGlenn Lagasse 
1720f169c0eaSGlenn Lagasse done:
1721f169c0eaSGlenn Lagasse 	z_free_brand_list(brands);
1722f169c0eaSGlenn Lagasse 	z_free_zone_list(zlist);
1723f169c0eaSGlenn Lagasse 
1724f169c0eaSGlenn Lagasse 	return (ret);
1725f169c0eaSGlenn Lagasse }
1726f169c0eaSGlenn Lagasse 
1727f169c0eaSGlenn Lagasse /*
1728f169c0eaSGlenn Lagasse  * Function:	be_destroy_zone_roots
1729f169c0eaSGlenn Lagasse  * Description:	This function will open the zone's root container dataset
1730f169c0eaSGlenn Lagasse  *		and iterate the datasets within, looking for roots that
1731f169c0eaSGlenn Lagasse  *		belong to the given global BE and destroying them.
1732f169c0eaSGlenn Lagasse  *		If no other zone roots remain in the zone's root container
1733f169c0eaSGlenn Lagasse  *		dataset, the function will destroy it and the zone's
1734f169c0eaSGlenn Lagasse  *		zonepath dataset as well.
1735f169c0eaSGlenn Lagasse  * Parameters:
1736f169c0eaSGlenn Lagasse  *		zonepath_ds - pointer to zone's zonepath dataset.
1737f169c0eaSGlenn Lagasse  *		dd - pointer to a linked destroy data.
1738f169c0eaSGlenn Lagasse  * Returns:
1739f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
1740f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
1741f169c0eaSGlenn Lagasse  * Scope:
1742f169c0eaSGlenn Lagasse  *		Private
1743f169c0eaSGlenn Lagasse  */
1744f169c0eaSGlenn Lagasse static int
1745f169c0eaSGlenn Lagasse be_destroy_zone_roots(char *zonepath_ds, be_destroy_data_t *dd)
1746f169c0eaSGlenn Lagasse {
1747f169c0eaSGlenn Lagasse 	zfs_handle_t	*zhp;
1748f169c0eaSGlenn Lagasse 	char		zone_container_ds[MAXPATHLEN];
1749f169c0eaSGlenn Lagasse 	int		ret = BE_SUCCESS;
1750f169c0eaSGlenn Lagasse 
1751f169c0eaSGlenn Lagasse 	/* Generate string for the root container dataset for this zone. */
1752f169c0eaSGlenn Lagasse 	be_make_container_ds(zonepath_ds, zone_container_ds,
1753f169c0eaSGlenn Lagasse 	    sizeof (zone_container_ds));
1754f169c0eaSGlenn Lagasse 
1755f169c0eaSGlenn Lagasse 	/* Get handle to this zone's root container dataset. */
1756f169c0eaSGlenn Lagasse 	if ((zhp = zfs_open(g_zfs, zone_container_ds, ZFS_TYPE_FILESYSTEM))
1757f169c0eaSGlenn Lagasse 	    == NULL) {
1758f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_destroy_zone_roots: failed to "
1759f169c0eaSGlenn Lagasse 		    "open zone root container dataset (%s): %s\n"),
1760f169c0eaSGlenn Lagasse 		    zone_container_ds, libzfs_error_description(g_zfs));
1761f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
1762f169c0eaSGlenn Lagasse 	}
1763f169c0eaSGlenn Lagasse 
1764f169c0eaSGlenn Lagasse 	/*
1765f169c0eaSGlenn Lagasse 	 * Iterate through all of this zone's BEs, destroying the ones
1766f169c0eaSGlenn Lagasse 	 * that belong to the parent global BE.
1767f169c0eaSGlenn Lagasse 	 */
1768f169c0eaSGlenn Lagasse 	if ((ret = zfs_iter_filesystems(zhp, be_destroy_zone_roots_callback,
1769f169c0eaSGlenn Lagasse 	    dd)) != 0) {
1770f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_destroy_zone_roots: failed to "
1771f169c0eaSGlenn Lagasse 		    "destroy zone roots under zonepath dataset %s: %s\n"),
1772f169c0eaSGlenn Lagasse 		    zonepath_ds, libzfs_error_description(g_zfs));
1773f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
1774f169c0eaSGlenn Lagasse 		return (ret);
1775f169c0eaSGlenn Lagasse 	}
1776f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
1777f169c0eaSGlenn Lagasse 
1778f169c0eaSGlenn Lagasse 	/* Get handle to this zone's root container dataset. */
1779f169c0eaSGlenn Lagasse 	if ((zhp = zfs_open(g_zfs, zone_container_ds, ZFS_TYPE_FILESYSTEM))
1780f169c0eaSGlenn Lagasse 	    == NULL) {
1781f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_destroy_zone_roots: failed to "
1782f169c0eaSGlenn Lagasse 		    "open zone root container dataset (%s): %s\n"),
1783f169c0eaSGlenn Lagasse 		    zone_container_ds, libzfs_error_description(g_zfs));
1784f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
1785f169c0eaSGlenn Lagasse 	}
1786f169c0eaSGlenn Lagasse 
1787f169c0eaSGlenn Lagasse 	/*
1788f169c0eaSGlenn Lagasse 	 * If there are no more zone roots in this zone's root container,
1789f169c0eaSGlenn Lagasse 	 * dataset, destroy it and the zonepath dataset as well.
1790f169c0eaSGlenn Lagasse 	 */
1791f169c0eaSGlenn Lagasse 	if (zfs_iter_filesystems(zhp, be_zone_root_exists_callback, NULL)
1792f169c0eaSGlenn Lagasse 	    == 0) {
1793f169c0eaSGlenn Lagasse 		/* Destroy the zone root container dataset */
1794f169c0eaSGlenn Lagasse 		if (zfs_unmount(zhp, NULL, MS_FORCE) != 0 ||
1795f169c0eaSGlenn Lagasse 		    zfs_destroy(zhp, B_FALSE) != 0) {
1796f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_destroy_zone_roots: failed to "
1797f169c0eaSGlenn Lagasse 			    "destroy zone root container dataset (%s): %s\n"),
1798f169c0eaSGlenn Lagasse 			    zone_container_ds, libzfs_error_description(g_zfs));
1799f169c0eaSGlenn Lagasse 			goto done;
1800f169c0eaSGlenn Lagasse 		}
1801f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
1802f169c0eaSGlenn Lagasse 
1803f169c0eaSGlenn Lagasse 		/* Get handle to zonepath dataset */
1804f169c0eaSGlenn Lagasse 		if ((zhp = zfs_open(g_zfs, zonepath_ds, ZFS_TYPE_FILESYSTEM))
1805f169c0eaSGlenn Lagasse 		    == NULL) {
1806f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_destroy_zone_roots: failed to "
1807f169c0eaSGlenn Lagasse 			    "open zonepath dataset (%s): %s\n"),
1808f169c0eaSGlenn Lagasse 			    zonepath_ds, libzfs_error_description(g_zfs));
1809f169c0eaSGlenn Lagasse 			goto done;
1810f169c0eaSGlenn Lagasse 		}
1811f169c0eaSGlenn Lagasse 
1812f169c0eaSGlenn Lagasse 		/* Destroy zonepath dataset */
1813f169c0eaSGlenn Lagasse 		if (zfs_unmount(zhp, NULL, MS_FORCE) != 0 ||
1814f169c0eaSGlenn Lagasse 		    zfs_destroy(zhp, B_FALSE) != 0) {
1815f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_destroy_zone_roots: "
1816f169c0eaSGlenn Lagasse 			    "failed to destroy zonepath dataest %s: %s\n"),
1817f169c0eaSGlenn Lagasse 			    zonepath_ds, libzfs_error_description(g_zfs));
1818f169c0eaSGlenn Lagasse 			goto done;
1819f169c0eaSGlenn Lagasse 		}
1820f169c0eaSGlenn Lagasse 	}
1821f169c0eaSGlenn Lagasse 
1822f169c0eaSGlenn Lagasse done:
1823f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
1824f169c0eaSGlenn Lagasse 	return (ret);
1825f169c0eaSGlenn Lagasse }
1826f169c0eaSGlenn Lagasse 
1827f169c0eaSGlenn Lagasse /*
1828f169c0eaSGlenn Lagasse  * Function:	be_destroy_zone_roots_callback
1829f169c0eaSGlenn Lagasse  * Description: This function is used as a callback to iterate over all of
1830f169c0eaSGlenn Lagasse  *		a zone's root datasets, finding the one's that
1831f169c0eaSGlenn Lagasse  *		correspond to the current BE. The name's
1832f169c0eaSGlenn Lagasse  *		of the zone root datasets are then destroyed by _be_destroy().
1833f169c0eaSGlenn Lagasse  * Parameters:
1834f169c0eaSGlenn Lagasse  *		zhp - zfs_handle_t pointer to current dataset being processed
1835f169c0eaSGlenn Lagasse  *		data - be_destroy_data_t pointer
1836f169c0eaSGlenn Lagasse  * Returns:
1837f169c0eaSGlenn Lagasse  *		0 - Success
1838f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
1839f169c0eaSGlenn Lagasse  * Scope:
1840f169c0eaSGlenn Lagasse  *		Private
1841f169c0eaSGlenn Lagasse  */
1842f169c0eaSGlenn Lagasse static int
1843f169c0eaSGlenn Lagasse be_destroy_zone_roots_callback(zfs_handle_t *zhp, void *data)
1844f169c0eaSGlenn Lagasse {
1845f169c0eaSGlenn Lagasse 	be_destroy_data_t	*dd = data;
1846f169c0eaSGlenn Lagasse 	uuid_t			parent_uuid = { 0 };
1847f169c0eaSGlenn Lagasse 	int			ret = 0;
1848f169c0eaSGlenn Lagasse 
1849f169c0eaSGlenn Lagasse 	if (be_zone_get_parent_uuid(zfs_get_name(zhp), &parent_uuid)
1850f169c0eaSGlenn Lagasse 	    != BE_SUCCESS) {
1851f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_destroy_zone_roots_callback: "
1852f169c0eaSGlenn Lagasse 		    "could not get parentuuid for zone root dataset %s\n"),
1853f169c0eaSGlenn Lagasse 		    zfs_get_name(zhp));
1854f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
1855f169c0eaSGlenn Lagasse 		return (0);
1856f169c0eaSGlenn Lagasse 	}
1857f169c0eaSGlenn Lagasse 
1858f169c0eaSGlenn Lagasse 	if (uuid_compare(dd->gz_be_uuid, parent_uuid) == 0) {
1859f169c0eaSGlenn Lagasse 		/*
1860f169c0eaSGlenn Lagasse 		 * Found a zone root dataset belonging to the parent
1861f169c0eaSGlenn Lagasse 		 * BE being destroyed.  Destroy this zone BE.
1862f169c0eaSGlenn Lagasse 		 */
1863f169c0eaSGlenn Lagasse 		if ((ret = _be_destroy(zfs_get_name(zhp), dd)) != BE_SUCCESS) {
1864f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_destroy_zone_root_callback: "
1865f169c0eaSGlenn Lagasse 			    "failed to destroy zone root %s\n"),
1866f169c0eaSGlenn Lagasse 			    zfs_get_name(zhp));
1867f169c0eaSGlenn Lagasse 			ZFS_CLOSE(zhp);
1868f169c0eaSGlenn Lagasse 			return (ret);
1869f169c0eaSGlenn Lagasse 		}
1870f169c0eaSGlenn Lagasse 	}
1871f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
1872f169c0eaSGlenn Lagasse 
1873f169c0eaSGlenn Lagasse 	return (ret);
1874f169c0eaSGlenn Lagasse }
1875f169c0eaSGlenn Lagasse 
1876f169c0eaSGlenn Lagasse /*
1877f169c0eaSGlenn Lagasse  * Function:	be_copy_zones
1878f169c0eaSGlenn Lagasse  * Description:	Find valid zones and clone them to create their
1879f169c0eaSGlenn Lagasse  *		corresponding datasets for the BE being created.
1880f169c0eaSGlenn Lagasse  * Parameters:
1881f169c0eaSGlenn Lagasse  *		obe_name - name of source global BE being copied.
1882f169c0eaSGlenn Lagasse  *		obe_root_ds - root dataset of source global BE being copied.
1883f169c0eaSGlenn Lagasse  *		nbe_root_ds - root dataset of target global BE.
1884f169c0eaSGlenn Lagasse  * Return:
1885f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
1886f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
1887f169c0eaSGlenn Lagasse  * Scope:
1888f169c0eaSGlenn Lagasse  *		Private
1889f169c0eaSGlenn Lagasse  */
1890f169c0eaSGlenn Lagasse static int
1891f169c0eaSGlenn Lagasse be_copy_zones(char *obe_name, char *obe_root_ds, char *nbe_root_ds)
1892f169c0eaSGlenn Lagasse {
1893f169c0eaSGlenn Lagasse 	int		i, num_retries;
1894f169c0eaSGlenn Lagasse 	int		ret = BE_SUCCESS;
1895f169c0eaSGlenn Lagasse 	int		iret = 0;
1896f169c0eaSGlenn Lagasse 	char		*zonename = NULL;
1897f169c0eaSGlenn Lagasse 	char		*zonepath = NULL;
1898f169c0eaSGlenn Lagasse 	char		*zone_be_name = NULL;
1899f169c0eaSGlenn Lagasse 	char		*temp_mntpt = NULL;
1900f169c0eaSGlenn Lagasse 	char		*new_zone_be_name = NULL;
1901f169c0eaSGlenn Lagasse 	char		zoneroot[MAXPATHLEN];
1902f169c0eaSGlenn Lagasse 	char		zoneroot_ds[MAXPATHLEN];
1903f169c0eaSGlenn Lagasse 	char		zone_container_ds[MAXPATHLEN];
1904f169c0eaSGlenn Lagasse 	char		new_zoneroot_ds[MAXPATHLEN];
1905f169c0eaSGlenn Lagasse 	char		ss[MAXPATHLEN];
1906f169c0eaSGlenn Lagasse 	uuid_t		uu = { 0 };
1907f169c0eaSGlenn Lagasse 	char		uu_string[UUID_PRINTABLE_STRING_LENGTH] = { 0 };
1908f169c0eaSGlenn Lagasse 	be_transaction_data_t bt = { 0 };
1909f169c0eaSGlenn Lagasse 	zfs_handle_t	*obe_zhp = NULL;
1910f169c0eaSGlenn Lagasse 	zfs_handle_t	*nbe_zhp = NULL;
1911f169c0eaSGlenn Lagasse 	zfs_handle_t	*z_zhp = NULL;
1912f169c0eaSGlenn Lagasse 	zoneList_t	zlist = NULL;
1913f169c0eaSGlenn Lagasse 	zoneBrandList_t	*brands = NULL;
1914f169c0eaSGlenn Lagasse 	boolean_t	mounted_here = B_FALSE;
1915f169c0eaSGlenn Lagasse 	char		*snap_name = NULL;
1916f169c0eaSGlenn Lagasse 
1917f169c0eaSGlenn Lagasse 	/* If zones are not implemented, then get out. */
1918f169c0eaSGlenn Lagasse 	if (!z_zones_are_implemented()) {
1919f169c0eaSGlenn Lagasse 		return (BE_SUCCESS);
1920f169c0eaSGlenn Lagasse 	}
1921f169c0eaSGlenn Lagasse 
1922f169c0eaSGlenn Lagasse 	/* Get list of supported brands */
1923f169c0eaSGlenn Lagasse 	if ((brands = be_get_supported_brandlist()) == NULL) {
1924f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_copy_zones: "
1925f169c0eaSGlenn Lagasse 		    "no supported brands\n"));
1926f169c0eaSGlenn Lagasse 		return (BE_SUCCESS);
1927f169c0eaSGlenn Lagasse 	}
1928f169c0eaSGlenn Lagasse 
1929f169c0eaSGlenn Lagasse 	/* Get handle to origin BE's root dataset */
1930f169c0eaSGlenn Lagasse 	if ((obe_zhp = zfs_open(g_zfs, obe_root_ds, ZFS_TYPE_FILESYSTEM))
1931f169c0eaSGlenn Lagasse 	    == NULL) {
1932f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_copy_zones: failed to open "
1933f169c0eaSGlenn Lagasse 		    "the origin BE root dataset (%s) for zones processing: "
1934f169c0eaSGlenn Lagasse 		    "%s\n"), obe_root_ds, libzfs_error_description(g_zfs));
1935f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
1936f169c0eaSGlenn Lagasse 	}
1937f169c0eaSGlenn Lagasse 
1938f169c0eaSGlenn Lagasse 	/* Get handle to newly cloned BE's root dataset */
1939f169c0eaSGlenn Lagasse 	if ((nbe_zhp = zfs_open(g_zfs, nbe_root_ds, ZFS_TYPE_FILESYSTEM))
1940f169c0eaSGlenn Lagasse 	    == NULL) {
1941f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_copy_zones: failed to open "
1942f169c0eaSGlenn Lagasse 		    "the new BE root dataset (%s): %s\n"), nbe_root_ds,
1943f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
1944f169c0eaSGlenn Lagasse 		ZFS_CLOSE(obe_zhp);
1945f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
1946f169c0eaSGlenn Lagasse 	}
1947f169c0eaSGlenn Lagasse 
1948f169c0eaSGlenn Lagasse 	/* Get the uuid of the newly cloned parent BE. */
1949f169c0eaSGlenn Lagasse 	if (be_get_uuid(zfs_get_name(nbe_zhp), &uu) != BE_SUCCESS) {
1950f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_copy_zones: "
1951f169c0eaSGlenn Lagasse 		    "failed to get uuid for BE root "
1952f169c0eaSGlenn Lagasse 		    "dataset %s\n"), zfs_get_name(nbe_zhp));
1953f169c0eaSGlenn Lagasse 		ZFS_CLOSE(nbe_zhp);
1954f169c0eaSGlenn Lagasse 		goto done;
1955f169c0eaSGlenn Lagasse 	}
1956f169c0eaSGlenn Lagasse 	ZFS_CLOSE(nbe_zhp);
1957f169c0eaSGlenn Lagasse 	uuid_unparse(uu, uu_string);
1958f169c0eaSGlenn Lagasse 
1959f169c0eaSGlenn Lagasse 	/*
1960f169c0eaSGlenn Lagasse 	 * If the origin BE is not mounted, we must mount it here to
1961f169c0eaSGlenn Lagasse 	 * gather data about the non-global zones in it.
1962f169c0eaSGlenn Lagasse 	 */
1963f169c0eaSGlenn Lagasse 	if (!zfs_is_mounted(obe_zhp, &temp_mntpt)) {
1964f169c0eaSGlenn Lagasse 		if ((ret = _be_mount(obe_name, &temp_mntpt,
1965f169c0eaSGlenn Lagasse 		    BE_MOUNT_FLAG_NULL)) != BE_SUCCESS) {
1966f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy_zones: failed to "
1967f169c0eaSGlenn Lagasse 			    "mount the BE (%s) for zones procesing.\n"),
1968f169c0eaSGlenn Lagasse 			    obe_name);
1969f169c0eaSGlenn Lagasse 			goto done;
1970f169c0eaSGlenn Lagasse 		}
1971f169c0eaSGlenn Lagasse 		mounted_here = B_TRUE;
1972f169c0eaSGlenn Lagasse 	}
1973f169c0eaSGlenn Lagasse 
1974f169c0eaSGlenn Lagasse 	z_set_zone_root(temp_mntpt);
1975f169c0eaSGlenn Lagasse 
1976f169c0eaSGlenn Lagasse 	/* Get list of supported zones. */
1977f169c0eaSGlenn Lagasse 	if ((zlist = z_get_nonglobal_zone_list_by_brand(brands)) == NULL) {
1978f169c0eaSGlenn Lagasse 		ret = BE_SUCCESS;
1979f169c0eaSGlenn Lagasse 		goto done;
1980f169c0eaSGlenn Lagasse 	}
1981f169c0eaSGlenn Lagasse 
1982f169c0eaSGlenn Lagasse 	for (i = 0; (zonename = z_zlist_get_zonename(zlist, i)) != NULL; i++) {
1983f169c0eaSGlenn Lagasse 
1984f169c0eaSGlenn Lagasse 		be_fs_list_data_t	fld = { 0 };
1985f169c0eaSGlenn Lagasse 		char			zonepath_ds[MAXPATHLEN];
1986f169c0eaSGlenn Lagasse 		char			*ds = NULL;
1987f169c0eaSGlenn Lagasse 
1988f169c0eaSGlenn Lagasse 		/* Get zonepath of zone */
1989f169c0eaSGlenn Lagasse 		zonepath = z_zlist_get_zonepath(zlist, i);
1990f169c0eaSGlenn Lagasse 
1991f169c0eaSGlenn Lagasse 		/* Skip zones that aren't at least installed */
1992f169c0eaSGlenn Lagasse 		if (z_zlist_get_current_state(zlist, i) < ZONE_STATE_INSTALLED)
1993f169c0eaSGlenn Lagasse 			continue;
1994f169c0eaSGlenn Lagasse 
1995f169c0eaSGlenn Lagasse 		/*
1996f169c0eaSGlenn Lagasse 		 * Get the dataset of this zonepath.  If its not
1997f169c0eaSGlenn Lagasse 		 * a dataset, skip it.
1998f169c0eaSGlenn Lagasse 		 */
1999f169c0eaSGlenn Lagasse 		if ((ds = be_get_ds_from_dir(zonepath)) == NULL)
2000f169c0eaSGlenn Lagasse 			continue;
2001f169c0eaSGlenn Lagasse 
2002f169c0eaSGlenn Lagasse 		(void) strlcpy(zonepath_ds, ds, sizeof (zonepath_ds));
2003f169c0eaSGlenn Lagasse 		free(ds);
2004f169c0eaSGlenn Lagasse 		ds = NULL;
2005f169c0eaSGlenn Lagasse 
2006f169c0eaSGlenn Lagasse 		/* Get zoneroot directory */
2007f169c0eaSGlenn Lagasse 		be_make_zoneroot(zonepath, zoneroot, sizeof (zoneroot));
2008f169c0eaSGlenn Lagasse 
2009f169c0eaSGlenn Lagasse 		/* If zonepath dataset not supported, skip it. */
2010f169c0eaSGlenn Lagasse 		if (!be_zone_supported(zonepath_ds)) {
2011f169c0eaSGlenn Lagasse 			continue;
2012f169c0eaSGlenn Lagasse 		}
2013f169c0eaSGlenn Lagasse 
2014f169c0eaSGlenn Lagasse 		if ((ret = be_find_active_zone_root(obe_zhp, zonepath_ds,
2015f169c0eaSGlenn Lagasse 		    zoneroot_ds, sizeof (zoneroot_ds))) != BE_SUCCESS) {
2016f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy_zones: "
2017f169c0eaSGlenn Lagasse 			    "failed to find active zone root for zone %s "
2018f169c0eaSGlenn Lagasse 			    "in BE %s\n"), zonename, obe_name);
2019f169c0eaSGlenn Lagasse 			goto done;
2020f169c0eaSGlenn Lagasse 		}
2021f169c0eaSGlenn Lagasse 
2022f169c0eaSGlenn Lagasse 		be_make_container_ds(zonepath_ds, zone_container_ds,
2023f169c0eaSGlenn Lagasse 		    sizeof (zone_container_ds));
2024f169c0eaSGlenn Lagasse 
2025f169c0eaSGlenn Lagasse 		if ((z_zhp = zfs_open(g_zfs, zoneroot_ds,
2026f169c0eaSGlenn Lagasse 		    ZFS_TYPE_FILESYSTEM)) == NULL) {
2027f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy_zones: "
2028f169c0eaSGlenn Lagasse 			    "failed to open zone root dataset (%s): %s\n"),
2029f169c0eaSGlenn Lagasse 			    zoneroot_ds, libzfs_error_description(g_zfs));
2030f169c0eaSGlenn Lagasse 			ret = zfs_err_to_be_err(g_zfs);
2031f169c0eaSGlenn Lagasse 			goto done;
2032f169c0eaSGlenn Lagasse 		}
2033f169c0eaSGlenn Lagasse 
2034f169c0eaSGlenn Lagasse 		zone_be_name =
2035f169c0eaSGlenn Lagasse 		    be_get_zone_be_name(zoneroot_ds, zone_container_ds);
2036f169c0eaSGlenn Lagasse 
2037f169c0eaSGlenn Lagasse 		if ((new_zone_be_name = be_auto_zone_be_name(zone_container_ds,
2038f169c0eaSGlenn Lagasse 		    zone_be_name)) == NULL) {
2039f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy_zones: failed "
2040f169c0eaSGlenn Lagasse 			    "to generate auto name for zone BE.\n"));
2041f169c0eaSGlenn Lagasse 			ret = BE_ERR_AUTONAME;
2042f169c0eaSGlenn Lagasse 			goto done;
2043f169c0eaSGlenn Lagasse 		}
2044f169c0eaSGlenn Lagasse 
2045f169c0eaSGlenn Lagasse 		if ((snap_name = be_auto_snap_name()) == NULL) {
2046f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy_zones: failed to "
2047f169c0eaSGlenn Lagasse 			    "generate snapshot name for zone BE.\n"));
2048f169c0eaSGlenn Lagasse 			ret = BE_ERR_AUTONAME;
2049f169c0eaSGlenn Lagasse 			goto done;
2050f169c0eaSGlenn Lagasse 		}
2051f169c0eaSGlenn Lagasse 
2052f169c0eaSGlenn Lagasse 		(void) snprintf(ss, sizeof (ss), "%s@%s", zoneroot_ds,
2053f169c0eaSGlenn Lagasse 		    snap_name);
2054f169c0eaSGlenn Lagasse 
2055f169c0eaSGlenn Lagasse 		if (zfs_snapshot(g_zfs, ss, B_TRUE, NULL) != 0) {
2056f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy_zones: "
2057f169c0eaSGlenn Lagasse 			    "failed to snapshot zone BE (%s): %s\n"),
2058f169c0eaSGlenn Lagasse 			    ss, libzfs_error_description(g_zfs));
2059f169c0eaSGlenn Lagasse 			if (libzfs_errno(g_zfs) == EZFS_EXISTS)
2060f169c0eaSGlenn Lagasse 				ret = BE_ERR_ZONE_SS_EXISTS;
2061f169c0eaSGlenn Lagasse 			else
2062f169c0eaSGlenn Lagasse 				ret = zfs_err_to_be_err(g_zfs);
2063f169c0eaSGlenn Lagasse 
2064f169c0eaSGlenn Lagasse 			goto done;
2065f169c0eaSGlenn Lagasse 		}
2066f169c0eaSGlenn Lagasse 
2067f169c0eaSGlenn Lagasse 		(void) snprintf(new_zoneroot_ds, sizeof (new_zoneroot_ds),
2068f169c0eaSGlenn Lagasse 		    "%s/%s", zone_container_ds, new_zone_be_name);
2069f169c0eaSGlenn Lagasse 
2070f169c0eaSGlenn Lagasse 		bt.obe_name = zone_be_name;
2071f169c0eaSGlenn Lagasse 		bt.obe_root_ds = zoneroot_ds;
2072f169c0eaSGlenn Lagasse 		bt.obe_snap_name = snap_name;
2073f169c0eaSGlenn Lagasse 		bt.obe_altroot = temp_mntpt;
2074f169c0eaSGlenn Lagasse 		bt.nbe_name = new_zone_be_name;
2075f169c0eaSGlenn Lagasse 		bt.nbe_root_ds = new_zoneroot_ds;
2076f169c0eaSGlenn Lagasse 
2077f169c0eaSGlenn Lagasse 		if (nvlist_alloc(&bt.nbe_zfs_props, NV_UNIQUE_NAME, 0) != 0) {
2078f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy_zones: "
2079f169c0eaSGlenn Lagasse 			    "internal error: out of memory\n"));
2080f169c0eaSGlenn Lagasse 			ret = BE_ERR_NOMEM;
2081f169c0eaSGlenn Lagasse 			goto done;
2082f169c0eaSGlenn Lagasse 		}
2083f169c0eaSGlenn Lagasse 
2084f169c0eaSGlenn Lagasse 		/*
2085f169c0eaSGlenn Lagasse 		 * The call to be_clone_fs_callback always closes the
2086f169c0eaSGlenn Lagasse 		 * zfs_handle so there's no need to close z_zhp.
2087f169c0eaSGlenn Lagasse 		 */
2088f169c0eaSGlenn Lagasse 		if ((iret = be_clone_fs_callback(z_zhp, &bt)) != 0) {
2089f169c0eaSGlenn Lagasse 			z_zhp = NULL;
2090f169c0eaSGlenn Lagasse 			if (iret != BE_ERR_BE_EXISTS) {
2091f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_copy_zones: "
2092f169c0eaSGlenn Lagasse 				    "failed to create zone BE clone for new "
2093f169c0eaSGlenn Lagasse 				    "zone BE %s\n"), new_zone_be_name);
2094f169c0eaSGlenn Lagasse 				ret = iret;
2095f169c0eaSGlenn Lagasse 				if (bt.nbe_zfs_props != NULL)
2096f169c0eaSGlenn Lagasse 					nvlist_free(bt.nbe_zfs_props);
2097f169c0eaSGlenn Lagasse 				goto done;
2098f169c0eaSGlenn Lagasse 			}
2099f169c0eaSGlenn Lagasse 			/*
2100f169c0eaSGlenn Lagasse 			 * We failed to create the new zone BE because a zone
2101f169c0eaSGlenn Lagasse 			 * BE with the auto-name we generated above has since
2102f169c0eaSGlenn Lagasse 			 * come into existence. Regenerate a new auto-name
2103f169c0eaSGlenn Lagasse 			 * and retry.
2104f169c0eaSGlenn Lagasse 			 */
2105f169c0eaSGlenn Lagasse 			for (num_retries = 1;
2106f169c0eaSGlenn Lagasse 			    num_retries < BE_AUTO_NAME_MAX_TRY;
2107f169c0eaSGlenn Lagasse 			    num_retries++) {
2108f169c0eaSGlenn Lagasse 
2109f169c0eaSGlenn Lagasse 				/* Sleep 1 before retrying */
2110f169c0eaSGlenn Lagasse 				(void) sleep(1);
2111f169c0eaSGlenn Lagasse 
2112f169c0eaSGlenn Lagasse 				/* Generate new auto zone BE name */
2113f169c0eaSGlenn Lagasse 				free(new_zone_be_name);
2114f169c0eaSGlenn Lagasse 				if ((new_zone_be_name = be_auto_zone_be_name(
2115f169c0eaSGlenn Lagasse 				    zone_container_ds,
2116f169c0eaSGlenn Lagasse 				    zone_be_name)) == NULL) {
2117f169c0eaSGlenn Lagasse 					be_print_err(gettext("be_copy_zones: "
2118f169c0eaSGlenn Lagasse 					    "failed to generate auto name "
2119f169c0eaSGlenn Lagasse 					    "for zone BE.\n"));
2120f169c0eaSGlenn Lagasse 					ret = BE_ERR_AUTONAME;
2121f169c0eaSGlenn Lagasse 					if (bt.nbe_zfs_props != NULL)
2122f169c0eaSGlenn Lagasse 						nvlist_free(bt.nbe_zfs_props);
2123f169c0eaSGlenn Lagasse 					goto done;
2124f169c0eaSGlenn Lagasse 				}
2125f169c0eaSGlenn Lagasse 
2126f169c0eaSGlenn Lagasse 				(void) snprintf(new_zoneroot_ds,
2127f169c0eaSGlenn Lagasse 				    sizeof (new_zoneroot_ds),
2128f169c0eaSGlenn Lagasse 				    "%s/%s", zone_container_ds,
2129f169c0eaSGlenn Lagasse 				    new_zone_be_name);
2130f169c0eaSGlenn Lagasse 				bt.nbe_name = new_zone_be_name;
2131f169c0eaSGlenn Lagasse 				bt.nbe_root_ds = new_zoneroot_ds;
2132f169c0eaSGlenn Lagasse 
2133f169c0eaSGlenn Lagasse 				/*
2134f169c0eaSGlenn Lagasse 				 * Get handle to original zone BE's root
2135f169c0eaSGlenn Lagasse 				 * dataset.
2136f169c0eaSGlenn Lagasse 				 */
2137f169c0eaSGlenn Lagasse 				if ((z_zhp = zfs_open(g_zfs, zoneroot_ds,
2138f169c0eaSGlenn Lagasse 				    ZFS_TYPE_FILESYSTEM)) == NULL) {
2139f169c0eaSGlenn Lagasse 					be_print_err(gettext("be_copy_zones: "
2140f169c0eaSGlenn Lagasse 					    "failed to open zone root "
2141f169c0eaSGlenn Lagasse 					    "dataset (%s): %s\n"),
2142f169c0eaSGlenn Lagasse 					    zoneroot_ds,
2143f169c0eaSGlenn Lagasse 					    libzfs_error_description(g_zfs));
2144f169c0eaSGlenn Lagasse 					ret = zfs_err_to_be_err(g_zfs);
2145f169c0eaSGlenn Lagasse 					if (bt.nbe_zfs_props != NULL)
2146f169c0eaSGlenn Lagasse 						nvlist_free(bt.nbe_zfs_props);
2147f169c0eaSGlenn Lagasse 					goto done;
2148f169c0eaSGlenn Lagasse 				}
2149f169c0eaSGlenn Lagasse 
2150f169c0eaSGlenn Lagasse 				/*
2151f169c0eaSGlenn Lagasse 				 * Try to clone the zone BE again. This
2152f169c0eaSGlenn Lagasse 				 * call will end up closing the zfs
2153f169c0eaSGlenn Lagasse 				 * handle passed in whether it
2154f169c0eaSGlenn Lagasse 				 * succeeds or fails.
2155f169c0eaSGlenn Lagasse 				 */
2156f169c0eaSGlenn Lagasse 				iret = be_clone_fs_callback(z_zhp, &bt);
2157f169c0eaSGlenn Lagasse 				z_zhp = NULL;
2158f169c0eaSGlenn Lagasse 				if (iret == 0) {
2159f169c0eaSGlenn Lagasse 					break;
2160f169c0eaSGlenn Lagasse 				} else if (iret != BE_ERR_BE_EXISTS) {
2161f169c0eaSGlenn Lagasse 					be_print_err(gettext("be_copy_zones: "
2162f169c0eaSGlenn Lagasse 					    "failed to create zone BE clone "
2163f169c0eaSGlenn Lagasse 					    "for new zone BE %s\n"),
2164f169c0eaSGlenn Lagasse 					    new_zone_be_name);
2165f169c0eaSGlenn Lagasse 					ret = iret;
2166f169c0eaSGlenn Lagasse 					if (bt.nbe_zfs_props != NULL)
2167f169c0eaSGlenn Lagasse 						nvlist_free(bt.nbe_zfs_props);
2168f169c0eaSGlenn Lagasse 					goto done;
2169f169c0eaSGlenn Lagasse 				}
2170f169c0eaSGlenn Lagasse 			}
2171f169c0eaSGlenn Lagasse 			/*
2172f169c0eaSGlenn Lagasse 			 * If we've exhausted the maximum number of
2173f169c0eaSGlenn Lagasse 			 * tries, free the auto zone BE name and return
2174f169c0eaSGlenn Lagasse 			 * error.
2175f169c0eaSGlenn Lagasse 			 */
2176f169c0eaSGlenn Lagasse 			if (num_retries == BE_AUTO_NAME_MAX_TRY) {
2177f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_copy_zones: failed "
2178f169c0eaSGlenn Lagasse 				    "to create a unique auto zone BE name\n"));
2179f169c0eaSGlenn Lagasse 				free(bt.nbe_name);
2180f169c0eaSGlenn Lagasse 				bt.nbe_name = NULL;
2181f169c0eaSGlenn Lagasse 				ret = BE_ERR_AUTONAME;
2182f169c0eaSGlenn Lagasse 				if (bt.nbe_zfs_props != NULL)
2183f169c0eaSGlenn Lagasse 					nvlist_free(bt.nbe_zfs_props);
2184f169c0eaSGlenn Lagasse 				goto done;
2185f169c0eaSGlenn Lagasse 			}
2186f169c0eaSGlenn Lagasse 		}
2187f169c0eaSGlenn Lagasse 
2188f169c0eaSGlenn Lagasse 		if (bt.nbe_zfs_props != NULL)
2189f169c0eaSGlenn Lagasse 			nvlist_free(bt.nbe_zfs_props);
2190f169c0eaSGlenn Lagasse 
2191f169c0eaSGlenn Lagasse 		z_zhp = NULL;
2192f169c0eaSGlenn Lagasse 
2193f169c0eaSGlenn Lagasse 		if ((z_zhp = zfs_open(g_zfs, new_zoneroot_ds,
2194f169c0eaSGlenn Lagasse 		    ZFS_TYPE_FILESYSTEM)) == NULL) {
2195f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy_zones: "
2196f169c0eaSGlenn Lagasse 			    "failed to open the new zone BE root dataset "
2197f169c0eaSGlenn Lagasse 			    "(%s): %s\n"), new_zoneroot_ds,
2198f169c0eaSGlenn Lagasse 			    libzfs_error_description(g_zfs));
2199f169c0eaSGlenn Lagasse 			ret = zfs_err_to_be_err(g_zfs);
2200f169c0eaSGlenn Lagasse 			goto done;
2201f169c0eaSGlenn Lagasse 		}
2202f169c0eaSGlenn Lagasse 
2203f169c0eaSGlenn Lagasse 		if (zfs_prop_set(z_zhp, BE_ZONE_PARENTBE_PROPERTY,
2204f169c0eaSGlenn Lagasse 		    uu_string) != 0) {
2205f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy_zones: "
2206f169c0eaSGlenn Lagasse 			    "failed to set parentbe property\n"));
2207f169c0eaSGlenn Lagasse 			ZFS_CLOSE(z_zhp);
2208f169c0eaSGlenn Lagasse 			ret = zfs_err_to_be_err(g_zfs);
2209f169c0eaSGlenn Lagasse 			goto done;
2210f169c0eaSGlenn Lagasse 		}
2211f169c0eaSGlenn Lagasse 
2212f169c0eaSGlenn Lagasse 		if (zfs_prop_set(z_zhp, BE_ZONE_ACTIVE_PROPERTY, "on") != 0) {
2213f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy_zones: "
2214f169c0eaSGlenn Lagasse 			    "failed to set active property\n"));
2215f169c0eaSGlenn Lagasse 			ZFS_CLOSE(z_zhp);
2216f169c0eaSGlenn Lagasse 			ret = zfs_err_to_be_err(g_zfs);
2217f169c0eaSGlenn Lagasse 			goto done;
2218f169c0eaSGlenn Lagasse 		}
2219f169c0eaSGlenn Lagasse 
2220f169c0eaSGlenn Lagasse 		/*
2221f169c0eaSGlenn Lagasse 		 * Generate a list of file systems from the original
2222f169c0eaSGlenn Lagasse 		 * zone BE that are legacy mounted.  We use this list
2223f169c0eaSGlenn Lagasse 		 * to determine which entries in the vfstab we need to
2224f169c0eaSGlenn Lagasse 		 * update for the new zone BE we've just created.
2225f169c0eaSGlenn Lagasse 		 */
2226f169c0eaSGlenn Lagasse 		if ((ret = be_get_legacy_fs(obe_name, obe_root_ds,
2227f169c0eaSGlenn Lagasse 		    zoneroot_ds, zoneroot, &fld)) != BE_SUCCESS) {
2228f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy_zones: "
2229f169c0eaSGlenn Lagasse 			    "failed to get legacy mounted file system "
2230f169c0eaSGlenn Lagasse 			    "list for zone %s\n"), zonename);
2231f169c0eaSGlenn Lagasse 			ZFS_CLOSE(z_zhp);
2232f169c0eaSGlenn Lagasse 			goto done;
2233f169c0eaSGlenn Lagasse 		}
2234f169c0eaSGlenn Lagasse 
2235f169c0eaSGlenn Lagasse 		/*
2236f169c0eaSGlenn Lagasse 		 * Update new zone BE's vfstab.
2237f169c0eaSGlenn Lagasse 		 */
2238f169c0eaSGlenn Lagasse 		if ((ret = be_update_zone_vfstab(z_zhp, bt.nbe_name,
2239f169c0eaSGlenn Lagasse 		    zonepath_ds, zonepath_ds, &fld)) != BE_SUCCESS) {
2240f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_copy_zones: "
2241f169c0eaSGlenn Lagasse 			    "failed to update new BE's vfstab (%s)\n"),
2242f169c0eaSGlenn Lagasse 			    bt.nbe_name);
2243f169c0eaSGlenn Lagasse 			ZFS_CLOSE(z_zhp);
2244f169c0eaSGlenn Lagasse 			be_free_fs_list(&fld);
2245f169c0eaSGlenn Lagasse 			goto done;
2246f169c0eaSGlenn Lagasse 		}
2247f169c0eaSGlenn Lagasse 
2248f169c0eaSGlenn Lagasse 		be_free_fs_list(&fld);
2249f169c0eaSGlenn Lagasse 		ZFS_CLOSE(z_zhp);
2250f169c0eaSGlenn Lagasse 	}
2251f169c0eaSGlenn Lagasse 
2252f169c0eaSGlenn Lagasse done:
2253f169c0eaSGlenn Lagasse 	free(snap_name);
2254f169c0eaSGlenn Lagasse 	if (brands != NULL)
2255f169c0eaSGlenn Lagasse 		z_free_brand_list(brands);
2256f169c0eaSGlenn Lagasse 	if (zlist != NULL)
2257f169c0eaSGlenn Lagasse 		z_free_zone_list(zlist);
2258f169c0eaSGlenn Lagasse 
2259f169c0eaSGlenn Lagasse 	if (mounted_here)
2260f169c0eaSGlenn Lagasse 		(void) _be_unmount(obe_name, 0);
2261f169c0eaSGlenn Lagasse 
2262f169c0eaSGlenn Lagasse 	ZFS_CLOSE(obe_zhp);
2263f169c0eaSGlenn Lagasse 	return (ret);
2264f169c0eaSGlenn Lagasse }
2265f169c0eaSGlenn Lagasse 
2266f169c0eaSGlenn Lagasse /*
2267f169c0eaSGlenn Lagasse  * Function:	be_clone_fs_callback
2268f169c0eaSGlenn Lagasse  * Description:	Callback function used to iterate through a BE's filesystems
2269f169c0eaSGlenn Lagasse  *		to clone them for the new BE.
2270f169c0eaSGlenn Lagasse  * Parameters:
2271f169c0eaSGlenn Lagasse  *		zhp - zfs_handle_t pointer for the filesystem being processed.
2272f169c0eaSGlenn Lagasse  *		data - be_transaction_data_t pointer providing information
2273f169c0eaSGlenn Lagasse  *			about original BE and new BE.
2274f169c0eaSGlenn Lagasse  * Return:
2275f169c0eaSGlenn Lagasse  *		0 - Success
2276f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
2277f169c0eaSGlenn Lagasse  * Scope:
2278f169c0eaSGlenn Lagasse  *		Private
2279f169c0eaSGlenn Lagasse  */
2280f169c0eaSGlenn Lagasse static int
2281f169c0eaSGlenn Lagasse be_clone_fs_callback(zfs_handle_t *zhp, void *data)
2282f169c0eaSGlenn Lagasse {
2283f169c0eaSGlenn Lagasse 	be_transaction_data_t	*bt = data;
2284f169c0eaSGlenn Lagasse 	zfs_handle_t	*zhp_ss = NULL;
2285f169c0eaSGlenn Lagasse 	char		prop_buf[MAXPATHLEN];
2286f169c0eaSGlenn Lagasse 	char		zhp_name[ZFS_MAXNAMELEN];
2287f169c0eaSGlenn Lagasse 	char		clone_ds[MAXPATHLEN];
2288f169c0eaSGlenn Lagasse 	char		ss[MAXPATHLEN];
2289f169c0eaSGlenn Lagasse 	int		ret = 0;
2290f169c0eaSGlenn Lagasse 
2291f169c0eaSGlenn Lagasse 	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, prop_buf,
2292f169c0eaSGlenn Lagasse 	    ZFS_MAXPROPLEN, NULL, NULL, 0, B_FALSE) != 0) {
2293f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_clone_fs_callback: "
2294f169c0eaSGlenn Lagasse 		    "failed to get dataset mountpoint (%s): %s\n"),
2295f169c0eaSGlenn Lagasse 		    zfs_get_name(zhp), libzfs_error_description(g_zfs));
2296f169c0eaSGlenn Lagasse 		ret = zfs_err_to_be_err(g_zfs);
2297f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2298f169c0eaSGlenn Lagasse 		return (ret);
2299f169c0eaSGlenn Lagasse 	}
2300f169c0eaSGlenn Lagasse 
2301f169c0eaSGlenn Lagasse 	if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED) != 0 &&
2302f169c0eaSGlenn Lagasse 	    strcmp(prop_buf, "legacy") != 0) {
2303f169c0eaSGlenn Lagasse 		/*
2304f169c0eaSGlenn Lagasse 		 * Since zfs can't currently handle setting the
2305f169c0eaSGlenn Lagasse 		 * mountpoint for a zoned dataset we'll have to skip
2306f169c0eaSGlenn Lagasse 		 * this dataset. This is because the mountpoint is not
2307f169c0eaSGlenn Lagasse 		 * set to "legacy".
2308f169c0eaSGlenn Lagasse 		 */
2309f169c0eaSGlenn Lagasse 		goto zoned;
2310f169c0eaSGlenn Lagasse 	}
2311f169c0eaSGlenn Lagasse 	/*
2312f169c0eaSGlenn Lagasse 	 * Get a copy of the dataset name from the zfs handle
2313f169c0eaSGlenn Lagasse 	 */
2314f169c0eaSGlenn Lagasse 	(void) strlcpy(zhp_name, zfs_get_name(zhp), sizeof (zhp_name));
2315f169c0eaSGlenn Lagasse 
2316f169c0eaSGlenn Lagasse 	/*
2317f169c0eaSGlenn Lagasse 	 * Get the clone dataset name and prepare the zfs properties for it.
2318f169c0eaSGlenn Lagasse 	 */
2319f169c0eaSGlenn Lagasse 	if ((ret = be_prep_clone_send_fs(zhp, bt, clone_ds,
2320f169c0eaSGlenn Lagasse 	    sizeof (clone_ds))) != BE_SUCCESS) {
2321f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2322f169c0eaSGlenn Lagasse 		return (ret);
2323f169c0eaSGlenn Lagasse 	}
2324f169c0eaSGlenn Lagasse 
2325f169c0eaSGlenn Lagasse 	/*
2326f169c0eaSGlenn Lagasse 	 * Generate the name of the snapshot to use.
2327f169c0eaSGlenn Lagasse 	 */
2328f169c0eaSGlenn Lagasse 	(void) snprintf(ss, sizeof (ss), "%s@%s", zhp_name,
2329f169c0eaSGlenn Lagasse 	    bt->obe_snap_name);
2330f169c0eaSGlenn Lagasse 
2331f169c0eaSGlenn Lagasse 	/*
2332f169c0eaSGlenn Lagasse 	 * Get handle to snapshot.
2333f169c0eaSGlenn Lagasse 	 */
2334f169c0eaSGlenn Lagasse 	if ((zhp_ss = zfs_open(g_zfs, ss, ZFS_TYPE_SNAPSHOT)) == NULL) {
2335f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_clone_fs_callback: "
2336f169c0eaSGlenn Lagasse 		    "failed to get handle to snapshot (%s): %s\n"), ss,
2337f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
2338f169c0eaSGlenn Lagasse 		ret = zfs_err_to_be_err(g_zfs);
2339f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2340f169c0eaSGlenn Lagasse 		return (ret);
2341f169c0eaSGlenn Lagasse 	}
2342f169c0eaSGlenn Lagasse 
2343f169c0eaSGlenn Lagasse 	/*
2344f169c0eaSGlenn Lagasse 	 * Clone the dataset.
2345f169c0eaSGlenn Lagasse 	 */
2346f169c0eaSGlenn Lagasse 	if (zfs_clone(zhp_ss, clone_ds, bt->nbe_zfs_props) != 0) {
2347f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_clone_fs_callback: "
2348f169c0eaSGlenn Lagasse 		    "failed to create clone dataset (%s): %s\n"),
2349f169c0eaSGlenn Lagasse 		    clone_ds, libzfs_error_description(g_zfs));
2350f169c0eaSGlenn Lagasse 
2351f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp_ss);
2352f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2353f169c0eaSGlenn Lagasse 
2354f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
2355f169c0eaSGlenn Lagasse 	}
2356f169c0eaSGlenn Lagasse 
2357f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp_ss);
2358f169c0eaSGlenn Lagasse 
2359f169c0eaSGlenn Lagasse zoned:
2360f169c0eaSGlenn Lagasse 	/*
2361f169c0eaSGlenn Lagasse 	 * Iterate through zhp's children datasets (if any)
2362f169c0eaSGlenn Lagasse 	 * and clone them accordingly.
2363f169c0eaSGlenn Lagasse 	 */
2364f169c0eaSGlenn Lagasse 	if ((ret = zfs_iter_filesystems(zhp, be_clone_fs_callback, bt)) != 0) {
2365f169c0eaSGlenn Lagasse 		/*
2366f169c0eaSGlenn Lagasse 		 * Error occurred while processing a child dataset.
2367f169c0eaSGlenn Lagasse 		 * Destroy this dataset and return error.
2368f169c0eaSGlenn Lagasse 		 */
2369f169c0eaSGlenn Lagasse 		zfs_handle_t	*d_zhp = NULL;
2370f169c0eaSGlenn Lagasse 
2371f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2372f169c0eaSGlenn Lagasse 
2373f169c0eaSGlenn Lagasse 		if ((d_zhp = zfs_open(g_zfs, clone_ds, ZFS_TYPE_FILESYSTEM))
2374f169c0eaSGlenn Lagasse 		    == NULL) {
2375f169c0eaSGlenn Lagasse 			return (ret);
2376f169c0eaSGlenn Lagasse 		}
2377f169c0eaSGlenn Lagasse 
2378f169c0eaSGlenn Lagasse 		(void) zfs_destroy(d_zhp, B_FALSE);
2379f169c0eaSGlenn Lagasse 		ZFS_CLOSE(d_zhp);
2380f169c0eaSGlenn Lagasse 		return (ret);
2381f169c0eaSGlenn Lagasse 	}
2382f169c0eaSGlenn Lagasse 
2383f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
2384f169c0eaSGlenn Lagasse 	return (0);
2385f169c0eaSGlenn Lagasse }
2386f169c0eaSGlenn Lagasse 
2387f169c0eaSGlenn Lagasse /*
2388f169c0eaSGlenn Lagasse  * Function:	be_send_fs_callback
2389f169c0eaSGlenn Lagasse  * Description: Callback function used to iterate through a BE's filesystems
2390f169c0eaSGlenn Lagasse  *		to copy them for the new BE.
2391f169c0eaSGlenn Lagasse  * Parameters:
2392f169c0eaSGlenn Lagasse  *		zhp - zfs_handle_t pointer for the filesystem being processed.
2393f169c0eaSGlenn Lagasse  *		data - be_transaction_data_t pointer providing information
2394f169c0eaSGlenn Lagasse  *			about original BE and new BE.
2395f169c0eaSGlenn Lagasse  * Return:
2396f169c0eaSGlenn Lagasse  *		0 - Success
2397f169c0eaSGlenn Lagasse  *		be_errnot_t - Failure
2398f169c0eaSGlenn Lagasse  * Scope:
2399f169c0eaSGlenn Lagasse  *		Private
2400f169c0eaSGlenn Lagasse  */
2401f169c0eaSGlenn Lagasse static int
2402f169c0eaSGlenn Lagasse be_send_fs_callback(zfs_handle_t *zhp, void *data)
2403f169c0eaSGlenn Lagasse {
2404f169c0eaSGlenn Lagasse 	be_transaction_data_t	*bt = data;
2405f169c0eaSGlenn Lagasse 	recvflags_t	flags = { 0 };
2406f169c0eaSGlenn Lagasse 	char		zhp_name[ZFS_MAXNAMELEN];
2407f169c0eaSGlenn Lagasse 	char		clone_ds[MAXPATHLEN];
2408f169c0eaSGlenn Lagasse 	sendflags_t	send_flags = { 0 };
2409f169c0eaSGlenn Lagasse 	int		pid, status, retval;
2410f169c0eaSGlenn Lagasse 	int		srpipe[2];
2411f169c0eaSGlenn Lagasse 	int		ret = 0;
2412f169c0eaSGlenn Lagasse 
2413f169c0eaSGlenn Lagasse 	/*
2414f169c0eaSGlenn Lagasse 	 * Get a copy of the dataset name from the zfs handle
2415f169c0eaSGlenn Lagasse 	 */
2416f169c0eaSGlenn Lagasse 	(void) strlcpy(zhp_name, zfs_get_name(zhp), sizeof (zhp_name));
2417f169c0eaSGlenn Lagasse 
2418f169c0eaSGlenn Lagasse 	/*
2419f169c0eaSGlenn Lagasse 	 * Get the clone dataset name and prepare the zfs properties for it.
2420f169c0eaSGlenn Lagasse 	 */
2421f169c0eaSGlenn Lagasse 	if ((ret = be_prep_clone_send_fs(zhp, bt, clone_ds,
2422f169c0eaSGlenn Lagasse 	    sizeof (clone_ds))) != BE_SUCCESS) {
2423f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2424f169c0eaSGlenn Lagasse 		return (ret);
2425f169c0eaSGlenn Lagasse 	}
2426f169c0eaSGlenn Lagasse 
2427f169c0eaSGlenn Lagasse 	/*
2428f169c0eaSGlenn Lagasse 	 * Create the new dataset.
2429f169c0eaSGlenn Lagasse 	 */
2430f169c0eaSGlenn Lagasse 	if (zfs_create(g_zfs, clone_ds, ZFS_TYPE_FILESYSTEM, bt->nbe_zfs_props)
2431f169c0eaSGlenn Lagasse 	    != 0) {
2432f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_send_fs_callback: "
2433f169c0eaSGlenn Lagasse 		    "failed to create new dataset '%s': %s\n"),
2434f169c0eaSGlenn Lagasse 		    clone_ds, libzfs_error_description(g_zfs));
2435f169c0eaSGlenn Lagasse 		ret = zfs_err_to_be_err(g_zfs);
2436f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2437f169c0eaSGlenn Lagasse 		return (ret);
2438f169c0eaSGlenn Lagasse 	}
2439f169c0eaSGlenn Lagasse 
2440f169c0eaSGlenn Lagasse 	/*
2441f169c0eaSGlenn Lagasse 	 * Destination file system is already created
2442f169c0eaSGlenn Lagasse 	 * hence we need to set the force flag on
2443f169c0eaSGlenn Lagasse 	 */
2444f169c0eaSGlenn Lagasse 	flags.force = B_TRUE;
2445f169c0eaSGlenn Lagasse 
2446f169c0eaSGlenn Lagasse 	/*
2447f169c0eaSGlenn Lagasse 	 * Initiate the pipe to be used for the send and recv
2448f169c0eaSGlenn Lagasse 	 */
2449f169c0eaSGlenn Lagasse 	if (pipe(srpipe) != 0) {
2450f169c0eaSGlenn Lagasse 		int err = errno;
2451f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_send_fs_callback: failed to "
2452f169c0eaSGlenn Lagasse 		    "open pipe\n"));
2453f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2454f169c0eaSGlenn Lagasse 		return (errno_to_be_err(err));
2455f169c0eaSGlenn Lagasse 	}
2456f169c0eaSGlenn Lagasse 
2457f169c0eaSGlenn Lagasse 	/*
2458f169c0eaSGlenn Lagasse 	 * Fork off a child to send the dataset
2459f169c0eaSGlenn Lagasse 	 */
2460f169c0eaSGlenn Lagasse 	if ((pid = fork()) == -1) {
2461f169c0eaSGlenn Lagasse 		int err = errno;
2462f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_send_fs_callback: failed to fork\n"));
2463f169c0eaSGlenn Lagasse 		(void) close(srpipe[0]);
2464f169c0eaSGlenn Lagasse 		(void) close(srpipe[1]);
2465f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2466f169c0eaSGlenn Lagasse 		return (errno_to_be_err(err));
2467f169c0eaSGlenn Lagasse 	} else if (pid == 0) { /* child process */
2468f169c0eaSGlenn Lagasse 		(void) close(srpipe[0]);
2469f169c0eaSGlenn Lagasse 
2470f169c0eaSGlenn Lagasse 		/* Send dataset */
247119b94df9SMatthew Ahrens 		if (zfs_send(zhp, NULL, bt->obe_snap_name, &send_flags,
2472f169c0eaSGlenn Lagasse 		    srpipe[1], NULL, NULL, NULL) != 0) {
2473f169c0eaSGlenn Lagasse 			_exit(1);
2474f169c0eaSGlenn Lagasse 		}
2475f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2476f169c0eaSGlenn Lagasse 
2477f169c0eaSGlenn Lagasse 		_exit(0);
2478f169c0eaSGlenn Lagasse 	}
2479f169c0eaSGlenn Lagasse 
2480f169c0eaSGlenn Lagasse 	(void) close(srpipe[1]);
2481f169c0eaSGlenn Lagasse 
2482f169c0eaSGlenn Lagasse 	/* Receive dataset */
248319b94df9SMatthew Ahrens 	if (zfs_receive(g_zfs, clone_ds, &flags, srpipe[0], NULL) != 0) {
2484f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_send_fs_callback: failed to "
2485f169c0eaSGlenn Lagasse 		    "recv dataset (%s)\n"), clone_ds);
2486f169c0eaSGlenn Lagasse 	}
2487f169c0eaSGlenn Lagasse 	(void) close(srpipe[0]);
2488f169c0eaSGlenn Lagasse 
2489f169c0eaSGlenn Lagasse 	/* wait for child to exit */
2490f169c0eaSGlenn Lagasse 	do {
2491f169c0eaSGlenn Lagasse 		retval = waitpid(pid, &status, 0);
2492f169c0eaSGlenn Lagasse 		if (retval == -1) {
2493f169c0eaSGlenn Lagasse 			status = 0;
2494f169c0eaSGlenn Lagasse 		}
2495f169c0eaSGlenn Lagasse 	} while (retval != pid);
2496f169c0eaSGlenn Lagasse 
2497f169c0eaSGlenn Lagasse 	if (WEXITSTATUS(status) != 0) {
2498f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_send_fs_callback: failed to "
2499f169c0eaSGlenn Lagasse 		    "send dataset (%s)\n"), zhp_name);
2500f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2501f169c0eaSGlenn Lagasse 		return (BE_ERR_ZFS);
2502f169c0eaSGlenn Lagasse 	}
2503f169c0eaSGlenn Lagasse 
2504f169c0eaSGlenn Lagasse 
2505f169c0eaSGlenn Lagasse 	/*
2506f169c0eaSGlenn Lagasse 	 * Iterate through zhp's children datasets (if any)
2507f169c0eaSGlenn Lagasse 	 * and send them accordingly.
2508f169c0eaSGlenn Lagasse 	 */
2509f169c0eaSGlenn Lagasse 	if ((ret = zfs_iter_filesystems(zhp, be_send_fs_callback, bt)) != 0) {
2510f169c0eaSGlenn Lagasse 		/*
2511f169c0eaSGlenn Lagasse 		 * Error occurred while processing a child dataset.
2512f169c0eaSGlenn Lagasse 		 * Destroy this dataset and return error.
2513f169c0eaSGlenn Lagasse 		 */
2514f169c0eaSGlenn Lagasse 		zfs_handle_t	*d_zhp = NULL;
2515f169c0eaSGlenn Lagasse 
2516f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2517f169c0eaSGlenn Lagasse 
2518f169c0eaSGlenn Lagasse 		if ((d_zhp = zfs_open(g_zfs, clone_ds, ZFS_TYPE_FILESYSTEM))
2519f169c0eaSGlenn Lagasse 		    == NULL) {
2520f169c0eaSGlenn Lagasse 			return (ret);
2521f169c0eaSGlenn Lagasse 		}
2522f169c0eaSGlenn Lagasse 
2523f169c0eaSGlenn Lagasse 		(void) zfs_destroy(d_zhp, B_FALSE);
2524f169c0eaSGlenn Lagasse 		ZFS_CLOSE(d_zhp);
2525f169c0eaSGlenn Lagasse 		return (ret);
2526f169c0eaSGlenn Lagasse 	}
2527f169c0eaSGlenn Lagasse 
2528f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
2529f169c0eaSGlenn Lagasse 	return (0);
2530f169c0eaSGlenn Lagasse }
2531f169c0eaSGlenn Lagasse 
2532f169c0eaSGlenn Lagasse /*
2533f169c0eaSGlenn Lagasse  * Function:	be_destroy_callback
2534f169c0eaSGlenn Lagasse  * Description:	Callback function used to destroy a BEs children datasets
2535f169c0eaSGlenn Lagasse  *		and snapshots.
2536f169c0eaSGlenn Lagasse  * Parameters:
2537f169c0eaSGlenn Lagasse  *		zhp - zfs_handle_t pointer to the filesystem being processed.
2538f169c0eaSGlenn Lagasse  *		data - Not used.
2539f169c0eaSGlenn Lagasse  * Returns:
2540f169c0eaSGlenn Lagasse  *		0 - Success
2541f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
2542f169c0eaSGlenn Lagasse  * Scope:
2543f169c0eaSGlenn Lagasse  *		Private
2544f169c0eaSGlenn Lagasse  */
2545f169c0eaSGlenn Lagasse static int
2546f169c0eaSGlenn Lagasse be_destroy_callback(zfs_handle_t *zhp, void *data)
2547f169c0eaSGlenn Lagasse {
2548f169c0eaSGlenn Lagasse 	be_destroy_data_t	*dd = data;
2549f169c0eaSGlenn Lagasse 	int ret = 0;
2550f169c0eaSGlenn Lagasse 
2551f169c0eaSGlenn Lagasse 	/*
2552f169c0eaSGlenn Lagasse 	 * Iterate down this file system's hierarchical children
2553f169c0eaSGlenn Lagasse 	 * and destroy them first.
2554f169c0eaSGlenn Lagasse 	 */
2555f169c0eaSGlenn Lagasse 	if ((ret = zfs_iter_filesystems(zhp, be_destroy_callback, dd)) != 0) {
2556f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2557f169c0eaSGlenn Lagasse 		return (ret);
2558f169c0eaSGlenn Lagasse 	}
2559f169c0eaSGlenn Lagasse 
2560f169c0eaSGlenn Lagasse 	if (dd->destroy_snaps) {
2561f169c0eaSGlenn Lagasse 		/*
2562f169c0eaSGlenn Lagasse 		 * Iterate through this file system's snapshots and
2563f169c0eaSGlenn Lagasse 		 * destroy them before destroying the file system itself.
2564f169c0eaSGlenn Lagasse 		 */
2565f169c0eaSGlenn Lagasse 		if ((ret = zfs_iter_snapshots(zhp, be_destroy_callback, dd))
2566f169c0eaSGlenn Lagasse 		    != 0) {
2567f169c0eaSGlenn Lagasse 			ZFS_CLOSE(zhp);
2568f169c0eaSGlenn Lagasse 			return (ret);
2569f169c0eaSGlenn Lagasse 		}
2570f169c0eaSGlenn Lagasse 	}
2571f169c0eaSGlenn Lagasse 
2572f169c0eaSGlenn Lagasse 	/* Attempt to unmount the dataset before destroying it */
2573f169c0eaSGlenn Lagasse 	if (dd->force_unmount) {
2574f169c0eaSGlenn Lagasse 		if ((ret = zfs_unmount(zhp, NULL, MS_FORCE)) != 0) {
2575f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_destroy_callback: "
2576f169c0eaSGlenn Lagasse 			    "failed to unmount %s: %s\n"), zfs_get_name(zhp),
2577f169c0eaSGlenn Lagasse 			    libzfs_error_description(g_zfs));
2578f169c0eaSGlenn Lagasse 			ret = zfs_err_to_be_err(g_zfs);
2579f169c0eaSGlenn Lagasse 			ZFS_CLOSE(zhp);
2580f169c0eaSGlenn Lagasse 			return (ret);
2581f169c0eaSGlenn Lagasse 		}
2582f169c0eaSGlenn Lagasse 	}
2583f169c0eaSGlenn Lagasse 
2584f169c0eaSGlenn Lagasse 	if (zfs_destroy(zhp, B_FALSE) != 0) {
2585f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_destroy_callback: "
2586f169c0eaSGlenn Lagasse 		    "failed to destroy %s: %s\n"), zfs_get_name(zhp),
2587f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
2588f169c0eaSGlenn Lagasse 		ret = zfs_err_to_be_err(g_zfs);
2589f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2590f169c0eaSGlenn Lagasse 		return (ret);
2591f169c0eaSGlenn Lagasse 	}
2592f169c0eaSGlenn Lagasse 
2593f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
2594f169c0eaSGlenn Lagasse 	return (0);
2595f169c0eaSGlenn Lagasse }
2596f169c0eaSGlenn Lagasse 
2597f169c0eaSGlenn Lagasse /*
2598f169c0eaSGlenn Lagasse  * Function:	be_demote_callback
2599f169c0eaSGlenn Lagasse  * Description:	This callback function is used to iterate through the file
2600f169c0eaSGlenn Lagasse  *		systems of a BE, looking for the right clone to promote such
2601f169c0eaSGlenn Lagasse  *		that this file system is left without any dependent clones.
2602f169c0eaSGlenn Lagasse  *		If the file system has no dependent clones, it doesn't need
2603f169c0eaSGlenn Lagasse  *		to get demoted, and the function will return success.
2604f169c0eaSGlenn Lagasse  *
2605f169c0eaSGlenn Lagasse  *		The demotion will be done in two passes.  The first pass
2606f169c0eaSGlenn Lagasse  *		will attempt to find the youngest snapshot that has a clone
2607f169c0eaSGlenn Lagasse  *		that is part of some other BE.  The second pass will attempt
2608f169c0eaSGlenn Lagasse  *		to find the youngest snapshot that has a clone that is not
2609f169c0eaSGlenn Lagasse  *		part of a BE.  Doing this helps ensure the aggregated set of
2610f169c0eaSGlenn Lagasse  *		file systems that compose a BE stay coordinated wrt BE
2611f169c0eaSGlenn Lagasse  *		snapshots and BE dependents.  It also prevents a random user
2612f169c0eaSGlenn Lagasse  *		generated clone of a BE dataset to become the parent of other
2613f169c0eaSGlenn Lagasse  *		BE datasets after demoting this dataset.
2614f169c0eaSGlenn Lagasse  *
2615f169c0eaSGlenn Lagasse  * Parameters:
2616f169c0eaSGlenn Lagasse  *		zhp - zfs_handle_t pointer to the current file system being
2617f169c0eaSGlenn Lagasse  *			processed.
2618f169c0eaSGlenn Lagasse  *		data - not used.
2619f169c0eaSGlenn Lagasse  * Return:
2620f169c0eaSGlenn Lagasse  *		0 - Success
2621f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
2622f169c0eaSGlenn Lagasse  * Scope:
2623f169c0eaSGlenn Lagasse  *		Private
2624f169c0eaSGlenn Lagasse  */
2625f169c0eaSGlenn Lagasse static int
2626f169c0eaSGlenn Lagasse /* LINTED */
2627f169c0eaSGlenn Lagasse be_demote_callback(zfs_handle_t *zhp, void *data)
2628f169c0eaSGlenn Lagasse {
2629f169c0eaSGlenn Lagasse 	be_demote_data_t	dd = { 0 };
2630f169c0eaSGlenn Lagasse 	int			i, ret = 0;
2631f169c0eaSGlenn Lagasse 
2632f169c0eaSGlenn Lagasse 	/*
2633f169c0eaSGlenn Lagasse 	 * Initialize be_demote_data for the first pass - this will find a
2634f169c0eaSGlenn Lagasse 	 * clone in another BE, if one exists.
2635f169c0eaSGlenn Lagasse 	 */
2636f169c0eaSGlenn Lagasse 	dd.find_in_BE = B_TRUE;
2637f169c0eaSGlenn Lagasse 
2638f169c0eaSGlenn Lagasse 	for (i = 0; i < 2; i++) {
2639f169c0eaSGlenn Lagasse 
2640f169c0eaSGlenn Lagasse 		if (zfs_iter_snapshots(zhp, be_demote_find_clone_callback, &dd)
2641f169c0eaSGlenn Lagasse 		    != 0) {
2642f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_demote_callback: "
2643f169c0eaSGlenn Lagasse 			    "failed to iterate snapshots for %s: %s\n"),
2644f169c0eaSGlenn Lagasse 			    zfs_get_name(zhp), libzfs_error_description(g_zfs));
2645f169c0eaSGlenn Lagasse 			ret = zfs_err_to_be_err(g_zfs);
2646f169c0eaSGlenn Lagasse 			ZFS_CLOSE(zhp);
2647f169c0eaSGlenn Lagasse 			return (ret);
2648f169c0eaSGlenn Lagasse 		}
2649f169c0eaSGlenn Lagasse 		if (dd.clone_zhp != NULL) {
2650f169c0eaSGlenn Lagasse 			/* Found the clone to promote.  Promote it. */
2651f169c0eaSGlenn Lagasse 			if (zfs_promote(dd.clone_zhp) != 0) {
2652f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_demote_callback: "
2653f169c0eaSGlenn Lagasse 				    "failed to promote %s: %s\n"),
2654f169c0eaSGlenn Lagasse 				    zfs_get_name(dd.clone_zhp),
2655f169c0eaSGlenn Lagasse 				    libzfs_error_description(g_zfs));
2656f169c0eaSGlenn Lagasse 				ret = zfs_err_to_be_err(g_zfs);
2657f169c0eaSGlenn Lagasse 				ZFS_CLOSE(dd.clone_zhp);
2658f169c0eaSGlenn Lagasse 				ZFS_CLOSE(zhp);
2659f169c0eaSGlenn Lagasse 				return (ret);
2660f169c0eaSGlenn Lagasse 			}
2661f169c0eaSGlenn Lagasse 
2662f169c0eaSGlenn Lagasse 			ZFS_CLOSE(dd.clone_zhp);
2663f169c0eaSGlenn Lagasse 		}
2664f169c0eaSGlenn Lagasse 
2665f169c0eaSGlenn Lagasse 		/*
2666f169c0eaSGlenn Lagasse 		 * Reinitialize be_demote_data for the second pass.
2667f169c0eaSGlenn Lagasse 		 * This will find a user created clone outside of any BE
2668f169c0eaSGlenn Lagasse 		 * namespace, if one exists.
2669f169c0eaSGlenn Lagasse 		 */
2670f169c0eaSGlenn Lagasse 		dd.clone_zhp = NULL;
2671f169c0eaSGlenn Lagasse 		dd.origin_creation = 0;
2672f169c0eaSGlenn Lagasse 		dd.snapshot = NULL;
2673f169c0eaSGlenn Lagasse 		dd.find_in_BE = B_FALSE;
2674f169c0eaSGlenn Lagasse 	}
2675f169c0eaSGlenn Lagasse 
2676f169c0eaSGlenn Lagasse 	/* Iterate down this file system's children and demote them */
2677f169c0eaSGlenn Lagasse 	if ((ret = zfs_iter_filesystems(zhp, be_demote_callback, NULL)) != 0) {
2678f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2679f169c0eaSGlenn Lagasse 		return (ret);
2680f169c0eaSGlenn Lagasse 	}
2681f169c0eaSGlenn Lagasse 
2682f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
2683f169c0eaSGlenn Lagasse 	return (0);
2684f169c0eaSGlenn Lagasse }
2685f169c0eaSGlenn Lagasse 
2686f169c0eaSGlenn Lagasse /*
2687f169c0eaSGlenn Lagasse  * Function:	be_demote_find_clone_callback
2688f169c0eaSGlenn Lagasse  * Description:	This callback function is used to iterate through the
2689f169c0eaSGlenn Lagasse  *		snapshots of a dataset, looking for the youngest snapshot
2690f169c0eaSGlenn Lagasse  *		that has a clone.  If found, it returns a reference to the
2691f169c0eaSGlenn Lagasse  *		clone back to the caller in the callback data.
2692f169c0eaSGlenn Lagasse  * Parameters:
2693f169c0eaSGlenn Lagasse  *		zhp - zfs_handle_t pointer to current snapshot being looked at
2694f169c0eaSGlenn Lagasse  *		data - be_demote_data_t pointer used to store the clone that
2695f169c0eaSGlenn Lagasse  *			is found.
2696f169c0eaSGlenn Lagasse  * Returns:
2697f169c0eaSGlenn Lagasse  *		0 - Successfully iterated through all snapshots.
2698f169c0eaSGlenn Lagasse  *		1 - Failed to iterate through all snapshots.
2699f169c0eaSGlenn Lagasse  * Scope:
2700f169c0eaSGlenn Lagasse  *		Private
2701f169c0eaSGlenn Lagasse  */
2702f169c0eaSGlenn Lagasse static int
2703f169c0eaSGlenn Lagasse be_demote_find_clone_callback(zfs_handle_t *zhp, void *data)
2704f169c0eaSGlenn Lagasse {
2705f169c0eaSGlenn Lagasse 	be_demote_data_t	*dd = data;
2706f169c0eaSGlenn Lagasse 	time_t			snap_creation;
2707f169c0eaSGlenn Lagasse 	int			zret = 0;
2708f169c0eaSGlenn Lagasse 
2709f169c0eaSGlenn Lagasse 	/* If snapshot has no clones, no need to look at it */
2710f169c0eaSGlenn Lagasse 	if (zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES) == 0) {
2711f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2712f169c0eaSGlenn Lagasse 		return (0);
2713f169c0eaSGlenn Lagasse 	}
2714f169c0eaSGlenn Lagasse 
2715f169c0eaSGlenn Lagasse 	dd->snapshot = zfs_get_name(zhp);
2716f169c0eaSGlenn Lagasse 
2717f169c0eaSGlenn Lagasse 	/* Get the creation time of this snapshot */
2718f169c0eaSGlenn Lagasse 	snap_creation = (time_t)zfs_prop_get_int(zhp, ZFS_PROP_CREATION);
2719f169c0eaSGlenn Lagasse 
2720f169c0eaSGlenn Lagasse 	/*
2721f169c0eaSGlenn Lagasse 	 * If this snapshot's creation time is greater than (or younger than)
2722f169c0eaSGlenn Lagasse 	 * the current youngest snapshot found, iterate this snapshot to
2723f169c0eaSGlenn Lagasse 	 * check if it has a clone that we're looking for.
2724f169c0eaSGlenn Lagasse 	 */
2725f169c0eaSGlenn Lagasse 	if (snap_creation >= dd->origin_creation) {
2726f169c0eaSGlenn Lagasse 		/*
2727f169c0eaSGlenn Lagasse 		 * Iterate the dependents of this snapshot to find a
2728f169c0eaSGlenn Lagasse 		 * a clone that's a direct dependent.
2729f169c0eaSGlenn Lagasse 		 */
2730f169c0eaSGlenn Lagasse 		if ((zret = zfs_iter_dependents(zhp, B_FALSE,
2731f169c0eaSGlenn Lagasse 		    be_demote_get_one_clone, dd)) == -1) {
2732f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_demote_find_clone_callback: "
2733f169c0eaSGlenn Lagasse 			    "failed to iterate dependents of %s\n"),
2734f169c0eaSGlenn Lagasse 			    zfs_get_name(zhp));
2735f169c0eaSGlenn Lagasse 			ZFS_CLOSE(zhp);
2736f169c0eaSGlenn Lagasse 			return (1);
2737f169c0eaSGlenn Lagasse 		} else if (zret == 1) {
2738f169c0eaSGlenn Lagasse 			/*
2739f169c0eaSGlenn Lagasse 			 * Found a clone, update the origin_creation time
2740f169c0eaSGlenn Lagasse 			 * in the callback data.
2741f169c0eaSGlenn Lagasse 			 */
2742f169c0eaSGlenn Lagasse 			dd->origin_creation = snap_creation;
2743f169c0eaSGlenn Lagasse 		}
2744f169c0eaSGlenn Lagasse 	}
2745f169c0eaSGlenn Lagasse 
2746f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
2747f169c0eaSGlenn Lagasse 	return (0);
2748f169c0eaSGlenn Lagasse }
2749f169c0eaSGlenn Lagasse 
2750f169c0eaSGlenn Lagasse /*
2751f169c0eaSGlenn Lagasse  * Function:	be_demote_get_one_clone
2752f169c0eaSGlenn Lagasse  * Description:	This callback function is used to iterate through a
2753f169c0eaSGlenn Lagasse  *		snapshot's dependencies to find a filesystem that is a
2754f169c0eaSGlenn Lagasse  *		direct clone of the snapshot being iterated.
2755f169c0eaSGlenn Lagasse  * Parameters:
2756f169c0eaSGlenn Lagasse  *		zhp - zfs_handle_t pointer to current dataset being looked at
2757f169c0eaSGlenn Lagasse  *		data - be_demote_data_t pointer used to store the clone
2758f169c0eaSGlenn Lagasse  *			that is found, and also provides flag to note
2759f169c0eaSGlenn Lagasse  *			whether or not the clone filesystem being searched
2760f169c0eaSGlenn Lagasse  *			for needs to be found in a BE dataset hierarchy.
2761f169c0eaSGlenn Lagasse  * Return:
2762f169c0eaSGlenn Lagasse  *		1 - Success, found clone and its also a BE's root dataset.
2763f169c0eaSGlenn Lagasse  *		0 - Failure, clone not found.
2764f169c0eaSGlenn Lagasse  * Scope:
2765f169c0eaSGlenn Lagasse  *		Private
2766f169c0eaSGlenn Lagasse  */
2767f169c0eaSGlenn Lagasse static int
2768f169c0eaSGlenn Lagasse be_demote_get_one_clone(zfs_handle_t *zhp, void *data)
2769f169c0eaSGlenn Lagasse {
2770f169c0eaSGlenn Lagasse 	be_demote_data_t	*dd = data;
2771f169c0eaSGlenn Lagasse 	char			origin[ZFS_MAXNAMELEN];
2772f169c0eaSGlenn Lagasse 	char			ds_path[ZFS_MAXNAMELEN];
2773f169c0eaSGlenn Lagasse 
2774f169c0eaSGlenn Lagasse 	if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
2775f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2776f169c0eaSGlenn Lagasse 		return (0);
2777f169c0eaSGlenn Lagasse 	}
2778f169c0eaSGlenn Lagasse 
2779f169c0eaSGlenn Lagasse 	(void) strlcpy(ds_path, zfs_get_name(zhp), sizeof (ds_path));
2780f169c0eaSGlenn Lagasse 
2781f169c0eaSGlenn Lagasse 	/*
2782f169c0eaSGlenn Lagasse 	 * Make sure this is a direct clone of the snapshot
2783f169c0eaSGlenn Lagasse 	 * we're iterating.
2784f169c0eaSGlenn Lagasse 	 */
2785f169c0eaSGlenn Lagasse 	if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin, sizeof (origin), NULL,
2786f169c0eaSGlenn Lagasse 	    NULL, 0, B_FALSE) != 0) {
2787f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_demote_get_one_clone: "
2788f169c0eaSGlenn Lagasse 		    "failed to get origin of %s: %s\n"), ds_path,
2789f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
2790f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2791f169c0eaSGlenn Lagasse 		return (0);
2792f169c0eaSGlenn Lagasse 	}
2793f169c0eaSGlenn Lagasse 	if (strcmp(origin, dd->snapshot) != 0) {
2794f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2795f169c0eaSGlenn Lagasse 		return (0);
2796f169c0eaSGlenn Lagasse 	}
2797f169c0eaSGlenn Lagasse 
2798f169c0eaSGlenn Lagasse 	if (dd->find_in_BE) {
2799f169c0eaSGlenn Lagasse 		if ((zpool_iter(g_zfs, be_check_be_roots_callback, ds_path))
2800f169c0eaSGlenn Lagasse 		    > 0) {
2801f169c0eaSGlenn Lagasse 			if (dd->clone_zhp != NULL)
2802f169c0eaSGlenn Lagasse 				ZFS_CLOSE(dd->clone_zhp);
2803f169c0eaSGlenn Lagasse 			dd->clone_zhp = zhp;
2804f169c0eaSGlenn Lagasse 			return (1);
2805f169c0eaSGlenn Lagasse 		}
2806f169c0eaSGlenn Lagasse 
2807f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2808f169c0eaSGlenn Lagasse 		return (0);
2809f169c0eaSGlenn Lagasse 	}
2810f169c0eaSGlenn Lagasse 
2811f169c0eaSGlenn Lagasse 	if (dd->clone_zhp != NULL)
2812f169c0eaSGlenn Lagasse 		ZFS_CLOSE(dd->clone_zhp);
2813f169c0eaSGlenn Lagasse 
2814f169c0eaSGlenn Lagasse 	dd->clone_zhp = zhp;
2815f169c0eaSGlenn Lagasse 	return (1);
2816f169c0eaSGlenn Lagasse }
2817f169c0eaSGlenn Lagasse 
2818f169c0eaSGlenn Lagasse /*
2819f169c0eaSGlenn Lagasse  * Function:	be_get_snap
2820f169c0eaSGlenn Lagasse  * Description:	This function takes a snapshot dataset name and separates
2821f169c0eaSGlenn Lagasse  *		out the parent dataset portion from the snapshot name.
2822f169c0eaSGlenn Lagasse  *		I.e. it finds the '@' in the snapshot dataset name and
2823f169c0eaSGlenn Lagasse  *		replaces it with a '\0'.
2824f169c0eaSGlenn Lagasse  * Parameters:
2825f169c0eaSGlenn Lagasse  *		origin - char pointer to a snapshot dataset name.  Its
2826f169c0eaSGlenn Lagasse  *			contents will be modified by this function.
2827f169c0eaSGlenn Lagasse  *		*snap - pointer to a char pointer.  Will be set to the
2828f169c0eaSGlenn Lagasse  *			snapshot name portion upon success.
2829f169c0eaSGlenn Lagasse  * Return:
2830f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
2831f169c0eaSGlenn Lagasse  *		1 - Failure
2832f169c0eaSGlenn Lagasse  * Scope:
2833f169c0eaSGlenn Lagasse  *		Private
2834f169c0eaSGlenn Lagasse  */
2835f169c0eaSGlenn Lagasse static int
2836f169c0eaSGlenn Lagasse be_get_snap(char *origin, char **snap)
2837f169c0eaSGlenn Lagasse {
2838f169c0eaSGlenn Lagasse 	char	*cp;
2839f169c0eaSGlenn Lagasse 
2840f169c0eaSGlenn Lagasse 	/*
2841f169c0eaSGlenn Lagasse 	 * Separate out the origin's dataset and snapshot portions by
2842f169c0eaSGlenn Lagasse 	 * replacing the @ with a '\0'
2843f169c0eaSGlenn Lagasse 	 */
2844f169c0eaSGlenn Lagasse 	cp = strrchr(origin, '@');
2845f169c0eaSGlenn Lagasse 	if (cp != NULL) {
2846f169c0eaSGlenn Lagasse 		if (cp[1] != NULL && cp[1] != '\0') {
2847f169c0eaSGlenn Lagasse 			cp[0] = '\0';
2848f169c0eaSGlenn Lagasse 			*snap = cp+1;
2849f169c0eaSGlenn Lagasse 		} else {
2850f169c0eaSGlenn Lagasse 			return (1);
2851f169c0eaSGlenn Lagasse 		}
2852f169c0eaSGlenn Lagasse 	} else {
2853f169c0eaSGlenn Lagasse 		return (1);
2854f169c0eaSGlenn Lagasse 	}
2855f169c0eaSGlenn Lagasse 
2856f169c0eaSGlenn Lagasse 	return (BE_SUCCESS);
2857f169c0eaSGlenn Lagasse }
2858f169c0eaSGlenn Lagasse 
2859f169c0eaSGlenn Lagasse /*
2860f169c0eaSGlenn Lagasse  * Function:	be_create_container_ds
2861f169c0eaSGlenn Lagasse  * Description:	This function checks that the zpool passed has the BE
2862f169c0eaSGlenn Lagasse  *		container dataset, and if not, then creates it.
2863f169c0eaSGlenn Lagasse  * Parameters:
2864f169c0eaSGlenn Lagasse  *		zpool - name of pool to create BE container dataset in.
2865f169c0eaSGlenn Lagasse  * Return:
2866f169c0eaSGlenn Lagasse  *		B_TRUE - Successfully created BE container dataset, or it
2867f169c0eaSGlenn Lagasse  *			already existed.
2868f169c0eaSGlenn Lagasse  *		B_FALSE - Failed to create container dataset.
2869f169c0eaSGlenn Lagasse  * Scope:
2870f169c0eaSGlenn Lagasse  *		Private
2871f169c0eaSGlenn Lagasse  */
2872f169c0eaSGlenn Lagasse static boolean_t
2873f169c0eaSGlenn Lagasse be_create_container_ds(char *zpool)
2874f169c0eaSGlenn Lagasse {
2875f169c0eaSGlenn Lagasse 	nvlist_t	*props = NULL;
2876f169c0eaSGlenn Lagasse 	char		be_container_ds[MAXPATHLEN];
2877f169c0eaSGlenn Lagasse 
2878f169c0eaSGlenn Lagasse 	/* Generate string for BE container dataset for this pool */
2879f169c0eaSGlenn Lagasse 	be_make_container_ds(zpool, be_container_ds,
2880f169c0eaSGlenn Lagasse 	    sizeof (be_container_ds));
2881f169c0eaSGlenn Lagasse 
2882f169c0eaSGlenn Lagasse 	if (!zfs_dataset_exists(g_zfs, be_container_ds, ZFS_TYPE_FILESYSTEM)) {
2883f169c0eaSGlenn Lagasse 
2884f169c0eaSGlenn Lagasse 		if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) {
2885f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_create_container_ds: "
2886f169c0eaSGlenn Lagasse 			    "nvlist_alloc failed\n"));
2887f169c0eaSGlenn Lagasse 			return (B_FALSE);
2888f169c0eaSGlenn Lagasse 		}
2889f169c0eaSGlenn Lagasse 
2890f169c0eaSGlenn Lagasse 		if (nvlist_add_string(props,
2891f169c0eaSGlenn Lagasse 		    zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
2892f169c0eaSGlenn Lagasse 		    ZFS_MOUNTPOINT_LEGACY) != 0) {
2893f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_create_container_ds: "
2894f169c0eaSGlenn Lagasse 			    "internal error: out of memory\n"));
2895f169c0eaSGlenn Lagasse 			nvlist_free(props);
2896f169c0eaSGlenn Lagasse 			return (B_FALSE);
2897f169c0eaSGlenn Lagasse 		}
2898f169c0eaSGlenn Lagasse 
2899f169c0eaSGlenn Lagasse 		if (nvlist_add_string(props,
2900f169c0eaSGlenn Lagasse 		    zfs_prop_to_name(ZFS_PROP_CANMOUNT), "off") != 0) {
2901f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_create_container_ds: "
2902f169c0eaSGlenn Lagasse 			    "internal error: out of memory\n"));
2903f169c0eaSGlenn Lagasse 			nvlist_free(props);
2904f169c0eaSGlenn Lagasse 			return (B_FALSE);
2905f169c0eaSGlenn Lagasse 		}
2906f169c0eaSGlenn Lagasse 
2907f169c0eaSGlenn Lagasse 		if (zfs_create(g_zfs, be_container_ds, ZFS_TYPE_FILESYSTEM,
2908f169c0eaSGlenn Lagasse 		    props) != 0) {
2909f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_create_container_ds: "
2910f169c0eaSGlenn Lagasse 			    "failed to create container dataset (%s): %s\n"),
2911f169c0eaSGlenn Lagasse 			    be_container_ds, libzfs_error_description(g_zfs));
2912f169c0eaSGlenn Lagasse 			nvlist_free(props);
2913f169c0eaSGlenn Lagasse 			return (B_FALSE);
2914f169c0eaSGlenn Lagasse 		}
2915f169c0eaSGlenn Lagasse 
2916f169c0eaSGlenn Lagasse 		nvlist_free(props);
2917f169c0eaSGlenn Lagasse 	}
2918f169c0eaSGlenn Lagasse 
2919f169c0eaSGlenn Lagasse 	return (B_TRUE);
2920f169c0eaSGlenn Lagasse }
2921f169c0eaSGlenn Lagasse 
2922f169c0eaSGlenn Lagasse /*
2923f169c0eaSGlenn Lagasse  * Function:	be_prep_clone_send_fs
2924f169c0eaSGlenn Lagasse  * Description:	This function takes a zfs handle to a dataset from the
2925f169c0eaSGlenn Lagasse  *		original BE, and generates the name of the clone dataset
2926f169c0eaSGlenn Lagasse  *		to create for the new BE.  It also prepares the zfs
2927f169c0eaSGlenn Lagasse  *		properties to be used for the new BE.
2928f169c0eaSGlenn Lagasse  * Parameters:
2929f169c0eaSGlenn Lagasse  *		zhp - pointer to zfs_handle_t of the file system being
2930f169c0eaSGlenn Lagasse  *			cloned/copied.
2931f169c0eaSGlenn Lagasse  *		bt - be_transaction_data pointer providing information
2932f169c0eaSGlenn Lagasse  *			about the original BE and new BE.
2933f169c0eaSGlenn Lagasse  *		clone_ds - buffer to store the name of the dataset
2934f169c0eaSGlenn Lagasse  *			for the new BE.
2935f169c0eaSGlenn Lagasse  *		clone_ds_len - length of clone_ds buffer
2936f169c0eaSGlenn Lagasse  * Return:
2937f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
2938f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
2939f169c0eaSGlenn Lagasse  * Scope:
2940f169c0eaSGlenn Lagasse  *		Private
2941f169c0eaSGlenn Lagasse  */
2942f169c0eaSGlenn Lagasse static int
2943f169c0eaSGlenn Lagasse be_prep_clone_send_fs(zfs_handle_t *zhp, be_transaction_data_t *bt,
2944f169c0eaSGlenn Lagasse     char *clone_ds, int clone_ds_len)
2945f169c0eaSGlenn Lagasse {
2946f169c0eaSGlenn Lagasse 	zprop_source_t	sourcetype;
2947f169c0eaSGlenn Lagasse 	char		source[ZFS_MAXNAMELEN];
2948f169c0eaSGlenn Lagasse 	char		zhp_name[ZFS_MAXNAMELEN];
2949f169c0eaSGlenn Lagasse 	char		mountpoint[MAXPATHLEN];
2950f169c0eaSGlenn Lagasse 	char		*child_fs = NULL;
2951f169c0eaSGlenn Lagasse 	char		*zhp_mountpoint = NULL;
2952f169c0eaSGlenn Lagasse 	int		err = 0;
2953f169c0eaSGlenn Lagasse 
2954f169c0eaSGlenn Lagasse 	/*
2955f169c0eaSGlenn Lagasse 	 * Get a copy of the dataset name zfs_name from zhp
2956f169c0eaSGlenn Lagasse 	 */
2957f169c0eaSGlenn Lagasse 	(void) strlcpy(zhp_name, zfs_get_name(zhp), sizeof (zhp_name));
2958f169c0eaSGlenn Lagasse 
2959f169c0eaSGlenn Lagasse 	/*
2960f169c0eaSGlenn Lagasse 	 * Get file system name relative to the root.
2961f169c0eaSGlenn Lagasse 	 */
2962f169c0eaSGlenn Lagasse 	if (strncmp(zhp_name, bt->obe_root_ds, strlen(bt->obe_root_ds))
2963f169c0eaSGlenn Lagasse 	    == 0) {
2964f169c0eaSGlenn Lagasse 		child_fs = zhp_name + strlen(bt->obe_root_ds);
2965f169c0eaSGlenn Lagasse 
2966f169c0eaSGlenn Lagasse 		/*
2967f169c0eaSGlenn Lagasse 		 * if child_fs is NULL, this means we're processing the
2968f169c0eaSGlenn Lagasse 		 * root dataset itself; set child_fs to the empty string.
2969f169c0eaSGlenn Lagasse 		 */
2970f169c0eaSGlenn Lagasse 		if (child_fs == NULL)
2971f169c0eaSGlenn Lagasse 			child_fs = "";
2972f169c0eaSGlenn Lagasse 	} else {
2973f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
2974f169c0eaSGlenn Lagasse 	}
2975f169c0eaSGlenn Lagasse 
2976f169c0eaSGlenn Lagasse 	/*
2977f169c0eaSGlenn Lagasse 	 * Generate the name of the clone file system.
2978f169c0eaSGlenn Lagasse 	 */
2979f169c0eaSGlenn Lagasse 	(void) snprintf(clone_ds, clone_ds_len, "%s%s", bt->nbe_root_ds,
2980f169c0eaSGlenn Lagasse 	    child_fs);
2981f169c0eaSGlenn Lagasse 
2982f169c0eaSGlenn Lagasse 	/* Get the mountpoint and source properties of the existing dataset */
2983f169c0eaSGlenn Lagasse 	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
2984f169c0eaSGlenn Lagasse 	    sizeof (mountpoint), &sourcetype, source, sizeof (source),
2985f169c0eaSGlenn Lagasse 	    B_FALSE) != 0) {
2986f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_prep_clone_send_fs: "
2987f169c0eaSGlenn Lagasse 		    "failed to get mountpoint for (%s): %s\n"),
2988f169c0eaSGlenn Lagasse 		    zhp_name, libzfs_error_description(g_zfs));
2989f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
2990f169c0eaSGlenn Lagasse 	}
2991f169c0eaSGlenn Lagasse 
2992f169c0eaSGlenn Lagasse 	/*
2993f169c0eaSGlenn Lagasse 	 * Workaround for 6668667 where a mountpoint property of "/" comes
2994f169c0eaSGlenn Lagasse 	 * back as "".
2995f169c0eaSGlenn Lagasse 	 */
2996f169c0eaSGlenn Lagasse 	if (strcmp(mountpoint, "") == 0) {
2997f169c0eaSGlenn Lagasse 		(void) snprintf(mountpoint, sizeof (mountpoint), "/");
2998f169c0eaSGlenn Lagasse 	}
2999f169c0eaSGlenn Lagasse 
3000f169c0eaSGlenn Lagasse 	/*
3001f169c0eaSGlenn Lagasse 	 * Figure out what to set as the mountpoint for the new dataset.
3002f169c0eaSGlenn Lagasse 	 * If the source of the mountpoint property is local, use the
3003f169c0eaSGlenn Lagasse 	 * mountpoint value itself.  Otherwise, remove it from the
3004f169c0eaSGlenn Lagasse 	 * zfs properties list so that it gets inherited.
3005f169c0eaSGlenn Lagasse 	 */
3006f169c0eaSGlenn Lagasse 	if (sourcetype & ZPROP_SRC_LOCAL) {
3007f169c0eaSGlenn Lagasse 		/*
3008f169c0eaSGlenn Lagasse 		 * If the BE that this file system is a part of is
3009f169c0eaSGlenn Lagasse 		 * currently mounted, strip off the BE altroot portion
3010f169c0eaSGlenn Lagasse 		 * from the mountpoint.
3011f169c0eaSGlenn Lagasse 		 */
3012f169c0eaSGlenn Lagasse 		zhp_mountpoint = mountpoint;
3013f169c0eaSGlenn Lagasse 
3014f169c0eaSGlenn Lagasse 		if (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 &&
3015f169c0eaSGlenn Lagasse 		    bt->obe_altroot != NULL && strcmp(bt->obe_altroot,
3016f169c0eaSGlenn Lagasse 		    "/") != 0 && zfs_is_mounted(zhp, NULL)) {
3017f169c0eaSGlenn Lagasse 
3018f169c0eaSGlenn Lagasse 			int altroot_len = strlen(bt->obe_altroot);
3019f169c0eaSGlenn Lagasse 
3020f169c0eaSGlenn Lagasse 			if (strncmp(bt->obe_altroot, mountpoint, altroot_len)
3021f169c0eaSGlenn Lagasse 			    == 0) {
3022f169c0eaSGlenn Lagasse 				if (mountpoint[altroot_len] == '/')
3023f169c0eaSGlenn Lagasse 					zhp_mountpoint = mountpoint +
3024f169c0eaSGlenn Lagasse 					    altroot_len;
3025f169c0eaSGlenn Lagasse 				else if (mountpoint[altroot_len] == '\0')
3026f169c0eaSGlenn Lagasse 					(void) snprintf(mountpoint,
3027f169c0eaSGlenn Lagasse 					    sizeof (mountpoint), "/");
3028f169c0eaSGlenn Lagasse 			}
3029f169c0eaSGlenn Lagasse 		}
3030f169c0eaSGlenn Lagasse 
3031f169c0eaSGlenn Lagasse 		if (nvlist_add_string(bt->nbe_zfs_props,
3032f169c0eaSGlenn Lagasse 		    zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
3033f169c0eaSGlenn Lagasse 		    zhp_mountpoint) != 0) {
3034f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_prep_clone_send_fs: "
3035f169c0eaSGlenn Lagasse 			    "internal error: out of memory\n"));
3036f169c0eaSGlenn Lagasse 			return (BE_ERR_NOMEM);
3037f169c0eaSGlenn Lagasse 		}
3038f169c0eaSGlenn Lagasse 	} else {
3039f169c0eaSGlenn Lagasse 		err = nvlist_remove_all(bt->nbe_zfs_props,
3040f169c0eaSGlenn Lagasse 		    zfs_prop_to_name(ZFS_PROP_MOUNTPOINT));
3041f169c0eaSGlenn Lagasse 		if (err != 0 && err != ENOENT) {
3042f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_prep_clone_send_fs: "
3043f169c0eaSGlenn Lagasse 			    "failed to remove mountpoint from "
3044f169c0eaSGlenn Lagasse 			    "nvlist\n"));
3045f169c0eaSGlenn Lagasse 			return (BE_ERR_INVAL);
3046f169c0eaSGlenn Lagasse 		}
3047f169c0eaSGlenn Lagasse 	}
3048f169c0eaSGlenn Lagasse 
3049f169c0eaSGlenn Lagasse 	/*
3050f169c0eaSGlenn Lagasse 	 * Set the 'canmount' property
3051f169c0eaSGlenn Lagasse 	 */
3052f169c0eaSGlenn Lagasse 	if (nvlist_add_string(bt->nbe_zfs_props,
3053f169c0eaSGlenn Lagasse 	    zfs_prop_to_name(ZFS_PROP_CANMOUNT), "noauto") != 0) {
3054f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_prep_clone_send_fs: "
3055f169c0eaSGlenn Lagasse 		    "internal error: out of memory\n"));
3056f169c0eaSGlenn Lagasse 		return (BE_ERR_NOMEM);
3057f169c0eaSGlenn Lagasse 	}
3058f169c0eaSGlenn Lagasse 
3059f169c0eaSGlenn Lagasse 	return (BE_SUCCESS);
3060f169c0eaSGlenn Lagasse }
3061f169c0eaSGlenn Lagasse 
3062f169c0eaSGlenn Lagasse /*
3063f169c0eaSGlenn Lagasse  * Function:	be_get_zone_be_name
3064f169c0eaSGlenn Lagasse  * Description:	This function takes the zones root dataset, the container
3065f169c0eaSGlenn Lagasse  *		dataset and returns the zones BE name based on the zone
3066f169c0eaSGlenn Lagasse  *		root dataset.
3067f169c0eaSGlenn Lagasse  * Parameters:
3068f169c0eaSGlenn Lagasse  *		root_ds - the zones root dataset.
3069f169c0eaSGlenn Lagasse  *		container_ds - the container dataset for the zone.
3070f169c0eaSGlenn Lagasse  * Returns:
3071f169c0eaSGlenn Lagasse  *		char * - the BE name of this zone based on the root dataset.
3072f169c0eaSGlenn Lagasse  */
3073f169c0eaSGlenn Lagasse static char *
3074f169c0eaSGlenn Lagasse be_get_zone_be_name(char *root_ds, char *container_ds)
3075f169c0eaSGlenn Lagasse {
3076f169c0eaSGlenn Lagasse 	return (root_ds + (strlen(container_ds) + 1));
3077f169c0eaSGlenn Lagasse }
3078f169c0eaSGlenn Lagasse 
3079f169c0eaSGlenn Lagasse /*
3080f169c0eaSGlenn Lagasse  * Function:	be_zone_root_exists_callback
3081f169c0eaSGlenn Lagasse  * Description:	This callback function is used to determine if a
3082f169c0eaSGlenn Lagasse  *		zone root container dataset has any children.  It always
3083f169c0eaSGlenn Lagasse  *		returns 1, signifying a hierarchical child of the zone
3084f169c0eaSGlenn Lagasse  *		root container dataset has been traversed and therefore
3085f169c0eaSGlenn Lagasse  *		it has children.
3086f169c0eaSGlenn Lagasse  * Parameters:
3087f169c0eaSGlenn Lagasse  *		zhp - zfs_handle_t pointer to current dataset being processed.
3088f169c0eaSGlenn Lagasse  *		data - not used.
3089f169c0eaSGlenn Lagasse  * Returns:
3090f169c0eaSGlenn Lagasse  *		1 - dataset exists
3091f169c0eaSGlenn Lagasse  * Scope:
3092f169c0eaSGlenn Lagasse  *		Private
3093f169c0eaSGlenn Lagasse  */
3094f169c0eaSGlenn Lagasse static int
3095f169c0eaSGlenn Lagasse /* LINTED */
3096f169c0eaSGlenn Lagasse be_zone_root_exists_callback(zfs_handle_t *zhp, void *data)
3097f169c0eaSGlenn Lagasse {
3098f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
3099f169c0eaSGlenn Lagasse 	return (1);
3100f169c0eaSGlenn Lagasse }
3101