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