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