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