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 26*de1ab35cSAlexander Eremin /* 27*de1ab35cSAlexander Eremin * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 28*de1ab35cSAlexander Eremin */ 29*de1ab35cSAlexander Eremin 30f169c0eaSGlenn Lagasse /* 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; 255*de1ab35cSAlexander Eremin zpool_handle_t *zphp; 256f169c0eaSGlenn Lagasse char obe_root_ds[MAXPATHLEN]; 257*de1ab35cSAlexander Eremin char *obe_name = NULL; 258f169c0eaSGlenn Lagasse int zret = 0, ret = BE_SUCCESS; 259*de1ab35cSAlexander 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 265*de1ab35cSAlexander Eremin if ((ret = be_find_current_be(&bt)) != BE_SUCCESS) { 266*de1ab35cSAlexander Eremin return (ret); 267*de1ab35cSAlexander Eremin } 268*de1ab35cSAlexander Eremin 269f169c0eaSGlenn Lagasse /* Get original BE name if one was provided */ 270f169c0eaSGlenn Lagasse if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK, 271*de1ab35cSAlexander 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 277*de1ab35cSAlexander Eremin be_get_defaults(&be_defaults); 278*de1ab35cSAlexander Eremin 279f169c0eaSGlenn Lagasse /* If original BE name not provided, use current BE */ 280*de1ab35cSAlexander Eremin if (obe_name != NULL) { 281*de1ab35cSAlexander 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 298*de1ab35cSAlexander Eremin if (be_defaults.be_deflt_rpool_container) { 299*de1ab35cSAlexander Eremin if ((zphp = zpool_open(g_zfs, bt.obe_zpool)) == NULL) { 300*de1ab35cSAlexander Eremin be_print_err(gettext("be_rollback: failed to " 301*de1ab35cSAlexander Eremin "open rpool (%s): %s\n"), bt.obe_zpool, 302*de1ab35cSAlexander Eremin libzfs_error_description(g_zfs)); 303*de1ab35cSAlexander Eremin return (zfs_err_to_be_err(g_zfs)); 304*de1ab35cSAlexander Eremin } 305*de1ab35cSAlexander Eremin zret = be_find_zpool_callback(zphp, &bt); 306*de1ab35cSAlexander Eremin } else { 307*de1ab35cSAlexander Eremin /* Find which zpool obe_name lives in */ 308*de1ab35cSAlexander Eremin if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) == 309*de1ab35cSAlexander Eremin 0) { 310*de1ab35cSAlexander Eremin be_print_err(gettext("be_rollback: " 311*de1ab35cSAlexander Eremin "failed to find zpool for BE (%s)\n"), bt.obe_name); 312*de1ab35cSAlexander Eremin return (BE_ERR_BE_NOENT); 313*de1ab35cSAlexander Eremin } else if (zret < 0) { 314*de1ab35cSAlexander Eremin be_print_err(gettext("be_rollback: " 315*de1ab35cSAlexander Eremin "zpool_iter failed: %s\n"), 316*de1ab35cSAlexander Eremin libzfs_error_description(g_zfs)); 317*de1ab35cSAlexander Eremin return (zfs_err_to_be_err(g_zfs)); 318*de1ab35cSAlexander Eremin } 319f169c0eaSGlenn Lagasse } 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 326f169c0eaSGlenn Lagasse /* Get handle to BE's root dataset */ 327f169c0eaSGlenn Lagasse if ((zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_DATASET)) == NULL) { 328f169c0eaSGlenn Lagasse be_print_err(gettext("be_rollback: " 329f169c0eaSGlenn Lagasse "failed to open BE root dataset (%s): %s\n"), 330f169c0eaSGlenn Lagasse bt.obe_root_ds, libzfs_error_description(g_zfs)); 331f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs)); 332f169c0eaSGlenn Lagasse } 333f169c0eaSGlenn Lagasse 334f169c0eaSGlenn Lagasse /* 335f169c0eaSGlenn Lagasse * Check that snapshot name exists for this BE and all of its 336f169c0eaSGlenn Lagasse * children file systems. This call will end up closing the 337f169c0eaSGlenn Lagasse * zfs handle passed in whether it succeeds or fails. 338f169c0eaSGlenn Lagasse */ 339f169c0eaSGlenn Lagasse if ((ret = be_rollback_check_callback(zhp, bt.obe_snap_name)) != 0) { 340f169c0eaSGlenn Lagasse zhp = NULL; 341f169c0eaSGlenn Lagasse return (ret); 342f169c0eaSGlenn Lagasse } 343f169c0eaSGlenn Lagasse 344f169c0eaSGlenn Lagasse /* Get handle to BE's root dataset */ 345f169c0eaSGlenn Lagasse if ((zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_DATASET)) == NULL) { 346f169c0eaSGlenn Lagasse be_print_err(gettext("be_rollback: " 347f169c0eaSGlenn Lagasse "failed to open BE root dataset (%s): %s\n"), 348f169c0eaSGlenn Lagasse bt.obe_root_ds, libzfs_error_description(g_zfs)); 349f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs)); 350f169c0eaSGlenn Lagasse } 351f169c0eaSGlenn Lagasse 352f169c0eaSGlenn Lagasse /* 353f169c0eaSGlenn Lagasse * Iterate through a BE's datasets and roll them all back to 354f169c0eaSGlenn Lagasse * the specified snapshot. This call will end up closing the 355f169c0eaSGlenn Lagasse * zfs handle passed in whether it succeeds or fails. 356f169c0eaSGlenn Lagasse */ 357f169c0eaSGlenn Lagasse if ((ret = be_rollback_callback(zhp, bt.obe_snap_name)) != 0) { 358f169c0eaSGlenn Lagasse zhp = NULL; 359f169c0eaSGlenn Lagasse be_print_err(gettext("be_rollback: " 360f169c0eaSGlenn Lagasse "failed to rollback BE %s to %s\n"), bt.obe_name, 361f169c0eaSGlenn Lagasse bt.obe_snap_name); 362f169c0eaSGlenn Lagasse return (ret); 363f169c0eaSGlenn Lagasse } 364f169c0eaSGlenn Lagasse zhp = NULL; 365f169c0eaSGlenn Lagasse be_zfs_fini(); 366f169c0eaSGlenn Lagasse return (BE_SUCCESS); 367f169c0eaSGlenn Lagasse } 368f169c0eaSGlenn Lagasse 369f169c0eaSGlenn Lagasse 370f169c0eaSGlenn Lagasse /* ******************************************************************** */ 371f169c0eaSGlenn Lagasse /* Semi-Private Functions */ 372f169c0eaSGlenn Lagasse /* ******************************************************************** */ 373f169c0eaSGlenn Lagasse 374f169c0eaSGlenn Lagasse /* 375f169c0eaSGlenn Lagasse * Function: _be_create_snapshot 376f169c0eaSGlenn Lagasse * Description: see be_create_snapshot 377f169c0eaSGlenn Lagasse * Parameters: 378f169c0eaSGlenn Lagasse * be_name - The name of the BE that we're taking a snapshot of. 379f169c0eaSGlenn Lagasse * snap_name - The name of the snapshot we're creating. If 380f169c0eaSGlenn Lagasse * snap_name is NULL an auto generated name will be used, 381f169c0eaSGlenn Lagasse * and upon success, will return that name via this 382f169c0eaSGlenn Lagasse * reference pointer. The caller is responsible for 383f169c0eaSGlenn Lagasse * freeing the returned name. 384f169c0eaSGlenn Lagasse * policy - The clean-up policy type. (library wide use only) 385f169c0eaSGlenn Lagasse * Return: 386f169c0eaSGlenn Lagasse * BE_SUCCESS - Success 387f169c0eaSGlenn Lagasse * be_errno_t - Failure 388f169c0eaSGlenn Lagasse * Scope: 389f169c0eaSGlenn Lagasse * Semi-private (library wide use only) 390f169c0eaSGlenn Lagasse */ 391f169c0eaSGlenn Lagasse int 392f169c0eaSGlenn Lagasse _be_create_snapshot(char *be_name, char **snap_name, char *policy) 393f169c0eaSGlenn Lagasse { 394f169c0eaSGlenn Lagasse be_transaction_data_t bt = { 0 }; 395f169c0eaSGlenn Lagasse zfs_handle_t *zhp = NULL; 396f169c0eaSGlenn Lagasse nvlist_t *ss_props = NULL; 397f169c0eaSGlenn Lagasse char ss[MAXPATHLEN]; 398f169c0eaSGlenn Lagasse char root_ds[MAXPATHLEN]; 399f169c0eaSGlenn Lagasse int pool_version = 0; 400f169c0eaSGlenn Lagasse int i = 0; 401f169c0eaSGlenn Lagasse int zret = 0, ret = BE_SUCCESS; 402f169c0eaSGlenn Lagasse boolean_t autoname = B_FALSE; 403f169c0eaSGlenn Lagasse 404f169c0eaSGlenn Lagasse /* Set parameters in bt structure */ 405f169c0eaSGlenn Lagasse bt.obe_name = be_name; 406f169c0eaSGlenn Lagasse bt.obe_snap_name = *snap_name; 407f169c0eaSGlenn Lagasse bt.policy = policy; 408f169c0eaSGlenn Lagasse 409f169c0eaSGlenn Lagasse /* If original BE name not supplied, use current BE */ 410f169c0eaSGlenn Lagasse if (bt.obe_name == NULL) { 411f169c0eaSGlenn Lagasse if ((ret = be_find_current_be(&bt)) != BE_SUCCESS) { 412f169c0eaSGlenn Lagasse return (ret); 413f169c0eaSGlenn Lagasse } 414f169c0eaSGlenn Lagasse } 415f169c0eaSGlenn Lagasse 416f169c0eaSGlenn Lagasse /* Find which zpool obe_name lives in */ 417f169c0eaSGlenn Lagasse if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) == 0) { 418f169c0eaSGlenn Lagasse be_print_err(gettext("be_create_snapshot: failed to " 419f169c0eaSGlenn Lagasse "find zpool for BE (%s)\n"), bt.obe_name); 420f169c0eaSGlenn Lagasse return (BE_ERR_BE_NOENT); 421f169c0eaSGlenn Lagasse } else if (zret < 0) { 422f169c0eaSGlenn Lagasse be_print_err(gettext("be_create_snapshot: " 423f169c0eaSGlenn Lagasse "zpool_iter failed: %s\n"), 424f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 425f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs)); 426f169c0eaSGlenn Lagasse } 427f169c0eaSGlenn Lagasse 428f169c0eaSGlenn Lagasse be_make_root_ds(bt.obe_zpool, bt.obe_name, root_ds, 429f169c0eaSGlenn Lagasse sizeof (root_ds)); 430f169c0eaSGlenn Lagasse bt.obe_root_ds = root_ds; 431f169c0eaSGlenn Lagasse 432f169c0eaSGlenn Lagasse /* If BE policy not specified, use the default policy */ 433f169c0eaSGlenn Lagasse if (bt.policy == NULL) { 434f169c0eaSGlenn Lagasse bt.policy = be_default_policy(); 435f169c0eaSGlenn Lagasse } else { 436f169c0eaSGlenn Lagasse /* Validate policy type */ 437f169c0eaSGlenn Lagasse if (!valid_be_policy(bt.policy)) { 438f169c0eaSGlenn Lagasse be_print_err(gettext("be_create_snapshot: " 439f169c0eaSGlenn Lagasse "invalid BE policy type (%s)\n"), bt.policy); 440f169c0eaSGlenn Lagasse return (BE_ERR_INVAL); 441f169c0eaSGlenn Lagasse } 442f169c0eaSGlenn Lagasse } 443f169c0eaSGlenn Lagasse 444f169c0eaSGlenn Lagasse /* 445f169c0eaSGlenn Lagasse * If snapshot name not specified, set auto name flag and 446f169c0eaSGlenn Lagasse * generate auto snapshot name. 447f169c0eaSGlenn Lagasse */ 448f169c0eaSGlenn Lagasse if (bt.obe_snap_name == NULL) { 449f169c0eaSGlenn Lagasse autoname = B_TRUE; 450f169c0eaSGlenn Lagasse if ((bt.obe_snap_name = be_auto_snap_name()) 451f169c0eaSGlenn Lagasse == NULL) { 452f169c0eaSGlenn Lagasse be_print_err(gettext("be_create_snapshot: " 453f169c0eaSGlenn Lagasse "failed to create auto snapshot name\n")); 454f169c0eaSGlenn Lagasse ret = BE_ERR_AUTONAME; 455f169c0eaSGlenn Lagasse goto done; 456f169c0eaSGlenn Lagasse } 457f169c0eaSGlenn Lagasse } 458f169c0eaSGlenn Lagasse 459f169c0eaSGlenn Lagasse /* Generate the name of the snapshot to take. */ 460f169c0eaSGlenn Lagasse (void) snprintf(ss, sizeof (ss), "%s@%s", bt.obe_root_ds, 461f169c0eaSGlenn Lagasse bt.obe_snap_name); 462f169c0eaSGlenn Lagasse 463f169c0eaSGlenn Lagasse /* Get handle to BE's root dataset */ 464f169c0eaSGlenn Lagasse if ((zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_DATASET)) 465f169c0eaSGlenn Lagasse == NULL) { 466f169c0eaSGlenn Lagasse be_print_err(gettext("be_create_snapshot: " 467f169c0eaSGlenn Lagasse "failed to open BE root dataset (%s): %s\n"), 468f169c0eaSGlenn Lagasse bt.obe_root_ds, libzfs_error_description(g_zfs)); 469f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 470f169c0eaSGlenn Lagasse goto done; 471f169c0eaSGlenn Lagasse } 472f169c0eaSGlenn Lagasse 473f169c0eaSGlenn Lagasse /* Get the ZFS pool version of the pool where this dataset resides */ 474f169c0eaSGlenn Lagasse if (zfs_spa_version(zhp, &pool_version) != 0) { 475f169c0eaSGlenn Lagasse be_print_err(gettext("be_create_snapshot: failed to " 476f169c0eaSGlenn Lagasse "get ZFS pool version for %s: %s\n"), zfs_get_name(zhp), 477f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 478f169c0eaSGlenn Lagasse } 479f169c0eaSGlenn Lagasse 480f169c0eaSGlenn Lagasse /* 481f169c0eaSGlenn Lagasse * If ZFS pool version supports snapshot user properties, store 482f169c0eaSGlenn Lagasse * cleanup policy there. Otherwise don't set one - this snapshot 483f169c0eaSGlenn Lagasse * will always inherit the cleanup policy from its parent. 484f169c0eaSGlenn Lagasse */ 485f169c0eaSGlenn Lagasse if (pool_version >= SPA_VERSION_SNAP_PROPS) { 486f169c0eaSGlenn Lagasse if (nvlist_alloc(&ss_props, NV_UNIQUE_NAME, 0) != 0) { 487f169c0eaSGlenn Lagasse be_print_err(gettext("be_create_snapshot: internal " 488f169c0eaSGlenn Lagasse "error: out of memory\n")); 489f169c0eaSGlenn Lagasse return (BE_ERR_NOMEM); 490f169c0eaSGlenn Lagasse } 491f169c0eaSGlenn Lagasse if (nvlist_add_string(ss_props, BE_POLICY_PROPERTY, bt.policy) 492f169c0eaSGlenn Lagasse != 0) { 493f169c0eaSGlenn Lagasse be_print_err(gettext("be_create_snapshot: internal " 494f169c0eaSGlenn Lagasse "error: out of memory\n")); 495f169c0eaSGlenn Lagasse nvlist_free(ss_props); 496f169c0eaSGlenn Lagasse return (BE_ERR_NOMEM); 497f169c0eaSGlenn Lagasse } 498f169c0eaSGlenn Lagasse } else if (policy != NULL) { 499f169c0eaSGlenn Lagasse /* 500f169c0eaSGlenn Lagasse * If an explicit cleanup policy was requested 501f169c0eaSGlenn Lagasse * by the caller and we don't support it, error out. 502f169c0eaSGlenn Lagasse */ 503f169c0eaSGlenn Lagasse be_print_err(gettext("be_create_snapshot: cannot set " 504f169c0eaSGlenn Lagasse "cleanup policy: ZFS pool version is %d\n"), pool_version); 505f169c0eaSGlenn Lagasse return (BE_ERR_NOTSUP); 506f169c0eaSGlenn Lagasse } 507f169c0eaSGlenn Lagasse 508f169c0eaSGlenn Lagasse /* Create the snapshots recursively */ 509f169c0eaSGlenn Lagasse if (zfs_snapshot(g_zfs, ss, B_TRUE, ss_props) != 0) { 510f169c0eaSGlenn Lagasse if (!autoname || libzfs_errno(g_zfs) != EZFS_EXISTS) { 511f169c0eaSGlenn Lagasse be_print_err(gettext("be_create_snapshot: " 512f169c0eaSGlenn Lagasse "recursive snapshot of %s failed: %s\n"), 513f169c0eaSGlenn Lagasse ss, libzfs_error_description(g_zfs)); 514f169c0eaSGlenn Lagasse 515f169c0eaSGlenn Lagasse if (libzfs_errno(g_zfs) == EZFS_EXISTS) 516f169c0eaSGlenn Lagasse ret = BE_ERR_SS_EXISTS; 517f169c0eaSGlenn Lagasse else 518f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 519f169c0eaSGlenn Lagasse 520f169c0eaSGlenn Lagasse goto done; 521f169c0eaSGlenn Lagasse } else { 522f169c0eaSGlenn Lagasse for (i = 1; i < BE_AUTO_NAME_MAX_TRY; i++) { 523f169c0eaSGlenn Lagasse 524f169c0eaSGlenn Lagasse /* Sleep 1 before retrying */ 525f169c0eaSGlenn Lagasse (void) sleep(1); 526f169c0eaSGlenn Lagasse 527f169c0eaSGlenn Lagasse /* Generate new auto snapshot name. */ 528f169c0eaSGlenn Lagasse free(bt.obe_snap_name); 529f169c0eaSGlenn Lagasse if ((bt.obe_snap_name = 530f169c0eaSGlenn Lagasse be_auto_snap_name()) == NULL) { 531f169c0eaSGlenn Lagasse be_print_err(gettext( 532f169c0eaSGlenn Lagasse "be_create_snapshot: failed to " 533f169c0eaSGlenn Lagasse "create auto snapshot name\n")); 534f169c0eaSGlenn Lagasse ret = BE_ERR_AUTONAME; 535f169c0eaSGlenn Lagasse goto done; 536f169c0eaSGlenn Lagasse } 537f169c0eaSGlenn Lagasse 538f169c0eaSGlenn Lagasse /* Generate string of the snapshot to take. */ 539f169c0eaSGlenn Lagasse (void) snprintf(ss, sizeof (ss), "%s@%s", 540f169c0eaSGlenn Lagasse bt.obe_root_ds, bt.obe_snap_name); 541f169c0eaSGlenn Lagasse 542f169c0eaSGlenn Lagasse /* Create the snapshots recursively */ 543f169c0eaSGlenn Lagasse if (zfs_snapshot(g_zfs, ss, B_TRUE, ss_props) 544f169c0eaSGlenn Lagasse != 0) { 545f169c0eaSGlenn Lagasse if (libzfs_errno(g_zfs) != 546f169c0eaSGlenn Lagasse EZFS_EXISTS) { 547f169c0eaSGlenn Lagasse be_print_err(gettext( 548f169c0eaSGlenn Lagasse "be_create_snapshot: " 549f169c0eaSGlenn Lagasse "recursive snapshot of %s " 550f169c0eaSGlenn Lagasse "failed: %s\n"), ss, 551f169c0eaSGlenn Lagasse libzfs_error_description( 552f169c0eaSGlenn Lagasse g_zfs)); 553f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 554f169c0eaSGlenn Lagasse goto done; 555f169c0eaSGlenn Lagasse } 556f169c0eaSGlenn Lagasse } else { 557f169c0eaSGlenn Lagasse break; 558f169c0eaSGlenn Lagasse } 559f169c0eaSGlenn Lagasse } 560f169c0eaSGlenn Lagasse 561f169c0eaSGlenn Lagasse /* 562f169c0eaSGlenn Lagasse * If we exhausted the maximum number of tries, 563f169c0eaSGlenn Lagasse * free the auto snap name and set error. 564f169c0eaSGlenn Lagasse */ 565f169c0eaSGlenn Lagasse if (i == BE_AUTO_NAME_MAX_TRY) { 566f169c0eaSGlenn Lagasse be_print_err(gettext("be_create_snapshot: " 567f169c0eaSGlenn Lagasse "failed to create unique auto snapshot " 568f169c0eaSGlenn Lagasse "name\n")); 569f169c0eaSGlenn Lagasse free(bt.obe_snap_name); 570f169c0eaSGlenn Lagasse bt.obe_snap_name = NULL; 571f169c0eaSGlenn Lagasse ret = BE_ERR_AUTONAME; 572f169c0eaSGlenn Lagasse } 573f169c0eaSGlenn Lagasse } 574f169c0eaSGlenn Lagasse } 575f169c0eaSGlenn Lagasse 576f169c0eaSGlenn Lagasse /* 577f169c0eaSGlenn Lagasse * If we succeeded in creating an auto named snapshot, store 578f169c0eaSGlenn Lagasse * the name in the nvlist passed in by the caller. 579f169c0eaSGlenn Lagasse */ 580f169c0eaSGlenn Lagasse if (autoname && bt.obe_snap_name) { 581f169c0eaSGlenn Lagasse *snap_name = bt.obe_snap_name; 582f169c0eaSGlenn Lagasse } 583f169c0eaSGlenn Lagasse 584f169c0eaSGlenn Lagasse done: 585f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 586f169c0eaSGlenn Lagasse 587f169c0eaSGlenn Lagasse if (ss_props != NULL) 588f169c0eaSGlenn Lagasse nvlist_free(ss_props); 589f169c0eaSGlenn Lagasse 590f169c0eaSGlenn Lagasse return (ret); 591f169c0eaSGlenn Lagasse } 592f169c0eaSGlenn Lagasse 593f169c0eaSGlenn Lagasse /* 594f169c0eaSGlenn Lagasse * Function: _be_destroy_snapshot 595f169c0eaSGlenn Lagasse * Description: see be_destroy_snapshot 596f169c0eaSGlenn Lagasse * Parameters: 597f169c0eaSGlenn Lagasse * be_name - The name of the BE that the snapshot belongs to. 598f169c0eaSGlenn Lagasse * snap_name - The name of the snapshot we're destroying. 599f169c0eaSGlenn Lagasse * Return: 600f169c0eaSGlenn Lagasse * BE_SUCCESS - Success 601f169c0eaSGlenn Lagasse * be_errno_t - Failure 602f169c0eaSGlenn Lagasse * Scope: 603f169c0eaSGlenn Lagasse * Semi-private (library wide use only) 604f169c0eaSGlenn Lagasse */ 605f169c0eaSGlenn Lagasse int 606f169c0eaSGlenn Lagasse _be_destroy_snapshot(char *be_name, char *snap_name) 607f169c0eaSGlenn Lagasse { 608f169c0eaSGlenn Lagasse be_transaction_data_t bt = { 0 }; 609f169c0eaSGlenn Lagasse zfs_handle_t *zhp; 610f169c0eaSGlenn Lagasse char ss[MAXPATHLEN]; 611f169c0eaSGlenn Lagasse char root_ds[MAXPATHLEN]; 612f169c0eaSGlenn Lagasse int err = BE_SUCCESS, ret = BE_SUCCESS; 613f169c0eaSGlenn Lagasse 614f169c0eaSGlenn Lagasse /* Make sure we actaully have a snapshot name */ 615f169c0eaSGlenn Lagasse if (snap_name == NULL) { 616f169c0eaSGlenn Lagasse be_print_err(gettext("be_destroy_snapshot: " 617f169c0eaSGlenn Lagasse "invalid snapshot name\n")); 618f169c0eaSGlenn Lagasse return (BE_ERR_INVAL); 619f169c0eaSGlenn Lagasse } 620f169c0eaSGlenn Lagasse 621f169c0eaSGlenn Lagasse /* Set parameters in bt structure */ 622f169c0eaSGlenn Lagasse bt.obe_name = be_name; 623f169c0eaSGlenn Lagasse bt.obe_snap_name = snap_name; 624f169c0eaSGlenn Lagasse 625f169c0eaSGlenn Lagasse /* If original BE name not supplied, use current BE */ 626f169c0eaSGlenn Lagasse if (bt.obe_name == NULL) { 627f169c0eaSGlenn Lagasse if ((err = be_find_current_be(&bt)) != BE_SUCCESS) { 628f169c0eaSGlenn Lagasse return (err); 629f169c0eaSGlenn Lagasse } 630f169c0eaSGlenn Lagasse } 631f169c0eaSGlenn Lagasse 632f169c0eaSGlenn Lagasse /* Find which zpool be_name lives in */ 633f169c0eaSGlenn Lagasse if ((ret = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) == 0) { 634f169c0eaSGlenn Lagasse be_print_err(gettext("be_destroy_snapshot: " 635f169c0eaSGlenn Lagasse "failed to find zpool for BE (%s)\n"), bt.obe_name); 636f169c0eaSGlenn Lagasse return (BE_ERR_BE_NOENT); 637f169c0eaSGlenn Lagasse } else if (ret < 0) { 638f169c0eaSGlenn Lagasse be_print_err(gettext("be_destroy_snapshot: " 639f169c0eaSGlenn Lagasse "zpool_iter failed: %s\n"), 640f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 641f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs)); 642f169c0eaSGlenn Lagasse } 643f169c0eaSGlenn Lagasse 644f169c0eaSGlenn Lagasse be_make_root_ds(bt.obe_zpool, bt.obe_name, root_ds, 645f169c0eaSGlenn Lagasse sizeof (root_ds)); 646f169c0eaSGlenn Lagasse bt.obe_root_ds = root_ds; 647f169c0eaSGlenn Lagasse 648f169c0eaSGlenn Lagasse zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_DATASET); 649f169c0eaSGlenn Lagasse if (zhp == NULL) { 650f169c0eaSGlenn Lagasse /* 651f169c0eaSGlenn Lagasse * The zfs_open failed, return an error. 652f169c0eaSGlenn Lagasse */ 653f169c0eaSGlenn Lagasse be_print_err(gettext("be_destroy_snapshot: " 654f169c0eaSGlenn Lagasse "failed to open BE root dataset (%s): %s\n"), 655f169c0eaSGlenn Lagasse bt.obe_root_ds, libzfs_error_description(g_zfs)); 656f169c0eaSGlenn Lagasse err = zfs_err_to_be_err(g_zfs); 657f169c0eaSGlenn Lagasse } else { 658f169c0eaSGlenn Lagasse /* 659f169c0eaSGlenn Lagasse * Generate the name of the snapshot to take. 660f169c0eaSGlenn Lagasse */ 661f169c0eaSGlenn Lagasse (void) snprintf(ss, sizeof (ss), "%s@%s", bt.obe_name, 662f169c0eaSGlenn Lagasse bt.obe_snap_name); 663f169c0eaSGlenn Lagasse 664f169c0eaSGlenn Lagasse /* 665f169c0eaSGlenn Lagasse * destroy the snapshot. 666f169c0eaSGlenn Lagasse */ 667f169c0eaSGlenn Lagasse /* 668f169c0eaSGlenn Lagasse * The boolean set to B_FALSE and passed to zfs_destroy_snaps() 669f169c0eaSGlenn Lagasse * tells zfs to process and destroy the snapshots now. 670f169c0eaSGlenn Lagasse * Otherwise the call will potentially return where the 671f169c0eaSGlenn Lagasse * snapshot isn't actually destroyed yet, and ZFS is waiting 672f169c0eaSGlenn Lagasse * until all the references to the snapshot have been 673f169c0eaSGlenn Lagasse * released before actually destroying the snapshot. 674f169c0eaSGlenn Lagasse */ 675f169c0eaSGlenn Lagasse if (zfs_destroy_snaps(zhp, bt.obe_snap_name, B_FALSE) != 0) { 676f169c0eaSGlenn Lagasse err = zfs_err_to_be_err(g_zfs); 677f169c0eaSGlenn Lagasse be_print_err(gettext("be_destroy_snapshot: " 678f169c0eaSGlenn Lagasse "failed to destroy snapshot %s: %s\n"), ss, 679f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 680f169c0eaSGlenn Lagasse } 681f169c0eaSGlenn Lagasse } 682f169c0eaSGlenn Lagasse 683f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 684f169c0eaSGlenn Lagasse 685f169c0eaSGlenn Lagasse return (err); 686f169c0eaSGlenn Lagasse } 687f169c0eaSGlenn Lagasse 688f169c0eaSGlenn Lagasse /* ******************************************************************** */ 689f169c0eaSGlenn Lagasse /* Private Functions */ 690f169c0eaSGlenn Lagasse /* ******************************************************************** */ 691f169c0eaSGlenn Lagasse 692f169c0eaSGlenn Lagasse /* 693f169c0eaSGlenn Lagasse * Function: be_rollback_check_callback 694f169c0eaSGlenn Lagasse * Description: Callback function used to iterate through a BE's filesystems 695f169c0eaSGlenn Lagasse * to check if a given snapshot name exists. 696f169c0eaSGlenn Lagasse * Parameters: 697f169c0eaSGlenn Lagasse * zhp - zfs_handle_t pointer to filesystem being processed. 698f169c0eaSGlenn Lagasse * data - name of the snapshot to check for. 699f169c0eaSGlenn Lagasse * Returns: 700f169c0eaSGlenn Lagasse * 0 - Success, snapshot name exists for all filesystems. 701f169c0eaSGlenn Lagasse * be_errno_t - Failure, snapshot name does not exist for all 702f169c0eaSGlenn Lagasse * filesystems. 703f169c0eaSGlenn Lagasse * Scope: 704f169c0eaSGlenn Lagasse * Private 705f169c0eaSGlenn Lagasse */ 706f169c0eaSGlenn Lagasse static int 707f169c0eaSGlenn Lagasse be_rollback_check_callback(zfs_handle_t *zhp, void *data) 708f169c0eaSGlenn Lagasse { 709f169c0eaSGlenn Lagasse char *snap_name = data; 710f169c0eaSGlenn Lagasse char ss[MAXPATHLEN]; 711f169c0eaSGlenn Lagasse int ret = BE_SUCCESS; 712f169c0eaSGlenn Lagasse 713f169c0eaSGlenn Lagasse /* Generate string for this filesystem's snapshot name */ 714f169c0eaSGlenn Lagasse (void) snprintf(ss, sizeof (ss), "%s@%s", zfs_get_name(zhp), snap_name); 715f169c0eaSGlenn Lagasse 716f169c0eaSGlenn Lagasse /* Check if snapshot exists */ 717f169c0eaSGlenn Lagasse if (!zfs_dataset_exists(g_zfs, ss, ZFS_TYPE_SNAPSHOT)) { 718f169c0eaSGlenn Lagasse be_print_err(gettext("be_rollback_check_callback: " 719f169c0eaSGlenn Lagasse "snapshot does not exist %s\n"), ss); 720f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 721f169c0eaSGlenn Lagasse return (BE_ERR_SS_NOENT); 722f169c0eaSGlenn Lagasse } 723f169c0eaSGlenn Lagasse 724f169c0eaSGlenn Lagasse /* Iterate this dataset's children and check them */ 725f169c0eaSGlenn Lagasse if ((ret = zfs_iter_filesystems(zhp, be_rollback_check_callback, 726f169c0eaSGlenn Lagasse snap_name)) != 0) { 727f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 728f169c0eaSGlenn Lagasse return (ret); 729f169c0eaSGlenn Lagasse } 730f169c0eaSGlenn Lagasse 731f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 732f169c0eaSGlenn Lagasse return (0); 733f169c0eaSGlenn Lagasse } 734f169c0eaSGlenn Lagasse 735f169c0eaSGlenn Lagasse /* 736f169c0eaSGlenn Lagasse * Function: be_rollback_callback 737f169c0eaSGlenn Lagasse * Description: Callback function used to iterate through a BE's filesystems 738f169c0eaSGlenn Lagasse * and roll them all back to the specified snapshot name. 739f169c0eaSGlenn Lagasse * Parameters: 740f169c0eaSGlenn Lagasse * zhp - zfs_handle_t pointer to filesystem being processed. 741f169c0eaSGlenn Lagasse * data - name of snapshot to rollback to. 742f169c0eaSGlenn Lagasse * Returns: 743f169c0eaSGlenn Lagasse * 0 - Success 744f169c0eaSGlenn Lagasse * be_errno_t - Failure 745f169c0eaSGlenn Lagasse * Scope: 746f169c0eaSGlenn Lagasse * Private 747f169c0eaSGlenn Lagasse */ 748f169c0eaSGlenn Lagasse static int 749f169c0eaSGlenn Lagasse be_rollback_callback(zfs_handle_t *zhp, void *data) 750f169c0eaSGlenn Lagasse { 751f169c0eaSGlenn Lagasse zfs_handle_t *zhp_snap = NULL; 752f169c0eaSGlenn Lagasse char *snap_name = data; 753f169c0eaSGlenn Lagasse char ss[MAXPATHLEN]; 754f169c0eaSGlenn Lagasse int ret = 0; 755f169c0eaSGlenn Lagasse 756f169c0eaSGlenn Lagasse /* Generate string for this filesystem's snapshot name */ 757f169c0eaSGlenn Lagasse (void) snprintf(ss, sizeof (ss), "%s@%s", zfs_get_name(zhp), snap_name); 758f169c0eaSGlenn Lagasse 759f169c0eaSGlenn Lagasse /* Get handle to this filesystem's snapshot */ 760f169c0eaSGlenn Lagasse if ((zhp_snap = zfs_open(g_zfs, ss, ZFS_TYPE_SNAPSHOT)) == NULL) { 761f169c0eaSGlenn Lagasse be_print_err(gettext("be_rollback_callback: " 762f169c0eaSGlenn Lagasse "failed to open snapshot %s: %s\n"), zfs_get_name(zhp), 763f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 764f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 765f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 766f169c0eaSGlenn Lagasse return (ret); 767f169c0eaSGlenn Lagasse } 768f169c0eaSGlenn Lagasse 769f169c0eaSGlenn Lagasse /* Rollback dataset */ 770f169c0eaSGlenn Lagasse if (zfs_rollback(zhp, zhp_snap, B_FALSE) != 0) { 771f169c0eaSGlenn Lagasse be_print_err(gettext("be_rollback_callback: " 772f169c0eaSGlenn Lagasse "failed to rollback BE dataset %s to snapshot %s: %s\n"), 773f169c0eaSGlenn Lagasse zfs_get_name(zhp), ss, libzfs_error_description(g_zfs)); 774f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 775f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp_snap); 776f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 777f169c0eaSGlenn Lagasse return (ret); 778f169c0eaSGlenn Lagasse } 779f169c0eaSGlenn Lagasse 780f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp_snap); 781f169c0eaSGlenn Lagasse /* Iterate this dataset's children and roll them back */ 782f169c0eaSGlenn Lagasse if ((ret = zfs_iter_filesystems(zhp, be_rollback_callback, 783f169c0eaSGlenn Lagasse snap_name)) != 0) { 784f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 785f169c0eaSGlenn Lagasse return (ret); 786f169c0eaSGlenn Lagasse } 787f169c0eaSGlenn Lagasse 788f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 789f169c0eaSGlenn Lagasse return (0); 790f169c0eaSGlenn Lagasse } 791