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