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