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