dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / libbe / common / be_create.c
blob5987ce253794a9c2123eb70f14760a1e998434cc
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
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, 2015 by Delphix. All rights reserved.
26 * Copyright (c) 2016 Martin Matuska. All rights reserved.
30 * System includes
33 #include <assert.h>
34 #include <ctype.h>
35 #include <errno.h>
36 #include <libgen.h>
37 #include <libintl.h>
38 #include <libnvpair.h>
39 #include <libzfs.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <sys/mnttab.h>
44 #include <sys/mount.h>
45 #include <sys/stat.h>
46 #include <sys/types.h>
47 #include <sys/wait.h>
48 #include <unistd.h>
50 #include <libbe.h>
51 #include <libbe_priv.h>
53 /* Library wide variables */
54 libzfs_handle_t *g_zfs = NULL;
56 /* Private function prototypes */
57 static int _be_destroy(const char *, be_destroy_data_t *);
58 static int be_destroy_zones(char *, char *, be_destroy_data_t *);
59 static int be_destroy_zone_roots(char *, be_destroy_data_t *);
60 static int be_destroy_zone_roots_callback(zfs_handle_t *, void *);
61 static int be_copy_zones(char *, char *, char *);
62 static int be_clone_fs_callback(zfs_handle_t *, void *);
63 static int be_destroy_callback(zfs_handle_t *, void *);
64 static int be_send_fs_callback(zfs_handle_t *, void *);
65 static int be_demote_callback(zfs_handle_t *, void *);
66 static int be_demote_find_clone_callback(zfs_handle_t *, void *);
67 static int be_has_snapshot_callback(zfs_handle_t *, void *);
68 static int be_demote_get_one_clone(zfs_handle_t *, void *);
69 static int be_get_snap(char *, char **);
70 static int be_prep_clone_send_fs(zfs_handle_t *, be_transaction_data_t *,
71 char *, int);
72 static boolean_t be_create_container_ds(char *);
73 static char *be_get_zone_be_name(char *root_ds, char *container_ds);
74 static int be_zone_root_exists_callback(zfs_handle_t *, void *);
76 /* ******************************************************************** */
77 /* Public Functions */
78 /* ******************************************************************** */
81 * Function: be_init
82 * Description: Creates the initial datasets for a BE and leaves them
83 * unpopulated. The resultant BE can be mounted but can't
84 * yet be activated or booted.
85 * Parameters:
86 * be_attrs - pointer to nvlist_t of attributes being passed in.
87 * The following attributes are used by this function:
89 * BE_ATTR_NEW_BE_NAME *required
90 * BE_ATTR_NEW_BE_POOL *required
91 * BE_ATTR_ZFS_PROPERTIES *optional
92 * BE_ATTR_FS_NAMES *optional
93 * BE_ATTR_FS_NUM *optional
94 * BE_ATTR_SHARED_FS_NAMES *optional
95 * BE_ATTR_SHARED_FS_NUM *optional
96 * Return:
97 * BE_SUCCESS - Success
98 * be_errno_t - Failure
99 * Scope:
100 * Public
103 be_init(nvlist_t *be_attrs)
105 be_transaction_data_t bt = { 0 };
106 zpool_handle_t *zlp;
107 nvlist_t *zfs_props = NULL;
108 char nbe_root_ds[MAXPATHLEN];
109 char child_fs[MAXPATHLEN];
110 char **fs_names = NULL;
111 char **shared_fs_names = NULL;
112 uint16_t fs_num = 0;
113 uint16_t shared_fs_num = 0;
114 int nelem;
115 int i;
116 int zret = 0, ret = BE_SUCCESS;
118 /* Initialize libzfs handle */
119 if (!be_zfs_init())
120 return (BE_ERR_INIT);
122 /* Get new BE name */
123 if (nvlist_lookup_string(be_attrs, BE_ATTR_NEW_BE_NAME, &bt.nbe_name)
124 != 0) {
125 be_print_err(gettext("be_init: failed to lookup "
126 "BE_ATTR_NEW_BE_NAME attribute\n"));
127 return (BE_ERR_INVAL);
130 /* Validate new BE name */
131 if (!be_valid_be_name(bt.nbe_name)) {
132 be_print_err(gettext("be_init: invalid BE name %s\n"),
133 bt.nbe_name);
134 return (BE_ERR_INVAL);
137 /* Get zpool name */
138 if (nvlist_lookup_string(be_attrs, BE_ATTR_NEW_BE_POOL, &bt.nbe_zpool)
139 != 0) {
140 be_print_err(gettext("be_init: failed to lookup "
141 "BE_ATTR_NEW_BE_POOL attribute\n"));
142 return (BE_ERR_INVAL);
145 /* Get file system attributes */
146 nelem = 0;
147 if (nvlist_lookup_pairs(be_attrs, 0,
148 BE_ATTR_FS_NUM, DATA_TYPE_UINT16, &fs_num,
149 BE_ATTR_FS_NAMES, DATA_TYPE_STRING_ARRAY, &fs_names, &nelem,
150 NULL) != 0) {
151 be_print_err(gettext("be_init: failed to lookup fs "
152 "attributes\n"));
153 return (BE_ERR_INVAL);
155 if (nelem != fs_num) {
156 be_print_err(gettext("be_init: size of FS_NAMES array (%d) "
157 "does not match FS_NUM (%d)\n"), nelem, fs_num);
158 return (BE_ERR_INVAL);
161 /* Get shared file system attributes */
162 nelem = 0;
163 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
164 BE_ATTR_SHARED_FS_NUM, DATA_TYPE_UINT16, &shared_fs_num,
165 BE_ATTR_SHARED_FS_NAMES, DATA_TYPE_STRING_ARRAY, &shared_fs_names,
166 &nelem, NULL) != 0) {
167 be_print_err(gettext("be_init: failed to lookup "
168 "shared fs attributes\n"));
169 return (BE_ERR_INVAL);
171 if (nelem != shared_fs_num) {
172 be_print_err(gettext("be_init: size of SHARED_FS_NAMES "
173 "array does not match SHARED_FS_NUM\n"));
174 return (BE_ERR_INVAL);
177 /* Verify that nbe_zpool exists */
178 if ((zlp = zpool_open(g_zfs, bt.nbe_zpool)) == NULL) {
179 be_print_err(gettext("be_init: failed to "
180 "find existing zpool (%s): %s\n"), bt.nbe_zpool,
181 libzfs_error_description(g_zfs));
182 return (zfs_err_to_be_err(g_zfs));
184 zpool_close(zlp);
187 * Verify BE container dataset in nbe_zpool exists.
188 * If not, create it.
190 if (!be_create_container_ds(bt.nbe_zpool))
191 return (BE_ERR_CREATDS);
194 * Verify that nbe_name doesn't already exist in some pool.
196 if ((zret = zpool_iter(g_zfs, be_exists_callback, bt.nbe_name)) > 0) {
197 be_print_err(gettext("be_init: BE (%s) already exists\n"),
198 bt.nbe_name);
199 return (BE_ERR_BE_EXISTS);
200 } else if (zret < 0) {
201 be_print_err(gettext("be_init: zpool_iter failed: %s\n"),
202 libzfs_error_description(g_zfs));
203 return (zfs_err_to_be_err(g_zfs));
206 /* Generate string for BE's root dataset */
207 be_make_root_ds(bt.nbe_zpool, bt.nbe_name, nbe_root_ds,
208 sizeof (nbe_root_ds));
211 * Create property list for new BE root dataset. If some
212 * zfs properties were already provided by the caller, dup
213 * that list. Otherwise initialize a new property list.
215 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
216 BE_ATTR_ZFS_PROPERTIES, DATA_TYPE_NVLIST, &zfs_props, NULL)
217 != 0) {
218 be_print_err(gettext("be_init: failed to lookup "
219 "BE_ATTR_ZFS_PROPERTIES attribute\n"));
220 return (BE_ERR_INVAL);
222 if (zfs_props != NULL) {
223 /* Make sure its a unique nvlist */
224 if (!(zfs_props->nvl_nvflag & NV_UNIQUE_NAME) &&
225 !(zfs_props->nvl_nvflag & NV_UNIQUE_NAME_TYPE)) {
226 be_print_err(gettext("be_init: ZFS property list "
227 "not unique\n"));
228 return (BE_ERR_INVAL);
231 /* Dup the list */
232 if (nvlist_dup(zfs_props, &bt.nbe_zfs_props, 0) != 0) {
233 be_print_err(gettext("be_init: failed to dup ZFS "
234 "property list\n"));
235 return (BE_ERR_NOMEM);
237 } else {
238 /* Initialize new nvlist */
239 if (nvlist_alloc(&bt.nbe_zfs_props, NV_UNIQUE_NAME, 0) != 0) {
240 be_print_err(gettext("be_init: internal "
241 "error: out of memory\n"));
242 return (BE_ERR_NOMEM);
246 /* Set the mountpoint property for the root dataset */
247 if (nvlist_add_string(bt.nbe_zfs_props,
248 zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), "/") != 0) {
249 be_print_err(gettext("be_init: internal error "
250 "out of memory\n"));
251 ret = BE_ERR_NOMEM;
252 goto done;
255 /* Set the 'canmount' property */
256 if (nvlist_add_string(bt.nbe_zfs_props,
257 zfs_prop_to_name(ZFS_PROP_CANMOUNT), "noauto") != 0) {
258 be_print_err(gettext("be_init: internal error "
259 "out of memory\n"));
260 ret = BE_ERR_NOMEM;
261 goto done;
264 /* Create BE root dataset for the new BE */
265 if (zfs_create(g_zfs, nbe_root_ds, ZFS_TYPE_FILESYSTEM,
266 bt.nbe_zfs_props) != 0) {
267 be_print_err(gettext("be_init: failed to "
268 "create BE root dataset (%s): %s\n"), nbe_root_ds,
269 libzfs_error_description(g_zfs));
270 ret = zfs_err_to_be_err(g_zfs);
271 goto done;
274 /* Set UUID for new BE */
275 if ((ret = be_set_uuid(nbe_root_ds)) != BE_SUCCESS) {
276 be_print_err(gettext("be_init: failed to "
277 "set uuid for new BE\n"));
281 * Clear the mountpoint property so that the non-shared
282 * file systems created below inherit their mountpoints.
284 (void) nvlist_remove(bt.nbe_zfs_props,
285 zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), DATA_TYPE_STRING);
287 /* Create the new BE's non-shared file systems */
288 for (i = 0; i < fs_num && fs_names[i]; i++) {
290 * If fs == "/", skip it;
291 * we already created the root dataset
293 if (strcmp(fs_names[i], "/") == 0)
294 continue;
296 /* Generate string for file system */
297 (void) snprintf(child_fs, sizeof (child_fs), "%s%s",
298 nbe_root_ds, fs_names[i]);
300 /* Create file system */
301 if (zfs_create(g_zfs, child_fs, ZFS_TYPE_FILESYSTEM,
302 bt.nbe_zfs_props) != 0) {
303 be_print_err(gettext("be_init: failed to create "
304 "BE's child dataset (%s): %s\n"), child_fs,
305 libzfs_error_description(g_zfs));
306 ret = zfs_err_to_be_err(g_zfs);
307 goto done;
311 /* Create the new BE's shared file systems */
312 if (shared_fs_num > 0) {
313 nvlist_t *props = NULL;
315 if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) {
316 be_print_err(gettext("be_init: nvlist_alloc failed\n"));
317 ret = BE_ERR_NOMEM;
318 goto done;
321 for (i = 0; i < shared_fs_num; i++) {
322 /* Generate string for shared file system */
323 (void) snprintf(child_fs, sizeof (child_fs), "%s%s",
324 bt.nbe_zpool, shared_fs_names[i]);
326 if (nvlist_add_string(props,
327 zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
328 shared_fs_names[i]) != 0) {
329 be_print_err(gettext("be_init: "
330 "internal error: out of memory\n"));
331 nvlist_free(props);
332 ret = BE_ERR_NOMEM;
333 goto done;
336 /* Create file system if it doesn't already exist */
337 if (zfs_dataset_exists(g_zfs, child_fs,
338 ZFS_TYPE_FILESYSTEM)) {
339 continue;
341 if (zfs_create(g_zfs, child_fs, ZFS_TYPE_FILESYSTEM,
342 props) != 0) {
343 be_print_err(gettext("be_init: failed to "
344 "create BE's shared dataset (%s): %s\n"),
345 child_fs, libzfs_error_description(g_zfs));
346 ret = zfs_err_to_be_err(g_zfs);
347 nvlist_free(props);
348 goto done;
352 nvlist_free(props);
355 done:
356 nvlist_free(bt.nbe_zfs_props);
358 be_zfs_fini();
360 return (ret);
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:
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
380 be_destroy(nvlist_t *be_attrs)
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;
393 /* Initialize libzfs handle */
394 if (!be_zfs_init())
395 return (BE_ERR_INIT);
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);
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.
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);
418 if (strcmp(cur_bt.obe_name, bt.obe_name) == 0) {
419 return (BE_ERR_DESTROY_CURR_BE);
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);
432 dd.destroy_snaps = flags & BE_DESTROY_FLAG_SNAPSHOTS;
433 dd.force_unmount = flags & BE_DESTROY_FLAG_FORCE_UNMOUNT;
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));
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;
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);
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.
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);
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));
484 * Check if BE has snapshots and BE_DESTROY_FLAG_SNAPSHOTS
485 * is not set.
487 (void) zfs_iter_snapshots(zhp, B_FALSE, be_has_snapshot_callback,
488 &bs_found);
489 if (!dd.destroy_snaps && bs_found) {
490 ZFS_CLOSE(zhp);
491 return (BE_ERR_SS_EXISTS);
494 /* Get the UUID of the global BE */
495 if (getzoneid() == GLOBAL_ZONEID) {
496 if (be_get_uuid(zfs_get_name(zhp),
497 &dd.gz_be_uuid) != BE_SUCCESS) {
498 be_print_err(gettext("be_destroy: BE has no "
499 "UUID (%s)\n"), zfs_get_name(zhp));
504 * If the global BE is mounted, make sure we've been given the
505 * flag to forcibly unmount it.
507 if (zfs_is_mounted(zhp, &mp)) {
508 if (!(dd.force_unmount)) {
509 be_print_err(gettext("be_destroy: "
510 "%s is currently mounted at %s, cannot destroy\n"),
511 bt.obe_name, mp != NULL ? mp : "<unknown>");
513 free(mp);
514 ZFS_CLOSE(zhp);
515 return (BE_ERR_MOUNTED);
517 free(mp);
521 * Destroy the non-global zone BE's if we are in the global zone
522 * and there is a UUID associated with the global zone BE
524 if (getzoneid() == GLOBAL_ZONEID && !uuid_is_null(dd.gz_be_uuid)) {
525 if ((ret = be_destroy_zones(bt.obe_name, bt.obe_root_ds, &dd))
526 != BE_SUCCESS) {
527 be_print_err(gettext("be_destroy: failed to "
528 "destroy one or more zones for BE %s\n"),
529 bt.obe_name);
530 goto done;
534 /* Unmount the BE if it was mounted */
535 if (zfs_is_mounted(zhp, NULL)) {
536 if ((ret = _be_unmount(bt.obe_name, BE_UNMOUNT_FLAG_FORCE))
537 != BE_SUCCESS) {
538 be_print_err(gettext("be_destroy: "
539 "failed to unmount %s\n"), bt.obe_name);
540 ZFS_CLOSE(zhp);
541 return (ret);
544 ZFS_CLOSE(zhp);
546 /* Destroy this BE */
547 if ((ret = _be_destroy((const char *)bt.obe_root_ds, &dd))
548 != BE_SUCCESS) {
549 goto done;
552 /* Remove BE's entry from the boot menu */
553 if (getzoneid() == GLOBAL_ZONEID) {
554 if ((ret = be_remove_menu(bt.obe_name, bt.obe_zpool, NULL))
555 != BE_SUCCESS) {
556 be_print_err(gettext("be_destroy: failed to "
557 "remove BE %s from the boot menu\n"),
558 bt.obe_root_ds);
559 goto done;
563 done:
564 be_zfs_fini();
566 return (ret);
570 * Function: be_copy
571 * Description: This function makes a copy of an existing BE. If the original
572 * BE and the new BE are in the same pool, it uses zfs cloning to
573 * create the new BE, otherwise it does a physical copy.
574 * If the original BE name isn't provided, it uses the currently
575 * booted BE. If the new BE name isn't provided, it creates an
576 * auto named BE and returns that name to the caller.
577 * Parameters:
578 * be_attrs - pointer to nvlist_t of attributes being passed in.
579 * The following attributes are used by this function:
581 * BE_ATTR_ORIG_BE_NAME *optional
582 * BE_ATTR_SNAP_NAME *optional
583 * BE_ATTR_NEW_BE_NAME *optional
584 * BE_ATTR_NEW_BE_POOL *optional
585 * BE_ATTR_NEW_BE_DESC *optional
586 * BE_ATTR_ZFS_PROPERTIES *optional
587 * BE_ATTR_POLICY *optional
589 * If the BE_ATTR_NEW_BE_NAME was not passed in, upon
590 * successful BE creation, the following attribute values
591 * will be returned to the caller by setting them in the
592 * be_attrs parameter passed in:
594 * BE_ATTR_SNAP_NAME
595 * BE_ATTR_NEW_BE_NAME
596 * Return:
597 * BE_SUCCESS - Success
598 * be_errno_t - Failure
599 * Scope:
600 * Public
603 be_copy(nvlist_t *be_attrs)
605 be_transaction_data_t bt = { 0 };
606 be_fs_list_data_t fld = { 0 };
607 zfs_handle_t *zhp = NULL;
608 zpool_handle_t *zphp = NULL;
609 nvlist_t *zfs_props = NULL;
610 uuid_t uu = { 0 };
611 uuid_t parent_uu = { 0 };
612 char obe_root_ds[MAXPATHLEN];
613 char nbe_root_ds[MAXPATHLEN];
614 char ss[MAXPATHLEN];
615 char *new_mp = NULL;
616 char *obe_name = NULL;
617 boolean_t autoname = B_FALSE;
618 boolean_t be_created = B_FALSE;
619 int i;
620 int zret;
621 int ret = BE_SUCCESS;
622 struct be_defaults be_defaults;
624 /* Initialize libzfs handle */
625 if (!be_zfs_init())
626 return (BE_ERR_INIT);
628 /* Get original BE name */
629 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
630 BE_ATTR_ORIG_BE_NAME, DATA_TYPE_STRING, &obe_name, NULL) != 0) {
631 be_print_err(gettext("be_copy: failed to lookup "
632 "BE_ATTR_ORIG_BE_NAME attribute\n"));
633 return (BE_ERR_INVAL);
636 if ((ret = be_find_current_be(&bt)) != BE_SUCCESS) {
637 return (ret);
640 be_get_defaults(&be_defaults);
642 /* If original BE name not provided, use current BE */
643 if (obe_name != NULL) {
644 bt.obe_name = obe_name;
645 /* Validate original BE name */
646 if (!be_valid_be_name(bt.obe_name)) {
647 be_print_err(gettext("be_copy: "
648 "invalid BE name %s\n"), bt.obe_name);
649 return (BE_ERR_INVAL);
653 if (be_defaults.be_deflt_rpool_container) {
654 if ((zphp = zpool_open(g_zfs, bt.obe_zpool)) == NULL) {
655 be_print_err(gettext("be_get_node_data: failed to "
656 "open rpool (%s): %s\n"), bt.obe_zpool,
657 libzfs_error_description(g_zfs));
658 return (zfs_err_to_be_err(g_zfs));
660 if (be_find_zpool_callback(zphp, &bt) == 0) {
661 return (BE_ERR_BE_NOENT);
663 } else {
664 /* Find which zpool obe_name lives in */
665 if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) ==
666 0) {
667 be_print_err(gettext("be_copy: failed to "
668 "find zpool for BE (%s)\n"), bt.obe_name);
669 return (BE_ERR_BE_NOENT);
670 } else if (zret < 0) {
671 be_print_err(gettext("be_copy: "
672 "zpool_iter failed: %s\n"),
673 libzfs_error_description(g_zfs));
674 return (zfs_err_to_be_err(g_zfs));
678 /* Get snapshot name of original BE if one was provided */
679 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
680 BE_ATTR_SNAP_NAME, DATA_TYPE_STRING, &bt.obe_snap_name, NULL)
681 != 0) {
682 be_print_err(gettext("be_copy: failed to lookup "
683 "BE_ATTR_SNAP_NAME attribute\n"));
684 return (BE_ERR_INVAL);
687 /* Get new BE name */
688 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
689 BE_ATTR_NEW_BE_NAME, DATA_TYPE_STRING, &bt.nbe_name, NULL)
690 != 0) {
691 be_print_err(gettext("be_copy: failed to lookup "
692 "BE_ATTR_NEW_BE_NAME attribute\n"));
693 return (BE_ERR_INVAL);
696 /* Get zpool name to create new BE in */
697 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
698 BE_ATTR_NEW_BE_POOL, DATA_TYPE_STRING, &bt.nbe_zpool, NULL) != 0) {
699 be_print_err(gettext("be_copy: failed to lookup "
700 "BE_ATTR_NEW_BE_POOL attribute\n"));
701 return (BE_ERR_INVAL);
704 /* Get new BE's description if one was provided */
705 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
706 BE_ATTR_NEW_BE_DESC, DATA_TYPE_STRING, &bt.nbe_desc, NULL) != 0) {
707 be_print_err(gettext("be_copy: failed to lookup "
708 "BE_ATTR_NEW_BE_DESC attribute\n"));
709 return (BE_ERR_INVAL);
712 /* Get BE policy to create this snapshot under */
713 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
714 BE_ATTR_POLICY, DATA_TYPE_STRING, &bt.policy, NULL) != 0) {
715 be_print_err(gettext("be_copy: failed to lookup "
716 "BE_ATTR_POLICY attribute\n"));
717 return (BE_ERR_INVAL);
721 * Create property list for new BE root dataset. If some
722 * zfs properties were already provided by the caller, dup
723 * that list. Otherwise initialize a new property list.
725 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
726 BE_ATTR_ZFS_PROPERTIES, DATA_TYPE_NVLIST, &zfs_props, NULL)
727 != 0) {
728 be_print_err(gettext("be_copy: failed to lookup "
729 "BE_ATTR_ZFS_PROPERTIES attribute\n"));
730 return (BE_ERR_INVAL);
732 if (zfs_props != NULL) {
733 /* Make sure its a unique nvlist */
734 if (!(zfs_props->nvl_nvflag & NV_UNIQUE_NAME) &&
735 !(zfs_props->nvl_nvflag & NV_UNIQUE_NAME_TYPE)) {
736 be_print_err(gettext("be_copy: ZFS property list "
737 "not unique\n"));
738 return (BE_ERR_INVAL);
741 /* Dup the list */
742 if (nvlist_dup(zfs_props, &bt.nbe_zfs_props, 0) != 0) {
743 be_print_err(gettext("be_copy: "
744 "failed to dup ZFS property list\n"));
745 return (BE_ERR_NOMEM);
747 } else {
748 /* Initialize new nvlist */
749 if (nvlist_alloc(&bt.nbe_zfs_props, NV_UNIQUE_NAME, 0) != 0) {
750 be_print_err(gettext("be_copy: internal "
751 "error: out of memory\n"));
752 return (BE_ERR_NOMEM);
757 * If new BE name provided, validate the BE name and then verify
758 * that new BE name doesn't already exist in some pool.
760 if (bt.nbe_name) {
761 /* Validate original BE name */
762 if (!be_valid_be_name(bt.nbe_name)) {
763 be_print_err(gettext("be_copy: "
764 "invalid BE name %s\n"), bt.nbe_name);
765 ret = BE_ERR_INVAL;
766 goto done;
769 /* Verify it doesn't already exist */
770 if (getzoneid() == GLOBAL_ZONEID) {
771 if ((zret = zpool_iter(g_zfs, be_exists_callback,
772 bt.nbe_name)) > 0) {
773 be_print_err(gettext("be_copy: BE (%s) already "
774 "exists\n"), bt.nbe_name);
775 ret = BE_ERR_BE_EXISTS;
776 goto done;
777 } else if (zret < 0) {
778 be_print_err(gettext("be_copy: zpool_iter "
779 "failed: %s\n"),
780 libzfs_error_description(g_zfs));
781 ret = zfs_err_to_be_err(g_zfs);
782 goto done;
784 } else {
785 be_make_root_ds(bt.nbe_zpool, bt.nbe_name, nbe_root_ds,
786 sizeof (nbe_root_ds));
787 if (zfs_dataset_exists(g_zfs, nbe_root_ds,
788 ZFS_TYPE_FILESYSTEM)) {
789 be_print_err(gettext("be_copy: BE (%s) already "
790 "exists\n"), bt.nbe_name);
791 ret = BE_ERR_BE_EXISTS;
792 goto done;
795 } else {
797 * If an auto named BE is desired, it must be in the same
798 * pool is the original BE.
800 if (bt.nbe_zpool != NULL) {
801 be_print_err(gettext("be_copy: cannot specify pool "
802 "name when creating an auto named BE\n"));
803 ret = BE_ERR_INVAL;
804 goto done;
808 * Generate auto named BE
810 if ((bt.nbe_name = be_auto_be_name(bt.obe_name))
811 == NULL) {
812 be_print_err(gettext("be_copy: "
813 "failed to generate auto BE name\n"));
814 ret = BE_ERR_AUTONAME;
815 goto done;
818 autoname = B_TRUE;
822 * If zpool name to create new BE in is not provided,
823 * create new BE in original BE's pool.
825 if (bt.nbe_zpool == NULL) {
826 bt.nbe_zpool = bt.obe_zpool;
829 /* Get root dataset names for obe_name and nbe_name */
830 be_make_root_ds(bt.obe_zpool, bt.obe_name, obe_root_ds,
831 sizeof (obe_root_ds));
832 be_make_root_ds(bt.nbe_zpool, bt.nbe_name, nbe_root_ds,
833 sizeof (nbe_root_ds));
835 bt.obe_root_ds = obe_root_ds;
836 bt.nbe_root_ds = nbe_root_ds;
839 * If an existing snapshot name has been provided to create from,
840 * verify that it exists for the original BE's root dataset.
842 if (bt.obe_snap_name != NULL) {
844 /* Generate dataset name for snapshot to use. */
845 (void) snprintf(ss, sizeof (ss), "%s@%s", bt.obe_root_ds,
846 bt.obe_snap_name);
848 /* Verify snapshot exists */
849 if (!zfs_dataset_exists(g_zfs, ss, ZFS_TYPE_SNAPSHOT)) {
850 be_print_err(gettext("be_copy: "
851 "snapshot does not exist (%s): %s\n"), ss,
852 libzfs_error_description(g_zfs));
853 ret = BE_ERR_SS_NOENT;
854 goto done;
856 } else {
858 * Else snapshot name was not provided, generate an
859 * auto named snapshot to use as its origin.
861 if ((ret = _be_create_snapshot(bt.obe_name,
862 &bt.obe_snap_name, bt.policy)) != BE_SUCCESS) {
863 be_print_err(gettext("be_copy: "
864 "failed to create auto named snapshot\n"));
865 goto done;
868 if (nvlist_add_string(be_attrs, BE_ATTR_SNAP_NAME,
869 bt.obe_snap_name) != 0) {
870 be_print_err(gettext("be_copy: "
871 "failed to add snap name to be_attrs\n"));
872 ret = BE_ERR_NOMEM;
873 goto done;
877 /* Get handle to original BE's root dataset. */
878 if ((zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_FILESYSTEM))
879 == NULL) {
880 be_print_err(gettext("be_copy: failed to "
881 "open BE root dataset (%s): %s\n"), bt.obe_root_ds,
882 libzfs_error_description(g_zfs));
883 ret = zfs_err_to_be_err(g_zfs);
884 goto done;
887 /* If original BE is currently mounted, record its altroot. */
888 if (zfs_is_mounted(zhp, &bt.obe_altroot) && bt.obe_altroot == NULL) {
889 be_print_err(gettext("be_copy: failed to "
890 "get altroot of mounted BE %s: %s\n"),
891 bt.obe_name, libzfs_error_description(g_zfs));
892 ret = zfs_err_to_be_err(g_zfs);
893 goto done;
896 if (strcmp(bt.obe_zpool, bt.nbe_zpool) == 0) {
898 /* Do clone */
901 * Iterate through original BE's datasets and clone
902 * them to create new BE. This call will end up closing
903 * the zfs handle passed in whether it succeeds for fails.
905 if ((ret = be_clone_fs_callback(zhp, &bt)) != 0) {
906 zhp = NULL;
907 /* Creating clone BE failed */
908 if (!autoname || ret != BE_ERR_BE_EXISTS) {
909 be_print_err(gettext("be_copy: "
910 "failed to clone new BE (%s) from "
911 "orig BE (%s)\n"),
912 bt.nbe_name, bt.obe_name);
913 ret = BE_ERR_CLONE;
914 goto done;
918 * We failed to create the new BE because a BE with
919 * the auto-name we generated above has since come
920 * into existence. Regenerate a new auto-name
921 * and retry.
923 for (i = 1; i < BE_AUTO_NAME_MAX_TRY; i++) {
925 /* Sleep 1 before retrying */
926 (void) sleep(1);
928 /* Generate new auto BE name */
929 free(bt.nbe_name);
930 if ((bt.nbe_name = be_auto_be_name(bt.obe_name))
931 == NULL) {
932 be_print_err(gettext("be_copy: "
933 "failed to generate auto "
934 "BE name\n"));
935 ret = BE_ERR_AUTONAME;
936 goto done;
940 * Regenerate string for new BE's
941 * root dataset name
943 be_make_root_ds(bt.nbe_zpool, bt.nbe_name,
944 nbe_root_ds, sizeof (nbe_root_ds));
945 bt.nbe_root_ds = nbe_root_ds;
948 * Get handle to original BE's root dataset.
950 if ((zhp = zfs_open(g_zfs, bt.obe_root_ds,
951 ZFS_TYPE_FILESYSTEM)) == NULL) {
952 be_print_err(gettext("be_copy: "
953 "failed to open BE root dataset "
954 "(%s): %s\n"), bt.obe_root_ds,
955 libzfs_error_description(g_zfs));
956 ret = zfs_err_to_be_err(g_zfs);
957 goto done;
961 * Try to clone the BE again. This
962 * call will end up closing the zfs
963 * handle passed in whether it
964 * succeeds or fails.
966 ret = be_clone_fs_callback(zhp, &bt);
967 zhp = NULL;
968 if (ret == 0) {
969 break;
970 } else if (ret != BE_ERR_BE_EXISTS) {
971 be_print_err(gettext("be_copy: "
972 "failed to clone new BE "
973 "(%s) from orig BE (%s)\n"),
974 bt.nbe_name, bt.obe_name);
975 ret = BE_ERR_CLONE;
976 goto done;
981 * If we've exhausted the maximum number of
982 * tries, free the auto BE name and return
983 * error.
985 if (i == BE_AUTO_NAME_MAX_TRY) {
986 be_print_err(gettext("be_copy: failed "
987 "to create unique auto BE name\n"));
988 free(bt.nbe_name);
989 bt.nbe_name = NULL;
990 ret = BE_ERR_AUTONAME;
991 goto done;
994 zhp = NULL;
996 } else {
998 /* Do copy (i.e. send BE datasets via zfs_send/recv) */
1001 * Verify BE container dataset in nbe_zpool exists.
1002 * If not, create it.
1004 if (!be_create_container_ds(bt.nbe_zpool)) {
1005 ret = BE_ERR_CREATDS;
1006 goto done;
1010 * Iterate through original BE's datasets and send
1011 * them to the other pool. This call will end up closing
1012 * the zfs handle passed in whether it succeeds or fails.
1014 if ((ret = be_send_fs_callback(zhp, &bt)) != 0) {
1015 be_print_err(gettext("be_copy: failed to "
1016 "send BE (%s) to pool (%s)\n"), bt.obe_name,
1017 bt.nbe_zpool);
1018 ret = BE_ERR_COPY;
1019 zhp = NULL;
1020 goto done;
1022 zhp = NULL;
1026 * Set flag to note that the dataset(s) for the new BE have been
1027 * successfully created so that if a failure happens from this point
1028 * on, we know to cleanup these datasets.
1030 be_created = B_TRUE;
1033 * Validate that the new BE is mountable.
1034 * Do not attempt to mount non-global zone datasets
1035 * since they are not cloned yet.
1037 if ((ret = _be_mount(bt.nbe_name, &new_mp, BE_MOUNT_FLAG_NO_ZONES))
1038 != BE_SUCCESS) {
1039 be_print_err(gettext("be_copy: failed to "
1040 "mount newly created BE\n"));
1041 (void) _be_unmount(bt.nbe_name, 0);
1042 goto done;
1045 /* Set UUID for new BE */
1046 if (getzoneid() == GLOBAL_ZONEID) {
1047 if (be_set_uuid(bt.nbe_root_ds) != BE_SUCCESS) {
1048 be_print_err(gettext("be_copy: failed to "
1049 "set uuid for new BE\n"));
1051 } else {
1052 if ((ret = be_zone_get_parent_uuid(bt.obe_root_ds,
1053 &parent_uu)) != BE_SUCCESS) {
1054 be_print_err(gettext("be_copy: failed to get "
1055 "parentbe uuid from orig BE\n"));
1056 ret = BE_ERR_ZONE_NO_PARENTBE;
1057 goto done;
1058 } else if ((ret = be_zone_set_parent_uuid(bt.nbe_root_ds,
1059 parent_uu)) != BE_SUCCESS) {
1060 be_print_err(gettext("be_copy: failed to set "
1061 "parentbe uuid for newly created BE\n"));
1062 goto done;
1067 * Process zones outside of the private BE namespace.
1068 * This has to be done here because we need the uuid set in the
1069 * root dataset of the new BE. The uuid is use to set the parentbe
1070 * property for the new zones datasets.
1072 if (getzoneid() == GLOBAL_ZONEID &&
1073 be_get_uuid(bt.obe_root_ds, &uu) == BE_SUCCESS) {
1074 if ((ret = be_copy_zones(bt.obe_name, bt.obe_root_ds,
1075 bt.nbe_root_ds)) != BE_SUCCESS) {
1076 be_print_err(gettext("be_copy: failed to process "
1077 "zones\n"));
1078 goto done;
1083 * Generate a list of file systems from the original BE that are
1084 * legacy mounted. We use this list to determine which entries in
1085 * vfstab we need to update for the new BE we've just created.
1087 if ((ret = be_get_legacy_fs(bt.obe_name, bt.obe_root_ds, NULL, NULL,
1088 &fld)) != BE_SUCCESS) {
1089 be_print_err(gettext("be_copy: failed to "
1090 "get legacy mounted file system list for %s\n"),
1091 bt.obe_name);
1092 goto done;
1096 * Update new BE's vfstab.
1098 if ((ret = be_update_vfstab(bt.nbe_name, bt.obe_zpool, bt.nbe_zpool,
1099 &fld, new_mp)) != BE_SUCCESS) {
1100 be_print_err(gettext("be_copy: failed to "
1101 "update new BE's vfstab (%s)\n"), bt.nbe_name);
1102 goto done;
1105 /* Unmount the new BE */
1106 if ((ret = _be_unmount(bt.nbe_name, 0)) != BE_SUCCESS) {
1107 be_print_err(gettext("be_copy: failed to "
1108 "unmount newly created BE\n"));
1109 goto done;
1113 * Add boot menu entry for newly created clone
1115 if (getzoneid() == GLOBAL_ZONEID &&
1116 (ret = be_append_menu(bt.nbe_name, bt.nbe_zpool,
1117 NULL, bt.obe_root_ds, bt.nbe_desc)) != BE_SUCCESS) {
1118 be_print_err(gettext("be_copy: failed to "
1119 "add BE (%s) to boot menu\n"), bt.nbe_name);
1120 goto done;
1124 * If we succeeded in creating an auto named BE, set its policy
1125 * type and return the auto generated name to the caller by storing
1126 * it in the nvlist passed in by the caller.
1128 if (autoname) {
1129 /* Get handle to new BE's root dataset. */
1130 if ((zhp = zfs_open(g_zfs, bt.nbe_root_ds,
1131 ZFS_TYPE_FILESYSTEM)) == NULL) {
1132 be_print_err(gettext("be_copy: failed to "
1133 "open BE root dataset (%s): %s\n"), bt.nbe_root_ds,
1134 libzfs_error_description(g_zfs));
1135 ret = zfs_err_to_be_err(g_zfs);
1136 goto done;
1140 * Set the policy type property into the new BE's root dataset
1142 if (bt.policy == NULL) {
1143 /* If no policy type provided, use default type */
1144 bt.policy = be_default_policy();
1147 if (zfs_prop_set(zhp, BE_POLICY_PROPERTY, bt.policy) != 0) {
1148 be_print_err(gettext("be_copy: failed to "
1149 "set BE policy for %s: %s\n"), bt.nbe_name,
1150 libzfs_error_description(g_zfs));
1151 ret = zfs_err_to_be_err(g_zfs);
1152 goto done;
1156 * Return the auto generated name to the caller
1158 if (bt.nbe_name) {
1159 if (nvlist_add_string(be_attrs, BE_ATTR_NEW_BE_NAME,
1160 bt.nbe_name) != 0) {
1161 be_print_err(gettext("be_copy: failed to "
1162 "add snap name to be_attrs\n"));
1167 done:
1168 ZFS_CLOSE(zhp);
1169 be_free_fs_list(&fld);
1171 nvlist_free(bt.nbe_zfs_props);
1173 free(bt.obe_altroot);
1174 free(new_mp);
1177 * If a failure occurred and we already created the datasets for
1178 * the new boot environment, destroy them.
1180 if (ret != BE_SUCCESS && be_created) {
1181 be_destroy_data_t cdd = { 0 };
1183 cdd.force_unmount = B_TRUE;
1185 be_print_err(gettext("be_copy: "
1186 "destroying partially created boot environment\n"));
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);
1193 (void) _be_destroy(bt.nbe_root_ds, &cdd);
1196 be_zfs_fini();
1198 return (ret);
1201 /* ******************************************************************** */
1202 /* Semi-Private Functions */
1203 /* ******************************************************************** */
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)
1224 be_find_zpool_callback(zpool_handle_t *zlp, void *data)
1226 be_transaction_data_t *bt = data;
1227 const char *zpool = zpool_get_name(zlp);
1228 char be_root_ds[MAXPATHLEN];
1231 * Generate string for the BE's root dataset
1233 be_make_root_ds(zpool, bt->obe_name, be_root_ds, sizeof (be_root_ds));
1236 * Check if dataset exists
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);
1245 zpool_close(zlp);
1246 return (0);
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)
1263 be_exists_callback(zpool_handle_t *zlp, void *data)
1265 const char *zpool = zpool_get_name(zlp);
1266 char *be_name = data;
1267 char be_root_ds[MAXPATHLEN];
1270 * Generate string for the BE's root dataset
1272 be_make_root_ds(zpool, be_name, be_root_ds, sizeof (be_root_ds));
1275 * Check if dataset exists
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);
1283 zpool_close(zlp);
1284 return (0);
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
1300 static int
1301 be_has_snapshot_callback(zfs_handle_t *zhp, void *data)
1303 boolean_t *bs = data;
1304 if (zfs_get_name(zhp) == NULL) {
1305 zfs_close(zhp);
1306 return (1);
1308 *bs = B_TRUE;
1309 zfs_close(zhp);
1310 return (0);
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
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)
1330 be_set_uuid(char *root_ds)
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;
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);
1344 uuid_unparse(uu, uu_string);
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));
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);
1362 ZFS_CLOSE(zhp);
1364 return (ret);
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.
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)
1383 be_get_uuid(const char *root_ds, uuid_t *uu)
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;
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));
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;
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) {
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.
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;
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;
1430 done:
1431 ZFS_CLOSE(zhp);
1432 return (ret);
1435 /* ******************************************************************** */
1436 /* Private Functions */
1437 /* ******************************************************************** */
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.
1450 * Return:
1451 * BE_SUCCESS - Success
1452 * be_errno_t - Failure
1453 * Scope:
1454 * Private
1456 static int
1457 _be_destroy(const char *root_ds, be_destroy_data_t *dd)
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;
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));
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.
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);
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));
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.
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);
1508 has_origin = B_TRUE;
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.
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);
1523 /* If BE has an origin */
1524 if (has_origin) {
1527 * If origin snapshot doesn't have any other
1528 * dependents, delete the origin.
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);
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);
1544 ZFS_CLOSE(zhp);
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);
1556 /* Destroy the snapshot origin used to create this BE. */
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.
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));
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.
1579 if (libzfs_errno(g_zfs) != EZFS_EXISTS) {
1580 ret = zfs_err_to_be_err(g_zfs);
1581 ZFS_CLOSE(zhp);
1582 return (ret);
1585 ZFS_CLOSE(zhp);
1588 return (ret);
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
1607 * NOTES - Requires that the BE being deleted has no dependent BEs. If it
1608 * does, the destroy will fail.
1610 static int
1611 be_destroy_zones(char *be_name, char *be_root_ds, be_destroy_data_t *dd)
1613 int ret = BE_SUCCESS;
1614 int force_umnt = BE_UNMOUNT_FLAG_NULL;
1615 char *zonepath_ds = NULL;
1616 char *mp = NULL;
1617 zfs_handle_t *zhp = NULL;
1618 FILE *cookie;
1619 struct zoneent *ze;
1621 /* Get handle to BE's root dataset */
1622 if ((zhp = zfs_open(g_zfs, be_root_ds, ZFS_TYPE_FILESYSTEM)) ==
1623 NULL) {
1624 be_print_err(gettext("be_destroy_zones: failed to "
1625 "open BE root dataset (%s): %s\n"), be_root_ds,
1626 libzfs_error_description(g_zfs));
1627 return (zfs_err_to_be_err(g_zfs));
1631 * If the global BE is not mounted, we must mount it here to
1632 * gather data about the non-global zones in it.
1634 if (!zfs_is_mounted(zhp, &mp)) {
1635 if ((ret = _be_mount(be_name, &mp,
1636 BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
1637 be_print_err(gettext("be_destroy_zones: failed to "
1638 "mount the BE (%s) for zones processing.\n"),
1639 be_name);
1640 ZFS_CLOSE(zhp);
1641 return (ret);
1644 ZFS_CLOSE(zhp);
1646 zonecfg_set_root((const char*)mp);
1647 free(mp);
1649 /* Unmount the BE before destroying the zones in it. */
1650 if (dd->force_unmount)
1651 force_umnt = BE_UNMOUNT_FLAG_FORCE;
1652 if ((ret = _be_unmount(be_name, force_umnt)) != BE_SUCCESS) {
1653 be_print_err(gettext("be_destroy_zones: failed to "
1654 "unmount the BE (%s)\n"), be_name);
1655 goto done;
1658 cookie = setzoneent();
1659 while((ze = getzoneent_private(cookie)) != NULL) {
1661 if (strcmp(ze->zone_name, "global") == 0)
1662 continue;
1664 /* Skip zones that aren't at least installed */
1665 if (ze->zone_state < ZONE_STATE_INSTALLED)
1666 continue;
1668 if (((zonepath_ds = be_get_ds_from_dir(ze->zone_path)) == NULL) ||
1669 !be_zone_supported(zonepath_ds)) {
1670 free(zonepath_ds);
1671 continue;
1674 /* Find the zone BE root datasets for this zone. */
1675 if ((ret = be_destroy_zone_roots(zonepath_ds, dd))
1676 != BE_SUCCESS) {
1677 be_print_err(gettext("be_destroy_zones: failed to "
1678 "find and destroy zone roots for zone %s\n"),
1679 ze->zone_name);
1680 free(zonepath_ds);
1681 goto done;
1683 free(ze);
1684 free(zonepath_ds);
1686 endzoneent(cookie);
1688 done:
1690 return (ret);
1694 * Function: be_destroy_zone_roots
1695 * Description: This function will open the zone's root container dataset
1696 * and iterate the datasets within, looking for roots that
1697 * belong to the given global BE and destroying them.
1698 * If no other zone roots remain in the zone's root container
1699 * dataset, the function will destroy it and the zone's
1700 * zonepath dataset as well.
1701 * Parameters:
1702 * zonepath_ds - pointer to zone's zonepath dataset.
1703 * dd - pointer to a linked destroy data.
1704 * Returns:
1705 * BE_SUCCESS - Success
1706 * be_errno_t - Failure
1707 * Scope:
1708 * Private
1710 static int
1711 be_destroy_zone_roots(char *zonepath_ds, be_destroy_data_t *dd)
1713 zfs_handle_t *zhp;
1714 char zone_container_ds[MAXPATHLEN];
1715 int ret = BE_SUCCESS;
1717 /* Generate string for the root container dataset for this zone. */
1718 be_make_container_ds(zonepath_ds, zone_container_ds,
1719 sizeof (zone_container_ds));
1721 /* Get handle to this zone's root container dataset. */
1722 if ((zhp = zfs_open(g_zfs, zone_container_ds, ZFS_TYPE_FILESYSTEM))
1723 == NULL) {
1724 be_print_err(gettext("be_destroy_zone_roots: failed to "
1725 "open zone root container dataset (%s): %s\n"),
1726 zone_container_ds, libzfs_error_description(g_zfs));
1727 return (zfs_err_to_be_err(g_zfs));
1731 * Iterate through all of this zone's BEs, destroying the ones
1732 * that belong to the parent global BE.
1734 if ((ret = zfs_iter_filesystems(zhp, be_destroy_zone_roots_callback,
1735 dd)) != 0) {
1736 be_print_err(gettext("be_destroy_zone_roots: failed to "
1737 "destroy zone roots under zonepath dataset %s: %s\n"),
1738 zonepath_ds, libzfs_error_description(g_zfs));
1739 ZFS_CLOSE(zhp);
1740 return (ret);
1742 ZFS_CLOSE(zhp);
1744 /* Get handle to this zone's root container dataset. */
1745 if ((zhp = zfs_open(g_zfs, zone_container_ds, ZFS_TYPE_FILESYSTEM))
1746 == NULL) {
1747 be_print_err(gettext("be_destroy_zone_roots: failed to "
1748 "open zone root container dataset (%s): %s\n"),
1749 zone_container_ds, libzfs_error_description(g_zfs));
1750 return (zfs_err_to_be_err(g_zfs));
1754 * If there are no more zone roots in this zone's root container,
1755 * dataset, destroy it and the zonepath dataset as well.
1757 if (zfs_iter_filesystems(zhp, be_zone_root_exists_callback, NULL)
1758 == 0) {
1759 /* Destroy the zone root container dataset */
1760 if (zfs_unmount(zhp, NULL, MS_FORCE) != 0 ||
1761 zfs_destroy(zhp, B_FALSE) != 0) {
1762 be_print_err(gettext("be_destroy_zone_roots: failed to "
1763 "destroy zone root container dataset (%s): %s\n"),
1764 zone_container_ds, libzfs_error_description(g_zfs));
1765 goto done;
1767 ZFS_CLOSE(zhp);
1769 /* Get handle to zonepath dataset */
1770 if ((zhp = zfs_open(g_zfs, zonepath_ds, ZFS_TYPE_FILESYSTEM))
1771 == NULL) {
1772 be_print_err(gettext("be_destroy_zone_roots: failed to "
1773 "open zonepath dataset (%s): %s\n"),
1774 zonepath_ds, libzfs_error_description(g_zfs));
1775 goto done;
1778 /* Destroy zonepath dataset */
1779 if (zfs_unmount(zhp, NULL, MS_FORCE) != 0 ||
1780 zfs_destroy(zhp, B_FALSE) != 0) {
1781 be_print_err(gettext("be_destroy_zone_roots: "
1782 "failed to destroy zonepath dataest %s: %s\n"),
1783 zonepath_ds, libzfs_error_description(g_zfs));
1784 goto done;
1788 done:
1789 ZFS_CLOSE(zhp);
1790 return (ret);
1794 * Function: be_destroy_zone_roots_callback
1795 * Description: This function is used as a callback to iterate over all of
1796 * a zone's root datasets, finding the one's that
1797 * correspond to the current BE. The name's
1798 * of the zone root datasets are then destroyed by _be_destroy().
1799 * Parameters:
1800 * zhp - zfs_handle_t pointer to current dataset being processed
1801 * data - be_destroy_data_t pointer
1802 * Returns:
1803 * 0 - Success
1804 * be_errno_t - Failure
1805 * Scope:
1806 * Private
1808 static int
1809 be_destroy_zone_roots_callback(zfs_handle_t *zhp, void *data)
1811 be_destroy_data_t *dd = data;
1812 uuid_t parent_uuid = { 0 };
1813 int ret = 0;
1815 if (be_zone_get_parent_uuid(zfs_get_name(zhp), &parent_uuid)
1816 != BE_SUCCESS) {
1817 be_print_err(gettext("be_destroy_zone_roots_callback: "
1818 "could not get parentuuid for zone root dataset %s\n"),
1819 zfs_get_name(zhp));
1820 ZFS_CLOSE(zhp);
1821 return (0);
1824 if (uuid_compare(dd->gz_be_uuid, parent_uuid) == 0) {
1826 * Found a zone root dataset belonging to the parent
1827 * BE being destroyed. Destroy this zone BE.
1829 if ((ret = _be_destroy(zfs_get_name(zhp), dd)) != BE_SUCCESS) {
1830 be_print_err(gettext("be_destroy_zone_root_callback: "
1831 "failed to destroy zone root %s\n"),
1832 zfs_get_name(zhp));
1833 ZFS_CLOSE(zhp);
1834 return (ret);
1837 ZFS_CLOSE(zhp);
1839 return (ret);
1843 * Function: be_copy_zones
1844 * Description: Find valid zones and clone them to create their
1845 * corresponding datasets for the BE being created.
1846 * Parameters:
1847 * obe_name - name of source global BE being copied.
1848 * obe_root_ds - root dataset of source global BE being copied.
1849 * nbe_root_ds - root dataset of target global BE.
1850 * Return:
1851 * BE_SUCCESS - Success
1852 * be_errno_t - Failure
1853 * Scope:
1854 * Private
1856 static int
1857 be_copy_zones(char *obe_name, char *obe_root_ds, char *nbe_root_ds)
1859 int num_retries;
1860 int ret = BE_SUCCESS;
1861 int iret = 0;
1862 char *zone_be_name = NULL;
1863 char *temp_mntpt = NULL;
1864 char *new_zone_be_name = NULL;
1865 char zoneroot[MAXPATHLEN];
1866 char zoneroot_ds[MAXPATHLEN];
1867 char zone_container_ds[MAXPATHLEN];
1868 char new_zoneroot_ds[MAXPATHLEN];
1869 char ss[MAXPATHLEN];
1870 uuid_t uu = { 0 };
1871 char uu_string[UUID_PRINTABLE_STRING_LENGTH] = { 0 };
1872 be_transaction_data_t bt = { 0 };
1873 zfs_handle_t *obe_zhp = NULL;
1874 zfs_handle_t *nbe_zhp = NULL;
1875 zfs_handle_t *z_zhp = NULL;
1876 boolean_t mounted_here = B_FALSE;
1877 char *snap_name = NULL;
1878 FILE *cookie;
1879 struct zoneent *ze;
1881 /* Get handle to origin BE's root dataset */
1882 if ((obe_zhp = zfs_open(g_zfs, obe_root_ds, ZFS_TYPE_FILESYSTEM))
1883 == NULL) {
1884 be_print_err(gettext("be_copy_zones: failed to open "
1885 "the origin BE root dataset (%s) for zones processing: "
1886 "%s\n"), obe_root_ds, libzfs_error_description(g_zfs));
1887 return (zfs_err_to_be_err(g_zfs));
1890 /* Get handle to newly cloned BE's root dataset */
1891 if ((nbe_zhp = zfs_open(g_zfs, nbe_root_ds, ZFS_TYPE_FILESYSTEM))
1892 == NULL) {
1893 be_print_err(gettext("be_copy_zones: failed to open "
1894 "the new BE root dataset (%s): %s\n"), nbe_root_ds,
1895 libzfs_error_description(g_zfs));
1896 ZFS_CLOSE(obe_zhp);
1897 return (zfs_err_to_be_err(g_zfs));
1900 /* Get the uuid of the newly cloned parent BE. */
1901 if (be_get_uuid(zfs_get_name(nbe_zhp), &uu) != BE_SUCCESS) {
1902 be_print_err(gettext("be_copy_zones: "
1903 "failed to get uuid for BE root "
1904 "dataset %s\n"), zfs_get_name(nbe_zhp));
1905 ZFS_CLOSE(nbe_zhp);
1906 goto done;
1908 ZFS_CLOSE(nbe_zhp);
1909 uuid_unparse(uu, uu_string);
1912 * If the origin BE is not mounted, we must mount it here to
1913 * gather data about the non-global zones in it.
1915 if (!zfs_is_mounted(obe_zhp, &temp_mntpt)) {
1916 if ((ret = _be_mount(obe_name, &temp_mntpt,
1917 BE_MOUNT_FLAG_NULL)) != BE_SUCCESS) {
1918 be_print_err(gettext("be_copy_zones: failed to "
1919 "mount the BE (%s) for zones procesing.\n"),
1920 obe_name);
1921 goto done;
1923 mounted_here = B_TRUE;
1926 zonecfg_set_root((const char *)temp_mntpt);
1928 cookie = setzoneent();
1929 while((ze = getzoneent_private(cookie)) != NULL) {
1931 be_fs_list_data_t fld = { 0 };
1932 char zonepath_ds[MAXPATHLEN];
1933 char *ds = NULL;
1935 if (strcmp(ze->zone_name, "global") == 0)
1936 continue;
1938 /* Skip zones that aren't at least installed */
1939 if (ze->zone_state < ZONE_STATE_INSTALLED)
1940 continue;
1942 if ((ds = be_get_ds_from_dir(ze->zone_path)) == NULL)
1943 continue;
1945 (void) strlcpy(zonepath_ds, ds, sizeof (zonepath_ds));
1946 free(ds);
1947 ds = NULL;
1949 /* Get zoneroot directory */
1950 be_make_zoneroot(ze->zone_path, zoneroot, sizeof (zoneroot));
1952 /* If zonepath dataset not supported, skip it. */
1953 if (!be_zone_supported(zonepath_ds)) {
1954 free(zonepath_ds);
1955 free(ze);
1956 continue;
1959 if ((ret = be_find_active_zone_root(obe_zhp, zonepath_ds,
1960 zoneroot_ds, sizeof (zoneroot_ds))) != BE_SUCCESS) {
1961 be_print_err(gettext("be_copy_zones: "
1962 "failed to find active zone root for zone %s "
1963 "in BE %s\n"), ze->zone_name, obe_name);
1964 goto done;
1967 be_make_container_ds(zonepath_ds, zone_container_ds,
1968 sizeof (zone_container_ds));
1970 if ((z_zhp = zfs_open(g_zfs, zoneroot_ds,
1971 ZFS_TYPE_FILESYSTEM)) == NULL) {
1972 be_print_err(gettext("be_copy_zones: "
1973 "failed to open zone root dataset (%s): %s\n"),
1974 zoneroot_ds, libzfs_error_description(g_zfs));
1975 ret = zfs_err_to_be_err(g_zfs);
1976 goto done;
1979 zone_be_name =
1980 be_get_zone_be_name(zoneroot_ds, zone_container_ds);
1982 if ((new_zone_be_name = be_auto_zone_be_name(zone_container_ds,
1983 zone_be_name)) == NULL) {
1984 be_print_err(gettext("be_copy_zones: failed "
1985 "to generate auto name for zone BE.\n"));
1986 ret = BE_ERR_AUTONAME;
1987 goto done;
1990 if ((snap_name = be_auto_snap_name()) == NULL) {
1991 be_print_err(gettext("be_copy_zones: failed to "
1992 "generate snapshot name for zone BE.\n"));
1993 ret = BE_ERR_AUTONAME;
1994 goto done;
1997 (void) snprintf(ss, sizeof (ss), "%s@%s", zoneroot_ds,
1998 snap_name);
2000 if (zfs_snapshot(g_zfs, ss, B_TRUE, NULL) != 0) {
2001 be_print_err(gettext("be_copy_zones: "
2002 "failed to snapshot zone BE (%s): %s\n"),
2003 ss, libzfs_error_description(g_zfs));
2004 if (libzfs_errno(g_zfs) == EZFS_EXISTS)
2005 ret = BE_ERR_ZONE_SS_EXISTS;
2006 else
2007 ret = zfs_err_to_be_err(g_zfs);
2009 goto done;
2012 (void) snprintf(new_zoneroot_ds, sizeof (new_zoneroot_ds),
2013 "%s/%s", zone_container_ds, new_zone_be_name);
2015 bt.obe_name = zone_be_name;
2016 bt.obe_root_ds = zoneroot_ds;
2017 bt.obe_snap_name = snap_name;
2018 bt.obe_altroot = temp_mntpt;
2019 bt.nbe_name = new_zone_be_name;
2020 bt.nbe_root_ds = new_zoneroot_ds;
2022 if (nvlist_alloc(&bt.nbe_zfs_props, NV_UNIQUE_NAME, 0) != 0) {
2023 be_print_err(gettext("be_copy_zones: "
2024 "internal error: out of memory\n"));
2025 ret = BE_ERR_NOMEM;
2026 goto done;
2030 * The call to be_clone_fs_callback always closes the
2031 * zfs_handle so there's no need to close z_zhp.
2033 if ((iret = be_clone_fs_callback(z_zhp, &bt)) != 0) {
2034 z_zhp = NULL;
2035 if (iret != BE_ERR_BE_EXISTS) {
2036 be_print_err(gettext("be_copy_zones: "
2037 "failed to create zone BE clone for new "
2038 "zone BE %s\n"), new_zone_be_name);
2039 ret = iret;
2040 nvlist_free(bt.nbe_zfs_props);
2041 goto done;
2044 * We failed to create the new zone BE because a zone
2045 * BE with the auto-name we generated above has since
2046 * come into existence. Regenerate a new auto-name
2047 * and retry.
2049 for (num_retries = 1;
2050 num_retries < BE_AUTO_NAME_MAX_TRY;
2051 num_retries++) {
2053 /* Sleep 1 before retrying */
2054 (void) sleep(1);
2056 /* Generate new auto zone BE name */
2057 free(new_zone_be_name);
2058 if ((new_zone_be_name = be_auto_zone_be_name(
2059 zone_container_ds,
2060 zone_be_name)) == NULL) {
2061 be_print_err(gettext("be_copy_zones: "
2062 "failed to generate auto name "
2063 "for zone BE.\n"));
2064 ret = BE_ERR_AUTONAME;
2065 nvlist_free(bt.nbe_zfs_props);
2066 goto done;
2069 (void) snprintf(new_zoneroot_ds,
2070 sizeof (new_zoneroot_ds),
2071 "%s/%s", zone_container_ds,
2072 new_zone_be_name);
2073 bt.nbe_name = new_zone_be_name;
2074 bt.nbe_root_ds = new_zoneroot_ds;
2077 * Get handle to original zone BE's root
2078 * dataset.
2080 if ((z_zhp = zfs_open(g_zfs, zoneroot_ds,
2081 ZFS_TYPE_FILESYSTEM)) == NULL) {
2082 be_print_err(gettext("be_copy_zones: "
2083 "failed to open zone root "
2084 "dataset (%s): %s\n"),
2085 zoneroot_ds,
2086 libzfs_error_description(g_zfs));
2087 ret = zfs_err_to_be_err(g_zfs);
2088 nvlist_free(bt.nbe_zfs_props);
2089 goto done;
2093 * Try to clone the zone BE again. This
2094 * call will end up closing the zfs
2095 * handle passed in whether it
2096 * succeeds or fails.
2098 iret = be_clone_fs_callback(z_zhp, &bt);
2099 z_zhp = NULL;
2100 if (iret == 0) {
2101 break;
2102 } else if (iret != BE_ERR_BE_EXISTS) {
2103 be_print_err(gettext("be_copy_zones: "
2104 "failed to create zone BE clone "
2105 "for new zone BE %s\n"),
2106 new_zone_be_name);
2107 ret = iret;
2108 nvlist_free(bt.nbe_zfs_props);
2109 goto done;
2113 * If we've exhausted the maximum number of
2114 * tries, free the auto zone BE name and return
2115 * error.
2117 if (num_retries == BE_AUTO_NAME_MAX_TRY) {
2118 be_print_err(gettext("be_copy_zones: failed "
2119 "to create a unique auto zone BE name\n"));
2120 free(bt.nbe_name);
2121 bt.nbe_name = NULL;
2122 ret = BE_ERR_AUTONAME;
2123 nvlist_free(bt.nbe_zfs_props);
2124 goto done;
2128 nvlist_free(bt.nbe_zfs_props);
2130 z_zhp = NULL;
2132 if ((z_zhp = zfs_open(g_zfs, new_zoneroot_ds,
2133 ZFS_TYPE_FILESYSTEM)) == NULL) {
2134 be_print_err(gettext("be_copy_zones: "
2135 "failed to open the new zone BE root dataset "
2136 "(%s): %s\n"), new_zoneroot_ds,
2137 libzfs_error_description(g_zfs));
2138 ret = zfs_err_to_be_err(g_zfs);
2139 goto done;
2142 if (zfs_prop_set(z_zhp, BE_ZONE_PARENTBE_PROPERTY,
2143 uu_string) != 0) {
2144 be_print_err(gettext("be_copy_zones: "
2145 "failed to set parentbe property\n"));
2146 ZFS_CLOSE(z_zhp);
2147 ret = zfs_err_to_be_err(g_zfs);
2148 goto done;
2151 if (zfs_prop_set(z_zhp, BE_ZONE_ACTIVE_PROPERTY, "on") != 0) {
2152 be_print_err(gettext("be_copy_zones: "
2153 "failed to set active property\n"));
2154 ZFS_CLOSE(z_zhp);
2155 ret = zfs_err_to_be_err(g_zfs);
2156 goto done;
2160 * Generate a list of file systems from the original
2161 * zone BE that are legacy mounted. We use this list
2162 * to determine which entries in the vfstab we need to
2163 * update for the new zone BE we've just created.
2165 if ((ret = be_get_legacy_fs(obe_name, obe_root_ds,
2166 zoneroot_ds, zoneroot, &fld)) != BE_SUCCESS) {
2167 be_print_err(gettext("be_copy_zones: "
2168 "failed to get legacy mounted file system "
2169 "list for zone %s\n"), ze->zone_name);
2170 ZFS_CLOSE(z_zhp);
2171 goto done;
2175 * Update new zone BE's vfstab.
2177 if ((ret = be_update_zone_vfstab(z_zhp, bt.nbe_name,
2178 zonepath_ds, zonepath_ds, &fld)) != BE_SUCCESS) {
2179 be_print_err(gettext("be_copy_zones: "
2180 "failed to update new BE's vfstab (%s)\n"),
2181 bt.nbe_name);
2182 ZFS_CLOSE(z_zhp);
2183 be_free_fs_list(&fld);
2184 goto done;
2187 free(ze);
2188 be_free_fs_list(&fld);
2189 ZFS_CLOSE(z_zhp);
2191 endzoneent(cookie);
2193 done:
2194 free(snap_name);
2196 if (mounted_here)
2197 (void) _be_unmount(obe_name, 0);
2199 ZFS_CLOSE(obe_zhp);
2200 return (ret);
2204 * Function: be_clone_fs_callback
2205 * Description: Callback function used to iterate through a BE's filesystems
2206 * to clone them for the new BE.
2207 * Parameters:
2208 * zhp - zfs_handle_t pointer for the filesystem being processed.
2209 * data - be_transaction_data_t pointer providing information
2210 * about original BE and new BE.
2211 * Return:
2212 * 0 - Success
2213 * be_errno_t - Failure
2214 * Scope:
2215 * Private
2217 static int
2218 be_clone_fs_callback(zfs_handle_t *zhp, void *data)
2220 be_transaction_data_t *bt = data;
2221 zfs_handle_t *zhp_ss = NULL;
2222 char prop_buf[MAXPATHLEN];
2223 char zhp_name[ZFS_MAX_DATASET_NAME_LEN];
2224 char clone_ds[MAXPATHLEN];
2225 char ss[MAXPATHLEN];
2226 int ret = 0;
2228 if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, prop_buf,
2229 ZFS_MAXPROPLEN, NULL, NULL, 0, B_FALSE) != 0) {
2230 be_print_err(gettext("be_clone_fs_callback: "
2231 "failed to get dataset mountpoint (%s): %s\n"),
2232 zfs_get_name(zhp), libzfs_error_description(g_zfs));
2233 ret = zfs_err_to_be_err(g_zfs);
2234 ZFS_CLOSE(zhp);
2235 return (ret);
2238 if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED) != 0 &&
2239 strcmp(prop_buf, "legacy") != 0) {
2241 * Since zfs can't currently handle setting the
2242 * mountpoint for a zoned dataset we'll have to skip
2243 * this dataset. This is because the mountpoint is not
2244 * set to "legacy".
2246 goto zoned;
2249 * Get a copy of the dataset name from the zfs handle
2251 (void) strlcpy(zhp_name, zfs_get_name(zhp), sizeof (zhp_name));
2254 * Get the clone dataset name and prepare the zfs properties for it.
2256 if ((ret = be_prep_clone_send_fs(zhp, bt, clone_ds,
2257 sizeof (clone_ds))) != BE_SUCCESS) {
2258 ZFS_CLOSE(zhp);
2259 return (ret);
2263 * Generate the name of the snapshot to use.
2265 (void) snprintf(ss, sizeof (ss), "%s@%s", zhp_name,
2266 bt->obe_snap_name);
2269 * Get handle to snapshot.
2271 if ((zhp_ss = zfs_open(g_zfs, ss, ZFS_TYPE_SNAPSHOT)) == NULL) {
2272 be_print_err(gettext("be_clone_fs_callback: "
2273 "failed to get handle to snapshot (%s): %s\n"), ss,
2274 libzfs_error_description(g_zfs));
2275 ret = zfs_err_to_be_err(g_zfs);
2276 ZFS_CLOSE(zhp);
2277 return (ret);
2281 * Clone the dataset.
2283 if (zfs_clone(zhp_ss, clone_ds, bt->nbe_zfs_props) != 0) {
2284 be_print_err(gettext("be_clone_fs_callback: "
2285 "failed to create clone dataset (%s): %s\n"),
2286 clone_ds, libzfs_error_description(g_zfs));
2288 ZFS_CLOSE(zhp_ss);
2289 ZFS_CLOSE(zhp);
2291 return (zfs_err_to_be_err(g_zfs));
2294 ZFS_CLOSE(zhp_ss);
2296 zoned:
2298 * Iterate through zhp's children datasets (if any)
2299 * and clone them accordingly.
2301 if ((ret = zfs_iter_filesystems(zhp, be_clone_fs_callback, bt)) != 0) {
2303 * Error occurred while processing a child dataset.
2304 * Destroy this dataset and return error.
2306 zfs_handle_t *d_zhp = NULL;
2308 ZFS_CLOSE(zhp);
2310 if ((d_zhp = zfs_open(g_zfs, clone_ds, ZFS_TYPE_FILESYSTEM))
2311 == NULL) {
2312 return (ret);
2315 (void) zfs_destroy(d_zhp, B_FALSE);
2316 ZFS_CLOSE(d_zhp);
2317 return (ret);
2320 ZFS_CLOSE(zhp);
2321 return (0);
2325 * Function: be_send_fs_callback
2326 * Description: Callback function used to iterate through a BE's filesystems
2327 * to copy them for the new BE.
2328 * Parameters:
2329 * zhp - zfs_handle_t pointer for the filesystem being processed.
2330 * data - be_transaction_data_t pointer providing information
2331 * about original BE and new BE.
2332 * Return:
2333 * 0 - Success
2334 * be_errnot_t - Failure
2335 * Scope:
2336 * Private
2338 static int
2339 be_send_fs_callback(zfs_handle_t *zhp, void *data)
2341 be_transaction_data_t *bt = data;
2342 recvflags_t flags = { 0 };
2343 char zhp_name[ZFS_MAX_DATASET_NAME_LEN];
2344 char clone_ds[MAXPATHLEN];
2345 sendflags_t send_flags = { 0 };
2346 int pid, status, retval;
2347 int srpipe[2];
2348 int ret = 0;
2351 * Get a copy of the dataset name from the zfs handle
2353 (void) strlcpy(zhp_name, zfs_get_name(zhp), sizeof (zhp_name));
2356 * Get the clone dataset name and prepare the zfs properties for it.
2358 if ((ret = be_prep_clone_send_fs(zhp, bt, clone_ds,
2359 sizeof (clone_ds))) != BE_SUCCESS) {
2360 ZFS_CLOSE(zhp);
2361 return (ret);
2365 * Create the new dataset.
2367 if (zfs_create(g_zfs, clone_ds, ZFS_TYPE_FILESYSTEM, bt->nbe_zfs_props)
2368 != 0) {
2369 be_print_err(gettext("be_send_fs_callback: "
2370 "failed to create new dataset '%s': %s\n"),
2371 clone_ds, libzfs_error_description(g_zfs));
2372 ret = zfs_err_to_be_err(g_zfs);
2373 ZFS_CLOSE(zhp);
2374 return (ret);
2378 * Destination file system is already created
2379 * hence we need to set the force flag on
2381 flags.force = B_TRUE;
2384 * Initiate the pipe to be used for the send and recv
2386 if (pipe(srpipe) != 0) {
2387 int err = errno;
2388 be_print_err(gettext("be_send_fs_callback: failed to "
2389 "open pipe\n"));
2390 ZFS_CLOSE(zhp);
2391 return (errno_to_be_err(err));
2395 * Fork off a child to send the dataset
2397 if ((pid = fork()) == -1) {
2398 int err = errno;
2399 be_print_err(gettext("be_send_fs_callback: failed to fork\n"));
2400 (void) close(srpipe[0]);
2401 (void) close(srpipe[1]);
2402 ZFS_CLOSE(zhp);
2403 return (errno_to_be_err(err));
2404 } else if (pid == 0) { /* child process */
2405 (void) close(srpipe[0]);
2407 /* Send dataset */
2408 if (zfs_send(zhp, NULL, bt->obe_snap_name, &send_flags,
2409 srpipe[1], NULL, NULL, NULL) != 0) {
2410 _exit(1);
2412 ZFS_CLOSE(zhp);
2414 _exit(0);
2417 (void) close(srpipe[1]);
2419 /* Receive dataset */
2420 if (zfs_receive(g_zfs, clone_ds, NULL, &flags, srpipe[0], NULL) != 0) {
2421 be_print_err(gettext("be_send_fs_callback: failed to "
2422 "recv dataset (%s)\n"), clone_ds);
2424 (void) close(srpipe[0]);
2426 /* wait for child to exit */
2427 do {
2428 retval = waitpid(pid, &status, 0);
2429 if (retval == -1) {
2430 status = 0;
2432 } while (retval != pid);
2434 if (WEXITSTATUS(status) != 0) {
2435 be_print_err(gettext("be_send_fs_callback: failed to "
2436 "send dataset (%s)\n"), zhp_name);
2437 ZFS_CLOSE(zhp);
2438 return (BE_ERR_ZFS);
2443 * Iterate through zhp's children datasets (if any)
2444 * and send them accordingly.
2446 if ((ret = zfs_iter_filesystems(zhp, be_send_fs_callback, bt)) != 0) {
2448 * Error occurred while processing a child dataset.
2449 * Destroy this dataset and return error.
2451 zfs_handle_t *d_zhp = NULL;
2453 ZFS_CLOSE(zhp);
2455 if ((d_zhp = zfs_open(g_zfs, clone_ds, ZFS_TYPE_FILESYSTEM))
2456 == NULL) {
2457 return (ret);
2460 (void) zfs_destroy(d_zhp, B_FALSE);
2461 ZFS_CLOSE(d_zhp);
2462 return (ret);
2465 ZFS_CLOSE(zhp);
2466 return (0);
2470 * Function: be_destroy_callback
2471 * Description: Callback function used to destroy a BEs children datasets
2472 * and snapshots.
2473 * Parameters:
2474 * zhp - zfs_handle_t pointer to the filesystem being processed.
2475 * data - Not used.
2476 * Returns:
2477 * 0 - Success
2478 * be_errno_t - Failure
2479 * Scope:
2480 * Private
2482 static int
2483 be_destroy_callback(zfs_handle_t *zhp, void *data)
2485 be_destroy_data_t *dd = data;
2486 int ret = 0;
2489 * Iterate down this file system's hierarchical children
2490 * and destroy them first.
2492 if ((ret = zfs_iter_filesystems(zhp, be_destroy_callback, dd)) != 0) {
2493 ZFS_CLOSE(zhp);
2494 return (ret);
2497 if (dd->destroy_snaps) {
2499 * Iterate through this file system's snapshots and
2500 * destroy them before destroying the file system itself.
2502 if ((ret = zfs_iter_snapshots(zhp, B_FALSE, be_destroy_callback,
2503 dd))
2504 != 0) {
2505 ZFS_CLOSE(zhp);
2506 return (ret);
2510 /* Attempt to unmount the dataset before destroying it */
2511 if (dd->force_unmount) {
2512 if ((ret = zfs_unmount(zhp, NULL, MS_FORCE)) != 0) {
2513 be_print_err(gettext("be_destroy_callback: "
2514 "failed to unmount %s: %s\n"), zfs_get_name(zhp),
2515 libzfs_error_description(g_zfs));
2516 ret = zfs_err_to_be_err(g_zfs);
2517 ZFS_CLOSE(zhp);
2518 return (ret);
2522 if (zfs_destroy(zhp, B_FALSE) != 0) {
2523 be_print_err(gettext("be_destroy_callback: "
2524 "failed to destroy %s: %s\n"), zfs_get_name(zhp),
2525 libzfs_error_description(g_zfs));
2526 ret = zfs_err_to_be_err(g_zfs);
2527 ZFS_CLOSE(zhp);
2528 return (ret);
2531 ZFS_CLOSE(zhp);
2532 return (0);
2536 * Function: be_demote_callback
2537 * Description: This callback function is used to iterate through the file
2538 * systems of a BE, looking for the right clone to promote such
2539 * that this file system is left without any dependent clones.
2540 * If the file system has no dependent clones, it doesn't need
2541 * to get demoted, and the function will return success.
2543 * The demotion will be done in two passes. The first pass
2544 * will attempt to find the youngest snapshot that has a clone
2545 * that is part of some other BE. The second pass will attempt
2546 * to find the youngest snapshot that has a clone that is not
2547 * part of a BE. Doing this helps ensure the aggregated set of
2548 * file systems that compose a BE stay coordinated wrt BE
2549 * snapshots and BE dependents. It also prevents a random user
2550 * generated clone of a BE dataset to become the parent of other
2551 * BE datasets after demoting this dataset.
2553 * Parameters:
2554 * zhp - zfs_handle_t pointer to the current file system being
2555 * processed.
2556 * data - not used.
2557 * Return:
2558 * 0 - Success
2559 * be_errno_t - Failure
2560 * Scope:
2561 * Private
2563 static int
2564 /* LINTED */
2565 be_demote_callback(zfs_handle_t *zhp, void *data)
2567 be_demote_data_t dd = { 0 };
2568 int i, ret = 0;
2571 * Initialize be_demote_data for the first pass - this will find a
2572 * clone in another BE, if one exists.
2574 dd.find_in_BE = B_TRUE;
2576 for (i = 0; i < 2; i++) {
2578 if (zfs_iter_snapshots(zhp, B_FALSE,
2579 be_demote_find_clone_callback, &dd) != 0) {
2580 be_print_err(gettext("be_demote_callback: "
2581 "failed to iterate snapshots for %s: %s\n"),
2582 zfs_get_name(zhp), libzfs_error_description(g_zfs));
2583 ret = zfs_err_to_be_err(g_zfs);
2584 ZFS_CLOSE(zhp);
2585 return (ret);
2587 if (dd.clone_zhp != NULL) {
2588 /* Found the clone to promote. Promote it. */
2589 if (zfs_promote(dd.clone_zhp) != 0) {
2590 be_print_err(gettext("be_demote_callback: "
2591 "failed to promote %s: %s\n"),
2592 zfs_get_name(dd.clone_zhp),
2593 libzfs_error_description(g_zfs));
2594 ret = zfs_err_to_be_err(g_zfs);
2595 ZFS_CLOSE(dd.clone_zhp);
2596 ZFS_CLOSE(zhp);
2597 return (ret);
2600 ZFS_CLOSE(dd.clone_zhp);
2604 * Reinitialize be_demote_data for the second pass.
2605 * This will find a user created clone outside of any BE
2606 * namespace, if one exists.
2608 dd.clone_zhp = NULL;
2609 dd.origin_creation = 0;
2610 dd.snapshot = NULL;
2611 dd.find_in_BE = B_FALSE;
2614 /* Iterate down this file system's children and demote them */
2615 if ((ret = zfs_iter_filesystems(zhp, be_demote_callback, NULL)) != 0) {
2616 ZFS_CLOSE(zhp);
2617 return (ret);
2620 ZFS_CLOSE(zhp);
2621 return (0);
2625 * Function: be_demote_find_clone_callback
2626 * Description: This callback function is used to iterate through the
2627 * snapshots of a dataset, looking for the youngest snapshot
2628 * that has a clone. If found, it returns a reference to the
2629 * clone back to the caller in the callback data.
2630 * Parameters:
2631 * zhp - zfs_handle_t pointer to current snapshot being looked at
2632 * data - be_demote_data_t pointer used to store the clone that
2633 * is found.
2634 * Returns:
2635 * 0 - Successfully iterated through all snapshots.
2636 * 1 - Failed to iterate through all snapshots.
2637 * Scope:
2638 * Private
2640 static int
2641 be_demote_find_clone_callback(zfs_handle_t *zhp, void *data)
2643 be_demote_data_t *dd = data;
2644 time_t snap_creation;
2645 int zret = 0;
2647 /* If snapshot has no clones, no need to look at it */
2648 if (zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES) == 0) {
2649 ZFS_CLOSE(zhp);
2650 return (0);
2653 dd->snapshot = zfs_get_name(zhp);
2655 /* Get the creation time of this snapshot */
2656 snap_creation = (time_t)zfs_prop_get_int(zhp, ZFS_PROP_CREATION);
2659 * If this snapshot's creation time is greater than (or younger than)
2660 * the current youngest snapshot found, iterate this snapshot to
2661 * check if it has a clone that we're looking for.
2663 if (snap_creation >= dd->origin_creation) {
2665 * Iterate the dependents of this snapshot to find a
2666 * a clone that's a direct dependent.
2668 if ((zret = zfs_iter_dependents(zhp, B_FALSE,
2669 be_demote_get_one_clone, dd)) == -1) {
2670 be_print_err(gettext("be_demote_find_clone_callback: "
2671 "failed to iterate dependents of %s\n"),
2672 zfs_get_name(zhp));
2673 ZFS_CLOSE(zhp);
2674 return (1);
2675 } else if (zret == 1) {
2677 * Found a clone, update the origin_creation time
2678 * in the callback data.
2680 dd->origin_creation = snap_creation;
2684 ZFS_CLOSE(zhp);
2685 return (0);
2689 * Function: be_demote_get_one_clone
2690 * Description: This callback function is used to iterate through a
2691 * snapshot's dependencies to find a filesystem that is a
2692 * direct clone of the snapshot being iterated.
2693 * Parameters:
2694 * zhp - zfs_handle_t pointer to current dataset being looked at
2695 * data - be_demote_data_t pointer used to store the clone
2696 * that is found, and also provides flag to note
2697 * whether or not the clone filesystem being searched
2698 * for needs to be found in a BE dataset hierarchy.
2699 * Return:
2700 * 1 - Success, found clone and its also a BE's root dataset.
2701 * 0 - Failure, clone not found.
2702 * Scope:
2703 * Private
2705 static int
2706 be_demote_get_one_clone(zfs_handle_t *zhp, void *data)
2708 be_demote_data_t *dd = data;
2709 char origin[ZFS_MAX_DATASET_NAME_LEN];
2710 char ds_path[ZFS_MAX_DATASET_NAME_LEN];
2712 if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
2713 ZFS_CLOSE(zhp);
2714 return (0);
2717 (void) strlcpy(ds_path, zfs_get_name(zhp), sizeof (ds_path));
2720 * Make sure this is a direct clone of the snapshot
2721 * we're iterating.
2723 if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin, sizeof (origin), NULL,
2724 NULL, 0, B_FALSE) != 0) {
2725 be_print_err(gettext("be_demote_get_one_clone: "
2726 "failed to get origin of %s: %s\n"), ds_path,
2727 libzfs_error_description(g_zfs));
2728 ZFS_CLOSE(zhp);
2729 return (0);
2731 if (strcmp(origin, dd->snapshot) != 0) {
2732 ZFS_CLOSE(zhp);
2733 return (0);
2736 if (dd->find_in_BE) {
2737 if ((zpool_iter(g_zfs, be_check_be_roots_callback, ds_path))
2738 > 0) {
2739 if (dd->clone_zhp != NULL)
2740 ZFS_CLOSE(dd->clone_zhp);
2741 dd->clone_zhp = zhp;
2742 return (1);
2745 ZFS_CLOSE(zhp);
2746 return (0);
2749 if (dd->clone_zhp != NULL)
2750 ZFS_CLOSE(dd->clone_zhp);
2752 dd->clone_zhp = zhp;
2753 return (1);
2757 * Function: be_get_snap
2758 * Description: This function takes a snapshot dataset name and separates
2759 * out the parent dataset portion from the snapshot name.
2760 * I.e. it finds the '@' in the snapshot dataset name and
2761 * replaces it with a '\0'.
2762 * Parameters:
2763 * origin - char pointer to a snapshot dataset name. Its
2764 * contents will be modified by this function.
2765 * *snap - pointer to a char pointer. Will be set to the
2766 * snapshot name portion upon success.
2767 * Return:
2768 * BE_SUCCESS - Success
2769 * 1 - Failure
2770 * Scope:
2771 * Private
2773 static int
2774 be_get_snap(char *origin, char **snap)
2776 char *cp;
2779 * Separate out the origin's dataset and snapshot portions by
2780 * replacing the @ with a '\0'
2782 cp = strrchr(origin, '@');
2783 if (cp != NULL) {
2784 if (cp[1] != '\0') {
2785 cp[0] = '\0';
2786 *snap = cp+1;
2787 } else {
2788 return (1);
2790 } else {
2791 return (1);
2794 return (BE_SUCCESS);
2798 * Function: be_create_container_ds
2799 * Description: This function checks that the zpool passed has the BE
2800 * container dataset, and if not, then creates it.
2801 * Parameters:
2802 * zpool - name of pool to create BE container dataset in.
2803 * Return:
2804 * B_TRUE - Successfully created BE container dataset, or it
2805 * already existed.
2806 * B_FALSE - Failed to create container dataset.
2807 * Scope:
2808 * Private
2810 static boolean_t
2811 be_create_container_ds(char *zpool)
2813 nvlist_t *props = NULL;
2814 char be_container_ds[MAXPATHLEN];
2816 /* Generate string for BE container dataset for this pool */
2817 be_make_container_ds(zpool, be_container_ds,
2818 sizeof (be_container_ds));
2820 if (!zfs_dataset_exists(g_zfs, be_container_ds, ZFS_TYPE_FILESYSTEM)) {
2822 if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) {
2823 be_print_err(gettext("be_create_container_ds: "
2824 "nvlist_alloc failed\n"));
2825 return (B_FALSE);
2828 if (nvlist_add_string(props,
2829 zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
2830 ZFS_MOUNTPOINT_LEGACY) != 0) {
2831 be_print_err(gettext("be_create_container_ds: "
2832 "internal error: out of memory\n"));
2833 nvlist_free(props);
2834 return (B_FALSE);
2837 if (nvlist_add_string(props,
2838 zfs_prop_to_name(ZFS_PROP_CANMOUNT), "off") != 0) {
2839 be_print_err(gettext("be_create_container_ds: "
2840 "internal error: out of memory\n"));
2841 nvlist_free(props);
2842 return (B_FALSE);
2845 if (zfs_create(g_zfs, be_container_ds, ZFS_TYPE_FILESYSTEM,
2846 props) != 0) {
2847 be_print_err(gettext("be_create_container_ds: "
2848 "failed to create container dataset (%s): %s\n"),
2849 be_container_ds, libzfs_error_description(g_zfs));
2850 nvlist_free(props);
2851 return (B_FALSE);
2854 nvlist_free(props);
2857 return (B_TRUE);
2861 * Function: be_prep_clone_send_fs
2862 * Description: This function takes a zfs handle to a dataset from the
2863 * original BE, and generates the name of the clone dataset
2864 * to create for the new BE. It also prepares the zfs
2865 * properties to be used for the new BE.
2866 * Parameters:
2867 * zhp - pointer to zfs_handle_t of the file system being
2868 * cloned/copied.
2869 * bt - be_transaction_data pointer providing information
2870 * about the original BE and new BE.
2871 * clone_ds - buffer to store the name of the dataset
2872 * for the new BE.
2873 * clone_ds_len - length of clone_ds buffer
2874 * Return:
2875 * BE_SUCCESS - Success
2876 * be_errno_t - Failure
2877 * Scope:
2878 * Private
2880 static int
2881 be_prep_clone_send_fs(zfs_handle_t *zhp, be_transaction_data_t *bt,
2882 char *clone_ds, int clone_ds_len)
2884 zprop_source_t sourcetype;
2885 char source[ZFS_MAX_DATASET_NAME_LEN];
2886 char zhp_name[ZFS_MAX_DATASET_NAME_LEN];
2887 char mountpoint[MAXPATHLEN];
2888 char *child_fs = NULL;
2889 char *zhp_mountpoint = NULL;
2890 int err = 0;
2893 * Get a copy of the dataset name zfs_name from zhp
2895 (void) strlcpy(zhp_name, zfs_get_name(zhp), sizeof (zhp_name));
2898 * Get file system name relative to the root.
2900 if (strncmp(zhp_name, bt->obe_root_ds, strlen(bt->obe_root_ds))
2901 == 0) {
2902 child_fs = zhp_name + strlen(bt->obe_root_ds);
2905 * if child_fs is NULL, this means we're processing the
2906 * root dataset itself; set child_fs to the empty string.
2908 if (child_fs == NULL)
2909 child_fs = "";
2910 } else {
2911 return (BE_ERR_INVAL);
2915 * Generate the name of the clone file system.
2917 (void) snprintf(clone_ds, clone_ds_len, "%s%s", bt->nbe_root_ds,
2918 child_fs);
2920 /* Get the mountpoint and source properties of the existing dataset */
2921 if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
2922 sizeof (mountpoint), &sourcetype, source, sizeof (source),
2923 B_FALSE) != 0) {
2924 be_print_err(gettext("be_prep_clone_send_fs: "
2925 "failed to get mountpoint for (%s): %s\n"),
2926 zhp_name, libzfs_error_description(g_zfs));
2927 return (zfs_err_to_be_err(g_zfs));
2931 * Workaround for 6668667 where a mountpoint property of "/" comes
2932 * back as "".
2934 if (strcmp(mountpoint, "") == 0) {
2935 (void) snprintf(mountpoint, sizeof (mountpoint), "/");
2939 * Figure out what to set as the mountpoint for the new dataset.
2940 * If the source of the mountpoint property is local, use the
2941 * mountpoint value itself. Otherwise, remove it from the
2942 * zfs properties list so that it gets inherited.
2944 if (sourcetype & ZPROP_SRC_LOCAL) {
2946 * If the BE that this file system is a part of is
2947 * currently mounted, strip off the BE altroot portion
2948 * from the mountpoint.
2950 zhp_mountpoint = mountpoint;
2952 if (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 &&
2953 bt->obe_altroot != NULL && strcmp(bt->obe_altroot,
2954 "/") != 0 && zfs_is_mounted(zhp, NULL)) {
2956 int altroot_len = strlen(bt->obe_altroot);
2958 if (strncmp(bt->obe_altroot, mountpoint, altroot_len)
2959 == 0) {
2960 if (mountpoint[altroot_len] == '/')
2961 zhp_mountpoint = mountpoint +
2962 altroot_len;
2963 else if (mountpoint[altroot_len] == '\0')
2964 (void) snprintf(mountpoint,
2965 sizeof (mountpoint), "/");
2969 if (nvlist_add_string(bt->nbe_zfs_props,
2970 zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
2971 zhp_mountpoint) != 0) {
2972 be_print_err(gettext("be_prep_clone_send_fs: "
2973 "internal error: out of memory\n"));
2974 return (BE_ERR_NOMEM);
2976 } else {
2977 err = nvlist_remove_all(bt->nbe_zfs_props,
2978 zfs_prop_to_name(ZFS_PROP_MOUNTPOINT));
2979 if (err != 0 && err != ENOENT) {
2980 be_print_err(gettext("be_prep_clone_send_fs: "
2981 "failed to remove mountpoint from "
2982 "nvlist\n"));
2983 return (BE_ERR_INVAL);
2988 * Set the 'canmount' property
2990 if (nvlist_add_string(bt->nbe_zfs_props,
2991 zfs_prop_to_name(ZFS_PROP_CANMOUNT), "noauto") != 0) {
2992 be_print_err(gettext("be_prep_clone_send_fs: "
2993 "internal error: out of memory\n"));
2994 return (BE_ERR_NOMEM);
2997 return (BE_SUCCESS);
3001 * Function: be_get_zone_be_name
3002 * Description: This function takes the zones root dataset, the container
3003 * dataset and returns the zones BE name based on the zone
3004 * root dataset.
3005 * Parameters:
3006 * root_ds - the zones root dataset.
3007 * container_ds - the container dataset for the zone.
3008 * Returns:
3009 * char * - the BE name of this zone based on the root dataset.
3011 static char *
3012 be_get_zone_be_name(char *root_ds, char *container_ds)
3014 return (root_ds + (strlen(container_ds) + 1));
3018 * Function: be_zone_root_exists_callback
3019 * Description: This callback function is used to determine if a
3020 * zone root container dataset has any children. It always
3021 * returns 1, signifying a hierarchical child of the zone
3022 * root container dataset has been traversed and therefore
3023 * it has children.
3024 * Parameters:
3025 * zhp - zfs_handle_t pointer to current dataset being processed.
3026 * data - not used.
3027 * Returns:
3028 * 1 - dataset exists
3029 * Scope:
3030 * Private
3032 static int
3033 /* LINTED */
3034 be_zone_root_exists_callback(zfs_handle_t *zhp, void *data)
3036 ZFS_CLOSE(zhp);
3037 return (1);