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