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