1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 /* 27 * System includes 28 */ 29 #include <assert.h> 30 #include <libintl.h> 31 #include <libnvpair.h> 32 #include <libzfs.h> 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include <sys/types.h> 37 #include <sys/stat.h> 38 #include <unistd.h> 39 40 #include <libbe.h> 41 #include <libbe_priv.h> 42 43 /* Private function prototypes */ 44 static int be_rollback_check_callback(zfs_handle_t *, void *); 45 static int be_rollback_callback(zfs_handle_t *, void *); 46 47 48 /* ******************************************************************** */ 49 /* Public Functions */ 50 /* ******************************************************************** */ 51 52 /* 53 * Function: be_create_snapshot 54 * Description: Creates a recursive snapshot of all the datasets within a BE. 55 * If the name of the BE to snapshot is not provided, it assumes 56 * we're snapshotting the currently running BE. If the snapshot 57 * name is not provided it creates an auto named snapshot, which 58 * will be returned to the caller upon success. 59 * Parameters: 60 * be_attrs - pointer to nvlist_t of attributes being passed in. 61 * The following attributes are used by this function: 62 * 63 * BE_ATTR_ORIG_BE_NAME *optional 64 * BE_ATTR_SNAP_NAME *optional 65 * BE_ATTR_POLICY *optional 66 * 67 * If the BE_ATTR_SNAP_NAME was not passed in, upon 68 * successful BE snapshot creation, the following 69 * attribute value will be returned to the caller by 70 * setting it in the be_attrs parameter passed in: 71 * 72 * BE_ATTR_SNAP_NAME 73 * 74 * Return: 75 * BE_SUCCESS - Success 76 * be_errno_t - Failure 77 * Scope: 78 * Public 79 */ 80 int 81 be_create_snapshot(nvlist_t *be_attrs) 82 { 83 char *be_name = NULL; 84 char *snap_name = NULL; 85 char *policy = NULL; 86 boolean_t autoname = B_FALSE; 87 int ret = BE_SUCCESS; 88 89 /* Initialize libzfs handle */ 90 if (!be_zfs_init()) 91 return (BE_ERR_INIT); 92 93 /* Get original BE name if one was provided */ 94 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK, 95 BE_ATTR_ORIG_BE_NAME, DATA_TYPE_STRING, &be_name, NULL) != 0) { 96 be_print_err(gettext("be_create_snapshot: failed to " 97 "lookup BE_ATTR_ORIG_BE_NAME attribute\n")); 98 be_zfs_fini(); 99 return (BE_ERR_INVAL); 100 } 101 102 /* Validate original BE name if one was provided */ 103 if (be_name != NULL && !be_valid_be_name(be_name)) { 104 be_print_err(gettext("be_create_snapshot: " 105 "invalid BE name %s\n"), be_name); 106 be_zfs_fini(); 107 return (BE_ERR_INVAL); 108 } 109 110 /* Get snapshot name to create if one was provided */ 111 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK, 112 BE_ATTR_SNAP_NAME, DATA_TYPE_STRING, &snap_name, NULL) != 0) { 113 be_print_err(gettext("be_create_snapshot: " 114 "failed to lookup BE_ATTR_SNAP_NAME attribute\n")); 115 be_zfs_fini(); 116 return (BE_ERR_INVAL); 117 } 118 119 /* Get BE policy to create this snapshot under */ 120 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK, 121 BE_ATTR_POLICY, DATA_TYPE_STRING, &policy, NULL) != 0) { 122 be_print_err(gettext("be_create_snapshot: " 123 "failed to lookup BE_ATTR_POLICY attribute\n")); 124 be_zfs_fini(); 125 return (BE_ERR_INVAL); 126 } 127 128 /* 129 * If no snap_name ws provided, we're going to create an 130 * auto named snapshot. Set flag so that we know to pass 131 * the auto named snapshot to the caller later. 132 */ 133 if (snap_name == NULL) 134 autoname = B_TRUE; 135 136 if ((ret = _be_create_snapshot(be_name, &snap_name, policy)) 137 == BE_SUCCESS) { 138 if (autoname == B_TRUE) { 139 /* 140 * Set auto named snapshot name in the 141 * nvlist passed in by the caller. 142 */ 143 if (nvlist_add_string(be_attrs, BE_ATTR_SNAP_NAME, 144 snap_name) != 0) { 145 be_print_err(gettext("be_create_snapshot: " 146 "failed to add auto snap name (%s) to " 147 "be_attrs\n"), snap_name); 148 ret = BE_ERR_NOMEM; 149 } 150 } 151 } 152 153 be_zfs_fini(); 154 155 return (ret); 156 } 157 158 /* 159 * Function: be_destroy_snapshot 160 * Description: Iterates through all the datasets of the BE and deletes 161 * the snapshots of each one with the specified name. If the 162 * BE name is not provided, it assumes we're operating on the 163 * currently running BE. The name of the snapshot name to 164 * destroy must be provided. 165 * Parameters: 166 * be_attrs - pointer to nvlist_t of attributes being passed in. 167 * The following attribute values are used by this 168 * function: 169 * 170 * BE_ATTR_ORIG_BE_NAME *optional 171 * BE_ATTR_SNAP_NAME *required 172 * Return: 173 * BE_SUCCESS - Success 174 * be_errno_t - Failure 175 * Scope: 176 * Public 177 */ 178 int 179 be_destroy_snapshot(nvlist_t *be_attrs) 180 { 181 char *be_name = NULL; 182 char *snap_name = NULL; 183 int ret = BE_SUCCESS; 184 185 /* Initialize libzfs handle */ 186 if (!be_zfs_init()) 187 return (BE_ERR_INIT); 188 189 /* Get original BE name if one was provided */ 190 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK, 191 BE_ATTR_ORIG_BE_NAME, DATA_TYPE_STRING, &be_name, NULL) != 0) { 192 be_print_err(gettext("be_destroy_snapshot: " 193 "failed to lookup BE_ATTR_ORIG_BE_NAME attribute\n")); 194 return (BE_ERR_INVAL); 195 } 196 197 /* Validate original BE name if one was provided */ 198 if (be_name != NULL && !be_valid_be_name(be_name)) { 199 be_print_err(gettext("be_destroy_snapshot: " 200 "invalid BE name %s\n"), be_name); 201 return (BE_ERR_INVAL); 202 } 203 204 /* Get snapshot name to destroy */ 205 if (nvlist_lookup_string(be_attrs, BE_ATTR_SNAP_NAME, &snap_name) 206 != 0) { 207 be_print_err(gettext("be_destroy_snapshot: " 208 "failed to lookup BE_ATTR_SNAP_NAME attribute.\n")); 209 return (BE_ERR_INVAL); 210 } 211 212 ret = _be_destroy_snapshot(be_name, snap_name); 213 214 be_zfs_fini(); 215 216 return (ret); 217 } 218 219 /* 220 * Function: be_rollback 221 * Description: Rolls back a BE and all of its children datasets to the 222 * named snapshot. All of the BE's datasets must have the 223 * named snapshot for this function to succeed. If the name 224 * of the BE is not passed in, this function assumes we're 225 * operating on the currently booted live BE. 226 * 227 * Note - This function does not check if the BE has any 228 * younger snapshots than the one we're trying to rollback to. 229 * If it does, then those younger snapshots and their dependent 230 * clone file systems will get destroyed in the process of 231 * rolling back. 232 * 233 * Parameters: 234 * be_attrs - pointer to nvlist_t of attributes being passed in. 235 * The following attributes are used by this function: 236 * 237 * BE_ATTR_ORIG_BE_NAME *optional 238 * BE_ATTR_SNAP_NAME *required 239 * 240 * Returns: 241 * BE_SUCCESS - Success 242 * be_errno_t - Failure 243 * Scope: 244 * Public 245 */ 246 int 247 be_rollback(nvlist_t *be_attrs) 248 { 249 be_transaction_data_t bt = { 0 }; 250 zfs_handle_t *zhp = NULL; 251 char obe_root_ds[MAXPATHLEN]; 252 int zret = 0, ret = BE_SUCCESS; 253 254 /* Initialize libzfs handle */ 255 if (!be_zfs_init()) 256 return (BE_ERR_INIT); 257 258 /* Get original BE name if one was provided */ 259 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK, 260 BE_ATTR_ORIG_BE_NAME, DATA_TYPE_STRING, &bt.obe_name, NULL) != 0) { 261 be_print_err(gettext("be_rollback: " 262 "failed to lookup BE_ATTR_ORIG_BE_NAME attribute\n")); 263 return (BE_ERR_INVAL); 264 } 265 266 /* If original BE name not provided, use current BE */ 267 if (bt.obe_name == NULL) { 268 if ((ret = be_find_current_be(&bt)) != BE_SUCCESS) { 269 return (ret); 270 } 271 } else { 272 /* Validate original BE name */ 273 if (!be_valid_be_name(bt.obe_name)) { 274 be_print_err(gettext("be_rollback: " 275 "invalid BE name %s\n"), bt.obe_name); 276 return (BE_ERR_INVAL); 277 } 278 } 279 280 /* Get snapshot name to rollback to */ 281 if (nvlist_lookup_string(be_attrs, BE_ATTR_SNAP_NAME, &bt.obe_snap_name) 282 != 0) { 283 be_print_err(gettext("be_rollback: " 284 "failed to lookup BE_ATTR_SNAP_NAME attribute.\n")); 285 return (BE_ERR_INVAL); 286 } 287 288 /* Find which zpool obe_name lives in */ 289 if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) == 0) { 290 be_print_err(gettext("be_rollback: " 291 "failed to find zpool for BE (%s)\n"), bt.obe_name); 292 return (BE_ERR_BE_NOENT); 293 } else if (zret < 0) { 294 be_print_err(gettext("be_rollback: " 295 "zpool_iter failed: %s\n"), 296 libzfs_error_description(g_zfs)); 297 return (zfs_err_to_be_err(g_zfs)); 298 } 299 300 /* Generate string for BE's root dataset */ 301 be_make_root_ds(bt.obe_zpool, bt.obe_name, obe_root_ds, 302 sizeof (obe_root_ds)); 303 bt.obe_root_ds = obe_root_ds; 304 305 /* Get handle to BE's root dataset */ 306 if ((zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_DATASET)) == NULL) { 307 be_print_err(gettext("be_rollback: " 308 "failed to open BE root dataset (%s): %s\n"), 309 bt.obe_root_ds, libzfs_error_description(g_zfs)); 310 return (zfs_err_to_be_err(g_zfs)); 311 } 312 313 /* 314 * Check that snapshot name exists for this BE and all of its 315 * children file systems. This call will end up closing the 316 * zfs handle passed in whether it succeeds or fails. 317 */ 318 if ((ret = be_rollback_check_callback(zhp, bt.obe_snap_name)) != 0) { 319 zhp = NULL; 320 return (ret); 321 } 322 323 /* Get handle to BE's root dataset */ 324 if ((zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_DATASET)) == NULL) { 325 be_print_err(gettext("be_rollback: " 326 "failed to open BE root dataset (%s): %s\n"), 327 bt.obe_root_ds, libzfs_error_description(g_zfs)); 328 return (zfs_err_to_be_err(g_zfs)); 329 } 330 331 /* 332 * Iterate through a BE's datasets and roll them all back to 333 * the specified snapshot. This call will end up closing the 334 * zfs handle passed in whether it succeeds or fails. 335 */ 336 if ((ret = be_rollback_callback(zhp, bt.obe_snap_name)) != 0) { 337 zhp = NULL; 338 be_print_err(gettext("be_rollback: " 339 "failed to rollback BE %s to %s\n"), bt.obe_name, 340 bt.obe_snap_name); 341 return (ret); 342 } 343 zhp = NULL; 344 be_zfs_fini(); 345 return (BE_SUCCESS); 346 } 347 348 349 /* ******************************************************************** */ 350 /* Semi-Private Functions */ 351 /* ******************************************************************** */ 352 353 /* 354 * Function: _be_create_snapshot 355 * Description: see be_create_snapshot 356 * Parameters: 357 * be_name - The name of the BE that we're taking a snapshot of. 358 * snap_name - The name of the snapshot we're creating. If 359 * snap_name is NULL an auto generated name will be used, 360 * and upon success, will return that name via this 361 * reference pointer. The caller is responsible for 362 * freeing the returned name. 363 * policy - The clean-up policy type. (library wide use only) 364 * Return: 365 * BE_SUCCESS - Success 366 * be_errno_t - Failure 367 * Scope: 368 * Semi-private (library wide use only) 369 */ 370 int 371 _be_create_snapshot(char *be_name, char **snap_name, char *policy) 372 { 373 be_transaction_data_t bt = { 0 }; 374 zfs_handle_t *zhp = NULL; 375 nvlist_t *ss_props = NULL; 376 char ss[MAXPATHLEN]; 377 char root_ds[MAXPATHLEN]; 378 int pool_version = 0; 379 int i = 0; 380 int zret = 0, ret = BE_SUCCESS; 381 boolean_t autoname = B_FALSE; 382 383 /* Set parameters in bt structure */ 384 bt.obe_name = be_name; 385 bt.obe_snap_name = *snap_name; 386 bt.policy = policy; 387 388 /* If original BE name not supplied, use current BE */ 389 if (bt.obe_name == NULL) { 390 if ((ret = be_find_current_be(&bt)) != BE_SUCCESS) { 391 return (ret); 392 } 393 } 394 395 /* Find which zpool obe_name lives in */ 396 if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) == 0) { 397 be_print_err(gettext("be_create_snapshot: failed to " 398 "find zpool for BE (%s)\n"), bt.obe_name); 399 return (BE_ERR_BE_NOENT); 400 } else if (zret < 0) { 401 be_print_err(gettext("be_create_snapshot: " 402 "zpool_iter failed: %s\n"), 403 libzfs_error_description(g_zfs)); 404 return (zfs_err_to_be_err(g_zfs)); 405 } 406 407 be_make_root_ds(bt.obe_zpool, bt.obe_name, root_ds, 408 sizeof (root_ds)); 409 bt.obe_root_ds = root_ds; 410 411 /* If BE policy not specified, use the default policy */ 412 if (bt.policy == NULL) { 413 bt.policy = be_default_policy(); 414 } else { 415 /* Validate policy type */ 416 if (!valid_be_policy(bt.policy)) { 417 be_print_err(gettext("be_create_snapshot: " 418 "invalid BE policy type (%s)\n"), bt.policy); 419 return (BE_ERR_INVAL); 420 } 421 } 422 423 /* 424 * If snapshot name not specified, set auto name flag and 425 * generate auto snapshot name. 426 */ 427 if (bt.obe_snap_name == NULL) { 428 autoname = B_TRUE; 429 if ((bt.obe_snap_name = be_auto_snap_name()) 430 == NULL) { 431 be_print_err(gettext("be_create_snapshot: " 432 "failed to create auto snapshot name\n")); 433 ret = BE_ERR_AUTONAME; 434 goto done; 435 } 436 } 437 438 /* Generate the name of the snapshot to take. */ 439 (void) snprintf(ss, sizeof (ss), "%s@%s", bt.obe_root_ds, 440 bt.obe_snap_name); 441 442 /* Get handle to BE's root dataset */ 443 if ((zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_DATASET)) 444 == NULL) { 445 be_print_err(gettext("be_create_snapshot: " 446 "failed to open BE root dataset (%s): %s\n"), 447 bt.obe_root_ds, libzfs_error_description(g_zfs)); 448 ret = zfs_err_to_be_err(g_zfs); 449 goto done; 450 } 451 452 /* Get the ZFS pool version of the pool where this dataset resides */ 453 if (zfs_spa_version(zhp, &pool_version) != 0) { 454 be_print_err(gettext("be_create_snapshot: failed to " 455 "get ZFS pool version for %s: %s\n"), zfs_get_name(zhp), 456 libzfs_error_description(g_zfs)); 457 } 458 459 /* 460 * If ZFS pool version supports snapshot user properties, store 461 * cleanup policy there. Otherwise don't set one - this snapshot 462 * will always inherit the cleanup policy from its parent. 463 */ 464 if (pool_version >= SPA_VERSION_SNAP_PROPS) { 465 if (nvlist_alloc(&ss_props, NV_UNIQUE_NAME, 0) != 0) { 466 be_print_err(gettext("be_create_snapshot: internal " 467 "error: out of memory\n")); 468 return (BE_ERR_NOMEM); 469 } 470 if (nvlist_add_string(ss_props, BE_POLICY_PROPERTY, bt.policy) 471 != 0) { 472 be_print_err(gettext("be_create_snapshot: internal " 473 "error: out of memory\n")); 474 nvlist_free(ss_props); 475 return (BE_ERR_NOMEM); 476 } 477 } else if (policy != NULL) { 478 /* 479 * If an explicit cleanup policy was requested 480 * by the caller and we don't support it, error out. 481 */ 482 be_print_err(gettext("be_create_snapshot: cannot set " 483 "cleanup policy: ZFS pool version is %d\n"), pool_version); 484 return (BE_ERR_NOTSUP); 485 } 486 487 /* Create the snapshots recursively */ 488 if (zfs_snapshot(g_zfs, ss, B_TRUE, ss_props) != 0) { 489 if (!autoname || libzfs_errno(g_zfs) != EZFS_EXISTS) { 490 be_print_err(gettext("be_create_snapshot: " 491 "recursive snapshot of %s failed: %s\n"), 492 ss, libzfs_error_description(g_zfs)); 493 494 if (libzfs_errno(g_zfs) == EZFS_EXISTS) 495 ret = BE_ERR_SS_EXISTS; 496 else 497 ret = zfs_err_to_be_err(g_zfs); 498 499 goto done; 500 } else { 501 for (i = 1; i < BE_AUTO_NAME_MAX_TRY; i++) { 502 503 /* Sleep 1 before retrying */ 504 (void) sleep(1); 505 506 /* Generate new auto snapshot name. */ 507 free(bt.obe_snap_name); 508 if ((bt.obe_snap_name = 509 be_auto_snap_name()) == NULL) { 510 be_print_err(gettext( 511 "be_create_snapshot: failed to " 512 "create auto snapshot name\n")); 513 ret = BE_ERR_AUTONAME; 514 goto done; 515 } 516 517 /* Generate string of the snapshot to take. */ 518 (void) snprintf(ss, sizeof (ss), "%s@%s", 519 bt.obe_root_ds, bt.obe_snap_name); 520 521 /* Create the snapshots recursively */ 522 if (zfs_snapshot(g_zfs, ss, B_TRUE, ss_props) 523 != 0) { 524 if (libzfs_errno(g_zfs) != 525 EZFS_EXISTS) { 526 be_print_err(gettext( 527 "be_create_snapshot: " 528 "recursive snapshot of %s " 529 "failed: %s\n"), ss, 530 libzfs_error_description( 531 g_zfs)); 532 ret = zfs_err_to_be_err(g_zfs); 533 goto done; 534 } 535 } else { 536 break; 537 } 538 } 539 540 /* 541 * If we exhausted the maximum number of tries, 542 * free the auto snap name and set error. 543 */ 544 if (i == BE_AUTO_NAME_MAX_TRY) { 545 be_print_err(gettext("be_create_snapshot: " 546 "failed to create unique auto snapshot " 547 "name\n")); 548 free(bt.obe_snap_name); 549 bt.obe_snap_name = NULL; 550 ret = BE_ERR_AUTONAME; 551 } 552 } 553 } 554 555 /* 556 * If we succeeded in creating an auto named snapshot, store 557 * the name in the nvlist passed in by the caller. 558 */ 559 if (autoname && bt.obe_snap_name) { 560 *snap_name = bt.obe_snap_name; 561 } 562 563 done: 564 ZFS_CLOSE(zhp); 565 566 if (ss_props != NULL) 567 nvlist_free(ss_props); 568 569 return (ret); 570 } 571 572 /* 573 * Function: _be_destroy_snapshot 574 * Description: see be_destroy_snapshot 575 * Parameters: 576 * be_name - The name of the BE that the snapshot belongs to. 577 * snap_name - The name of the snapshot we're destroying. 578 * Return: 579 * BE_SUCCESS - Success 580 * be_errno_t - Failure 581 * Scope: 582 * Semi-private (library wide use only) 583 */ 584 int 585 _be_destroy_snapshot(char *be_name, char *snap_name) 586 { 587 be_transaction_data_t bt = { 0 }; 588 zfs_handle_t *zhp; 589 char ss[MAXPATHLEN]; 590 char root_ds[MAXPATHLEN]; 591 int err = BE_SUCCESS, ret = BE_SUCCESS; 592 593 /* Make sure we actaully have a snapshot name */ 594 if (snap_name == NULL) { 595 be_print_err(gettext("be_destroy_snapshot: " 596 "invalid snapshot name\n")); 597 return (BE_ERR_INVAL); 598 } 599 600 /* Set parameters in bt structure */ 601 bt.obe_name = be_name; 602 bt.obe_snap_name = snap_name; 603 604 /* If original BE name not supplied, use current BE */ 605 if (bt.obe_name == NULL) { 606 if ((err = be_find_current_be(&bt)) != BE_SUCCESS) { 607 return (err); 608 } 609 } 610 611 /* Find which zpool be_name lives in */ 612 if ((ret = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) == 0) { 613 be_print_err(gettext("be_destroy_snapshot: " 614 "failed to find zpool for BE (%s)\n"), bt.obe_name); 615 return (BE_ERR_BE_NOENT); 616 } else if (ret < 0) { 617 be_print_err(gettext("be_destroy_snapshot: " 618 "zpool_iter failed: %s\n"), 619 libzfs_error_description(g_zfs)); 620 return (zfs_err_to_be_err(g_zfs)); 621 } 622 623 be_make_root_ds(bt.obe_zpool, bt.obe_name, root_ds, 624 sizeof (root_ds)); 625 bt.obe_root_ds = root_ds; 626 627 zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_DATASET); 628 if (zhp == NULL) { 629 /* 630 * The zfs_open failed, return an error. 631 */ 632 be_print_err(gettext("be_destroy_snapshot: " 633 "failed to open BE root dataset (%s): %s\n"), 634 bt.obe_root_ds, libzfs_error_description(g_zfs)); 635 err = zfs_err_to_be_err(g_zfs); 636 } else { 637 /* 638 * Generate the name of the snapshot to take. 639 */ 640 (void) snprintf(ss, sizeof (ss), "%s@%s", bt.obe_name, 641 bt.obe_snap_name); 642 643 /* 644 * destroy the snapshot. 645 */ 646 /* 647 * The boolean set to B_FALSE and passed to zfs_destroy_snaps() 648 * tells zfs to process and destroy the snapshots now. 649 * Otherwise the call will potentially return where the 650 * snapshot isn't actually destroyed yet, and ZFS is waiting 651 * until all the references to the snapshot have been 652 * released before actually destroying the snapshot. 653 */ 654 if (zfs_destroy_snaps(zhp, bt.obe_snap_name, B_FALSE) != 0) { 655 err = zfs_err_to_be_err(g_zfs); 656 be_print_err(gettext("be_destroy_snapshot: " 657 "failed to destroy snapshot %s: %s\n"), ss, 658 libzfs_error_description(g_zfs)); 659 } 660 } 661 662 ZFS_CLOSE(zhp); 663 664 return (err); 665 } 666 667 /* ******************************************************************** */ 668 /* Private Functions */ 669 /* ******************************************************************** */ 670 671 /* 672 * Function: be_rollback_check_callback 673 * Description: Callback function used to iterate through a BE's filesystems 674 * to check if a given snapshot name exists. 675 * Parameters: 676 * zhp - zfs_handle_t pointer to filesystem being processed. 677 * data - name of the snapshot to check for. 678 * Returns: 679 * 0 - Success, snapshot name exists for all filesystems. 680 * be_errno_t - Failure, snapshot name does not exist for all 681 * filesystems. 682 * Scope: 683 * Private 684 */ 685 static int 686 be_rollback_check_callback(zfs_handle_t *zhp, void *data) 687 { 688 char *snap_name = data; 689 char ss[MAXPATHLEN]; 690 int ret = BE_SUCCESS; 691 692 /* Generate string for this filesystem's snapshot name */ 693 (void) snprintf(ss, sizeof (ss), "%s@%s", zfs_get_name(zhp), snap_name); 694 695 /* Check if snapshot exists */ 696 if (!zfs_dataset_exists(g_zfs, ss, ZFS_TYPE_SNAPSHOT)) { 697 be_print_err(gettext("be_rollback_check_callback: " 698 "snapshot does not exist %s\n"), ss); 699 ZFS_CLOSE(zhp); 700 return (BE_ERR_SS_NOENT); 701 } 702 703 /* Iterate this dataset's children and check them */ 704 if ((ret = zfs_iter_filesystems(zhp, be_rollback_check_callback, 705 snap_name)) != 0) { 706 ZFS_CLOSE(zhp); 707 return (ret); 708 } 709 710 ZFS_CLOSE(zhp); 711 return (0); 712 } 713 714 /* 715 * Function: be_rollback_callback 716 * Description: Callback function used to iterate through a BE's filesystems 717 * and roll them all back to the specified snapshot name. 718 * Parameters: 719 * zhp - zfs_handle_t pointer to filesystem being processed. 720 * data - name of snapshot to rollback to. 721 * Returns: 722 * 0 - Success 723 * be_errno_t - Failure 724 * Scope: 725 * Private 726 */ 727 static int 728 be_rollback_callback(zfs_handle_t *zhp, void *data) 729 { 730 zfs_handle_t *zhp_snap = NULL; 731 char *snap_name = data; 732 char ss[MAXPATHLEN]; 733 int ret = 0; 734 735 /* Generate string for this filesystem's snapshot name */ 736 (void) snprintf(ss, sizeof (ss), "%s@%s", zfs_get_name(zhp), snap_name); 737 738 /* Get handle to this filesystem's snapshot */ 739 if ((zhp_snap = zfs_open(g_zfs, ss, ZFS_TYPE_SNAPSHOT)) == NULL) { 740 be_print_err(gettext("be_rollback_callback: " 741 "failed to open snapshot %s: %s\n"), zfs_get_name(zhp), 742 libzfs_error_description(g_zfs)); 743 ret = zfs_err_to_be_err(g_zfs); 744 ZFS_CLOSE(zhp); 745 return (ret); 746 } 747 748 /* Rollback dataset */ 749 if (zfs_rollback(zhp, zhp_snap, B_FALSE) != 0) { 750 be_print_err(gettext("be_rollback_callback: " 751 "failed to rollback BE dataset %s to snapshot %s: %s\n"), 752 zfs_get_name(zhp), ss, libzfs_error_description(g_zfs)); 753 ret = zfs_err_to_be_err(g_zfs); 754 ZFS_CLOSE(zhp_snap); 755 ZFS_CLOSE(zhp); 756 return (ret); 757 } 758 759 ZFS_CLOSE(zhp_snap); 760 /* Iterate this dataset's children and roll them back */ 761 if ((ret = zfs_iter_filesystems(zhp, be_rollback_callback, 762 snap_name)) != 0) { 763 ZFS_CLOSE(zhp); 764 return (ret); 765 } 766 767 ZFS_CLOSE(zhp); 768 return (0); 769 } 770