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