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