1*f169c0eaSGlenn Lagasse /* 2*f169c0eaSGlenn Lagasse * CDDL HEADER START 3*f169c0eaSGlenn Lagasse * 4*f169c0eaSGlenn Lagasse * The contents of this file are subject to the terms of the 5*f169c0eaSGlenn Lagasse * Common Development and Distribution License (the "License"). 6*f169c0eaSGlenn Lagasse * You may not use this file except in compliance with the License. 7*f169c0eaSGlenn Lagasse * 8*f169c0eaSGlenn Lagasse * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*f169c0eaSGlenn Lagasse * or http://www.opensolaris.org/os/licensing. 10*f169c0eaSGlenn Lagasse * See the License for the specific language governing permissions 11*f169c0eaSGlenn Lagasse * and limitations under the License. 12*f169c0eaSGlenn Lagasse * 13*f169c0eaSGlenn Lagasse * When distributing Covered Code, include this CDDL HEADER in each 14*f169c0eaSGlenn Lagasse * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*f169c0eaSGlenn Lagasse * If applicable, add the following below this CDDL HEADER, with the 16*f169c0eaSGlenn Lagasse * fields enclosed by brackets "[]" replaced with your own identifying 17*f169c0eaSGlenn Lagasse * information: Portions Copyright [yyyy] [name of copyright owner] 18*f169c0eaSGlenn Lagasse * 19*f169c0eaSGlenn Lagasse * CDDL HEADER END 20*f169c0eaSGlenn Lagasse */ 21*f169c0eaSGlenn Lagasse 22*f169c0eaSGlenn Lagasse /* 23*f169c0eaSGlenn Lagasse * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 24*f169c0eaSGlenn Lagasse */ 25*f169c0eaSGlenn Lagasse 26*f169c0eaSGlenn Lagasse /* 27*f169c0eaSGlenn Lagasse * System includes 28*f169c0eaSGlenn Lagasse */ 29*f169c0eaSGlenn Lagasse 30*f169c0eaSGlenn Lagasse #include <assert.h> 31*f169c0eaSGlenn Lagasse #include <ctype.h> 32*f169c0eaSGlenn Lagasse #include <errno.h> 33*f169c0eaSGlenn Lagasse #include <libgen.h> 34*f169c0eaSGlenn Lagasse #include <libintl.h> 35*f169c0eaSGlenn Lagasse #include <libnvpair.h> 36*f169c0eaSGlenn Lagasse #include <libzfs.h> 37*f169c0eaSGlenn Lagasse #include <stdio.h> 38*f169c0eaSGlenn Lagasse #include <stdlib.h> 39*f169c0eaSGlenn Lagasse #include <string.h> 40*f169c0eaSGlenn Lagasse #include <sys/mnttab.h> 41*f169c0eaSGlenn Lagasse #include <sys/mount.h> 42*f169c0eaSGlenn Lagasse #include <sys/stat.h> 43*f169c0eaSGlenn Lagasse #include <sys/types.h> 44*f169c0eaSGlenn Lagasse #include <sys/wait.h> 45*f169c0eaSGlenn Lagasse #include <unistd.h> 46*f169c0eaSGlenn Lagasse 47*f169c0eaSGlenn Lagasse #include <libbe.h> 48*f169c0eaSGlenn Lagasse #include <libbe_priv.h> 49*f169c0eaSGlenn Lagasse 50*f169c0eaSGlenn Lagasse /* Library wide variables */ 51*f169c0eaSGlenn Lagasse libzfs_handle_t *g_zfs = NULL; 52*f169c0eaSGlenn Lagasse 53*f169c0eaSGlenn Lagasse /* Private function prototypes */ 54*f169c0eaSGlenn Lagasse static int _be_destroy(const char *, be_destroy_data_t *); 55*f169c0eaSGlenn Lagasse static int be_destroy_zones(char *, char *, be_destroy_data_t *); 56*f169c0eaSGlenn Lagasse static int be_destroy_zone_roots(char *, be_destroy_data_t *); 57*f169c0eaSGlenn Lagasse static int be_destroy_zone_roots_callback(zfs_handle_t *, void *); 58*f169c0eaSGlenn Lagasse static int be_copy_zones(char *, char *, char *); 59*f169c0eaSGlenn Lagasse static int be_clone_fs_callback(zfs_handle_t *, void *); 60*f169c0eaSGlenn Lagasse static int be_destroy_callback(zfs_handle_t *, void *); 61*f169c0eaSGlenn Lagasse static int be_send_fs_callback(zfs_handle_t *, void *); 62*f169c0eaSGlenn Lagasse static int be_demote_callback(zfs_handle_t *, void *); 63*f169c0eaSGlenn Lagasse static int be_demote_find_clone_callback(zfs_handle_t *, void *); 64*f169c0eaSGlenn Lagasse static int be_demote_get_one_clone(zfs_handle_t *, void *); 65*f169c0eaSGlenn Lagasse static int be_get_snap(char *, char **); 66*f169c0eaSGlenn Lagasse static int be_prep_clone_send_fs(zfs_handle_t *, be_transaction_data_t *, 67*f169c0eaSGlenn Lagasse char *, int); 68*f169c0eaSGlenn Lagasse static boolean_t be_create_container_ds(char *); 69*f169c0eaSGlenn Lagasse static char *be_get_zone_be_name(char *root_ds, char *container_ds); 70*f169c0eaSGlenn Lagasse static int be_zone_root_exists_callback(zfs_handle_t *, void *); 71*f169c0eaSGlenn Lagasse 72*f169c0eaSGlenn Lagasse /* ******************************************************************** */ 73*f169c0eaSGlenn Lagasse /* Public Functions */ 74*f169c0eaSGlenn Lagasse /* ******************************************************************** */ 75*f169c0eaSGlenn Lagasse 76*f169c0eaSGlenn Lagasse /* 77*f169c0eaSGlenn Lagasse * Function: be_init 78*f169c0eaSGlenn Lagasse * Description: Creates the initial datasets for a BE and leaves them 79*f169c0eaSGlenn Lagasse * unpopulated. The resultant BE can be mounted but can't 80*f169c0eaSGlenn Lagasse * yet be activated or booted. 81*f169c0eaSGlenn Lagasse * Parameters: 82*f169c0eaSGlenn Lagasse * be_attrs - pointer to nvlist_t of attributes being passed in. 83*f169c0eaSGlenn Lagasse * The following attributes are used by this function: 84*f169c0eaSGlenn Lagasse * 85*f169c0eaSGlenn Lagasse * BE_ATTR_NEW_BE_NAME *required 86*f169c0eaSGlenn Lagasse * BE_ATTR_NEW_BE_POOL *required 87*f169c0eaSGlenn Lagasse * BE_ATTR_ZFS_PROPERTIES *optional 88*f169c0eaSGlenn Lagasse * BE_ATTR_FS_NAMES *optional 89*f169c0eaSGlenn Lagasse * BE_ATTR_FS_NUM *optional 90*f169c0eaSGlenn Lagasse * BE_ATTR_SHARED_FS_NAMES *optional 91*f169c0eaSGlenn Lagasse * BE_ATTR_SHARED_FS_NUM *optional 92*f169c0eaSGlenn Lagasse * Return: 93*f169c0eaSGlenn Lagasse * BE_SUCCESS - Success 94*f169c0eaSGlenn Lagasse * be_errno_t - Failure 95*f169c0eaSGlenn Lagasse * Scope: 96*f169c0eaSGlenn Lagasse * Public 97*f169c0eaSGlenn Lagasse */ 98*f169c0eaSGlenn Lagasse int 99*f169c0eaSGlenn Lagasse be_init(nvlist_t *be_attrs) 100*f169c0eaSGlenn Lagasse { 101*f169c0eaSGlenn Lagasse be_transaction_data_t bt = { 0 }; 102*f169c0eaSGlenn Lagasse zpool_handle_t *zlp; 103*f169c0eaSGlenn Lagasse nvlist_t *zfs_props = NULL; 104*f169c0eaSGlenn Lagasse char nbe_root_ds[MAXPATHLEN]; 105*f169c0eaSGlenn Lagasse char child_fs[MAXPATHLEN]; 106*f169c0eaSGlenn Lagasse char **fs_names = NULL; 107*f169c0eaSGlenn Lagasse char **shared_fs_names = NULL; 108*f169c0eaSGlenn Lagasse uint16_t fs_num = 0; 109*f169c0eaSGlenn Lagasse uint16_t shared_fs_num = 0; 110*f169c0eaSGlenn Lagasse int nelem; 111*f169c0eaSGlenn Lagasse int i; 112*f169c0eaSGlenn Lagasse int zret = 0, ret = BE_SUCCESS; 113*f169c0eaSGlenn Lagasse 114*f169c0eaSGlenn Lagasse /* Initialize libzfs handle */ 115*f169c0eaSGlenn Lagasse if (!be_zfs_init()) 116*f169c0eaSGlenn Lagasse return (BE_ERR_INIT); 117*f169c0eaSGlenn Lagasse 118*f169c0eaSGlenn Lagasse /* Get new BE name */ 119*f169c0eaSGlenn Lagasse if (nvlist_lookup_string(be_attrs, BE_ATTR_NEW_BE_NAME, &bt.nbe_name) 120*f169c0eaSGlenn Lagasse != 0) { 121*f169c0eaSGlenn Lagasse be_print_err(gettext("be_init: failed to lookup " 122*f169c0eaSGlenn Lagasse "BE_ATTR_NEW_BE_NAME attribute\n")); 123*f169c0eaSGlenn Lagasse return (BE_ERR_INVAL); 124*f169c0eaSGlenn Lagasse } 125*f169c0eaSGlenn Lagasse 126*f169c0eaSGlenn Lagasse /* Validate new BE name */ 127*f169c0eaSGlenn Lagasse if (!be_valid_be_name(bt.nbe_name)) { 128*f169c0eaSGlenn Lagasse be_print_err(gettext("be_init: invalid BE name %s\n"), 129*f169c0eaSGlenn Lagasse bt.nbe_name); 130*f169c0eaSGlenn Lagasse return (BE_ERR_INVAL); 131*f169c0eaSGlenn Lagasse } 132*f169c0eaSGlenn Lagasse 133*f169c0eaSGlenn Lagasse /* Get zpool name */ 134*f169c0eaSGlenn Lagasse if (nvlist_lookup_string(be_attrs, BE_ATTR_NEW_BE_POOL, &bt.nbe_zpool) 135*f169c0eaSGlenn Lagasse != 0) { 136*f169c0eaSGlenn Lagasse be_print_err(gettext("be_init: failed to lookup " 137*f169c0eaSGlenn Lagasse "BE_ATTR_NEW_BE_POOL attribute\n")); 138*f169c0eaSGlenn Lagasse return (BE_ERR_INVAL); 139*f169c0eaSGlenn Lagasse } 140*f169c0eaSGlenn Lagasse 141*f169c0eaSGlenn Lagasse /* Get file system attributes */ 142*f169c0eaSGlenn Lagasse nelem = 0; 143*f169c0eaSGlenn Lagasse if (nvlist_lookup_pairs(be_attrs, 0, 144*f169c0eaSGlenn Lagasse BE_ATTR_FS_NUM, DATA_TYPE_UINT16, &fs_num, 145*f169c0eaSGlenn Lagasse BE_ATTR_FS_NAMES, DATA_TYPE_STRING_ARRAY, &fs_names, &nelem, 146*f169c0eaSGlenn Lagasse NULL) != 0) { 147*f169c0eaSGlenn Lagasse be_print_err(gettext("be_init: failed to lookup fs " 148*f169c0eaSGlenn Lagasse "attributes\n")); 149*f169c0eaSGlenn Lagasse return (BE_ERR_INVAL); 150*f169c0eaSGlenn Lagasse } 151*f169c0eaSGlenn Lagasse if (nelem != fs_num) { 152*f169c0eaSGlenn Lagasse be_print_err(gettext("be_init: size of FS_NAMES array (%d) " 153*f169c0eaSGlenn Lagasse "does not match FS_NUM (%d)\n"), nelem, fs_num); 154*f169c0eaSGlenn Lagasse return (BE_ERR_INVAL); 155*f169c0eaSGlenn Lagasse } 156*f169c0eaSGlenn Lagasse 157*f169c0eaSGlenn Lagasse /* Get shared file system attributes */ 158*f169c0eaSGlenn Lagasse nelem = 0; 159*f169c0eaSGlenn Lagasse if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK, 160*f169c0eaSGlenn Lagasse BE_ATTR_SHARED_FS_NUM, DATA_TYPE_UINT16, &shared_fs_num, 161*f169c0eaSGlenn Lagasse BE_ATTR_SHARED_FS_NAMES, DATA_TYPE_STRING_ARRAY, &shared_fs_names, 162*f169c0eaSGlenn Lagasse &nelem, NULL) != 0) { 163*f169c0eaSGlenn Lagasse be_print_err(gettext("be_init: failed to lookup " 164*f169c0eaSGlenn Lagasse "shared fs attributes\n")); 165*f169c0eaSGlenn Lagasse return (BE_ERR_INVAL); 166*f169c0eaSGlenn Lagasse } 167*f169c0eaSGlenn Lagasse if (nelem != shared_fs_num) { 168*f169c0eaSGlenn Lagasse be_print_err(gettext("be_init: size of SHARED_FS_NAMES " 169*f169c0eaSGlenn Lagasse "array does not match SHARED_FS_NUM\n")); 170*f169c0eaSGlenn Lagasse return (BE_ERR_INVAL); 171*f169c0eaSGlenn Lagasse } 172*f169c0eaSGlenn Lagasse 173*f169c0eaSGlenn Lagasse /* Verify that nbe_zpool exists */ 174*f169c0eaSGlenn Lagasse if ((zlp = zpool_open(g_zfs, bt.nbe_zpool)) == NULL) { 175*f169c0eaSGlenn Lagasse be_print_err(gettext("be_init: failed to " 176*f169c0eaSGlenn Lagasse "find existing zpool (%s): %s\n"), bt.nbe_zpool, 177*f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 178*f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs)); 179*f169c0eaSGlenn Lagasse } 180*f169c0eaSGlenn Lagasse zpool_close(zlp); 181*f169c0eaSGlenn Lagasse 182*f169c0eaSGlenn Lagasse /* 183*f169c0eaSGlenn Lagasse * Verify BE container dataset in nbe_zpool exists. 184*f169c0eaSGlenn Lagasse * If not, create it. 185*f169c0eaSGlenn Lagasse */ 186*f169c0eaSGlenn Lagasse if (!be_create_container_ds(bt.nbe_zpool)) 187*f169c0eaSGlenn Lagasse return (BE_ERR_CREATDS); 188*f169c0eaSGlenn Lagasse 189*f169c0eaSGlenn Lagasse /* 190*f169c0eaSGlenn Lagasse * Verify that nbe_name doesn't already exist in some pool. 191*f169c0eaSGlenn Lagasse */ 192*f169c0eaSGlenn Lagasse if ((zret = zpool_iter(g_zfs, be_exists_callback, bt.nbe_name)) > 0) { 193*f169c0eaSGlenn Lagasse be_print_err(gettext("be_init: BE (%s) already exists\n"), 194*f169c0eaSGlenn Lagasse bt.nbe_name); 195*f169c0eaSGlenn Lagasse return (BE_ERR_BE_EXISTS); 196*f169c0eaSGlenn Lagasse } else if (zret < 0) { 197*f169c0eaSGlenn Lagasse be_print_err(gettext("be_init: zpool_iter failed: %s\n"), 198*f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 199*f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs)); 200*f169c0eaSGlenn Lagasse } 201*f169c0eaSGlenn Lagasse 202*f169c0eaSGlenn Lagasse /* Generate string for BE's root dataset */ 203*f169c0eaSGlenn Lagasse be_make_root_ds(bt.nbe_zpool, bt.nbe_name, nbe_root_ds, 204*f169c0eaSGlenn Lagasse sizeof (nbe_root_ds)); 205*f169c0eaSGlenn Lagasse 206*f169c0eaSGlenn Lagasse /* 207*f169c0eaSGlenn Lagasse * Create property list for new BE root dataset. If some 208*f169c0eaSGlenn Lagasse * zfs properties were already provided by the caller, dup 209*f169c0eaSGlenn Lagasse * that list. Otherwise initialize a new property list. 210*f169c0eaSGlenn Lagasse */ 211*f169c0eaSGlenn Lagasse if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK, 212*f169c0eaSGlenn Lagasse BE_ATTR_ZFS_PROPERTIES, DATA_TYPE_NVLIST, &zfs_props, NULL) 213*f169c0eaSGlenn Lagasse != 0) { 214*f169c0eaSGlenn Lagasse be_print_err(gettext("be_init: failed to lookup " 215*f169c0eaSGlenn Lagasse "BE_ATTR_ZFS_PROPERTIES attribute\n")); 216*f169c0eaSGlenn Lagasse return (BE_ERR_INVAL); 217*f169c0eaSGlenn Lagasse } 218*f169c0eaSGlenn Lagasse if (zfs_props != NULL) { 219*f169c0eaSGlenn Lagasse /* Make sure its a unique nvlist */ 220*f169c0eaSGlenn Lagasse if (!(zfs_props->nvl_nvflag & NV_UNIQUE_NAME) && 221*f169c0eaSGlenn Lagasse !(zfs_props->nvl_nvflag & NV_UNIQUE_NAME_TYPE)) { 222*f169c0eaSGlenn Lagasse be_print_err(gettext("be_init: ZFS property list " 223*f169c0eaSGlenn Lagasse "not unique\n")); 224*f169c0eaSGlenn Lagasse return (BE_ERR_INVAL); 225*f169c0eaSGlenn Lagasse } 226*f169c0eaSGlenn Lagasse 227*f169c0eaSGlenn Lagasse /* Dup the list */ 228*f169c0eaSGlenn Lagasse if (nvlist_dup(zfs_props, &bt.nbe_zfs_props, 0) != 0) { 229*f169c0eaSGlenn Lagasse be_print_err(gettext("be_init: failed to dup ZFS " 230*f169c0eaSGlenn Lagasse "property list\n")); 231*f169c0eaSGlenn Lagasse return (BE_ERR_NOMEM); 232*f169c0eaSGlenn Lagasse } 233*f169c0eaSGlenn Lagasse } else { 234*f169c0eaSGlenn Lagasse /* Initialize new nvlist */ 235*f169c0eaSGlenn Lagasse if (nvlist_alloc(&bt.nbe_zfs_props, NV_UNIQUE_NAME, 0) != 0) { 236*f169c0eaSGlenn Lagasse be_print_err(gettext("be_init: internal " 237*f169c0eaSGlenn Lagasse "error: out of memory\n")); 238*f169c0eaSGlenn Lagasse return (BE_ERR_NOMEM); 239*f169c0eaSGlenn Lagasse } 240*f169c0eaSGlenn Lagasse } 241*f169c0eaSGlenn Lagasse 242*f169c0eaSGlenn Lagasse /* Set the mountpoint property for the root dataset */ 243*f169c0eaSGlenn Lagasse if (nvlist_add_string(bt.nbe_zfs_props, 244*f169c0eaSGlenn Lagasse zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), "/") != 0) { 245*f169c0eaSGlenn Lagasse be_print_err(gettext("be_init: internal error " 246*f169c0eaSGlenn Lagasse "out of memory\n")); 247*f169c0eaSGlenn Lagasse ret = BE_ERR_NOMEM; 248*f169c0eaSGlenn Lagasse goto done; 249*f169c0eaSGlenn Lagasse } 250*f169c0eaSGlenn Lagasse 251*f169c0eaSGlenn Lagasse /* Set the 'canmount' property */ 252*f169c0eaSGlenn Lagasse if (nvlist_add_string(bt.nbe_zfs_props, 253*f169c0eaSGlenn Lagasse zfs_prop_to_name(ZFS_PROP_CANMOUNT), "noauto") != 0) { 254*f169c0eaSGlenn Lagasse be_print_err(gettext("be_init: internal error " 255*f169c0eaSGlenn Lagasse "out of memory\n")); 256*f169c0eaSGlenn Lagasse ret = BE_ERR_NOMEM; 257*f169c0eaSGlenn Lagasse goto done; 258*f169c0eaSGlenn Lagasse } 259*f169c0eaSGlenn Lagasse 260*f169c0eaSGlenn Lagasse /* Create BE root dataset for the new BE */ 261*f169c0eaSGlenn Lagasse if (zfs_create(g_zfs, nbe_root_ds, ZFS_TYPE_FILESYSTEM, 262*f169c0eaSGlenn Lagasse bt.nbe_zfs_props) != 0) { 263*f169c0eaSGlenn Lagasse be_print_err(gettext("be_init: failed to " 264*f169c0eaSGlenn Lagasse "create BE root dataset (%s): %s\n"), nbe_root_ds, 265*f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 266*f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 267*f169c0eaSGlenn Lagasse goto done; 268*f169c0eaSGlenn Lagasse } 269*f169c0eaSGlenn Lagasse 270*f169c0eaSGlenn Lagasse /* Set UUID for new BE */ 271*f169c0eaSGlenn Lagasse if ((ret = be_set_uuid(nbe_root_ds)) != BE_SUCCESS) { 272*f169c0eaSGlenn Lagasse be_print_err(gettext("be_init: failed to " 273*f169c0eaSGlenn Lagasse "set uuid for new BE\n")); 274*f169c0eaSGlenn Lagasse } 275*f169c0eaSGlenn Lagasse 276*f169c0eaSGlenn Lagasse /* 277*f169c0eaSGlenn Lagasse * Clear the mountpoint property so that the non-shared 278*f169c0eaSGlenn Lagasse * file systems created below inherit their mountpoints. 279*f169c0eaSGlenn Lagasse */ 280*f169c0eaSGlenn Lagasse (void) nvlist_remove(bt.nbe_zfs_props, 281*f169c0eaSGlenn Lagasse zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), DATA_TYPE_STRING); 282*f169c0eaSGlenn Lagasse 283*f169c0eaSGlenn Lagasse /* Create the new BE's non-shared file systems */ 284*f169c0eaSGlenn Lagasse for (i = 0; i < fs_num && fs_names[i]; i++) { 285*f169c0eaSGlenn Lagasse /* 286*f169c0eaSGlenn Lagasse * If fs == "/", skip it; 287*f169c0eaSGlenn Lagasse * we already created the root dataset 288*f169c0eaSGlenn Lagasse */ 289*f169c0eaSGlenn Lagasse if (strcmp(fs_names[i], "/") == 0) 290*f169c0eaSGlenn Lagasse continue; 291*f169c0eaSGlenn Lagasse 292*f169c0eaSGlenn Lagasse /* Generate string for file system */ 293*f169c0eaSGlenn Lagasse (void) snprintf(child_fs, sizeof (child_fs), "%s%s", 294*f169c0eaSGlenn Lagasse nbe_root_ds, fs_names[i]); 295*f169c0eaSGlenn Lagasse 296*f169c0eaSGlenn Lagasse /* Create file system */ 297*f169c0eaSGlenn Lagasse if (zfs_create(g_zfs, child_fs, ZFS_TYPE_FILESYSTEM, 298*f169c0eaSGlenn Lagasse bt.nbe_zfs_props) != 0) { 299*f169c0eaSGlenn Lagasse be_print_err(gettext("be_init: failed to create " 300*f169c0eaSGlenn Lagasse "BE's child dataset (%s): %s\n"), child_fs, 301*f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 302*f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 303*f169c0eaSGlenn Lagasse goto done; 304*f169c0eaSGlenn Lagasse } 305*f169c0eaSGlenn Lagasse } 306*f169c0eaSGlenn Lagasse 307*f169c0eaSGlenn Lagasse /* Create the new BE's shared file systems */ 308*f169c0eaSGlenn Lagasse if (shared_fs_num > 0) { 309*f169c0eaSGlenn Lagasse nvlist_t *props = NULL; 310*f169c0eaSGlenn Lagasse 311*f169c0eaSGlenn Lagasse if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) { 312*f169c0eaSGlenn Lagasse be_print_err(gettext("be_init: nvlist_alloc failed\n")); 313*f169c0eaSGlenn Lagasse ret = BE_ERR_NOMEM; 314*f169c0eaSGlenn Lagasse goto done; 315*f169c0eaSGlenn Lagasse } 316*f169c0eaSGlenn Lagasse 317*f169c0eaSGlenn Lagasse for (i = 0; i < shared_fs_num; i++) { 318*f169c0eaSGlenn Lagasse /* Generate string for shared file system */ 319*f169c0eaSGlenn Lagasse (void) snprintf(child_fs, sizeof (child_fs), "%s%s", 320*f169c0eaSGlenn Lagasse bt.nbe_zpool, shared_fs_names[i]); 321*f169c0eaSGlenn Lagasse 322*f169c0eaSGlenn Lagasse if (nvlist_add_string(props, 323*f169c0eaSGlenn Lagasse zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), 324*f169c0eaSGlenn Lagasse shared_fs_names[i]) != 0) { 325*f169c0eaSGlenn Lagasse be_print_err(gettext("be_init: " 326*f169c0eaSGlenn Lagasse "internal error: out of memory\n")); 327*f169c0eaSGlenn Lagasse nvlist_free(props); 328*f169c0eaSGlenn Lagasse ret = BE_ERR_NOMEM; 329*f169c0eaSGlenn Lagasse goto done; 330*f169c0eaSGlenn Lagasse } 331*f169c0eaSGlenn Lagasse 332*f169c0eaSGlenn Lagasse /* Create file system if it doesn't already exist */ 333*f169c0eaSGlenn Lagasse if (zfs_dataset_exists(g_zfs, child_fs, 334*f169c0eaSGlenn Lagasse ZFS_TYPE_FILESYSTEM)) { 335*f169c0eaSGlenn Lagasse continue; 336*f169c0eaSGlenn Lagasse } 337*f169c0eaSGlenn Lagasse if (zfs_create(g_zfs, child_fs, ZFS_TYPE_FILESYSTEM, 338*f169c0eaSGlenn Lagasse props) != 0) { 339*f169c0eaSGlenn Lagasse be_print_err(gettext("be_init: failed to " 340*f169c0eaSGlenn Lagasse "create BE's shared dataset (%s): %s\n"), 341*f169c0eaSGlenn Lagasse child_fs, libzfs_error_description(g_zfs)); 342*f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 343*f169c0eaSGlenn Lagasse nvlist_free(props); 344*f169c0eaSGlenn Lagasse goto done; 345*f169c0eaSGlenn Lagasse } 346*f169c0eaSGlenn Lagasse } 347*f169c0eaSGlenn Lagasse 348*f169c0eaSGlenn Lagasse nvlist_free(props); 349*f169c0eaSGlenn Lagasse } 350*f169c0eaSGlenn Lagasse 351*f169c0eaSGlenn Lagasse done: 352*f169c0eaSGlenn Lagasse if (bt.nbe_zfs_props != NULL) 353*f169c0eaSGlenn Lagasse nvlist_free(bt.nbe_zfs_props); 354*f169c0eaSGlenn Lagasse 355*f169c0eaSGlenn Lagasse be_zfs_fini(); 356*f169c0eaSGlenn Lagasse 357*f169c0eaSGlenn Lagasse return (ret); 358*f169c0eaSGlenn Lagasse } 359*f169c0eaSGlenn Lagasse 360*f169c0eaSGlenn Lagasse /* 361*f169c0eaSGlenn Lagasse * Function: be_destroy 362*f169c0eaSGlenn Lagasse * Description: Destroy a BE and all of its children datasets, snapshots and 363*f169c0eaSGlenn Lagasse * zones that belong to the parent BE. 364*f169c0eaSGlenn Lagasse * Parameters: 365*f169c0eaSGlenn Lagasse * be_attrs - pointer to nvlist_t of attributes being passed in. 366*f169c0eaSGlenn Lagasse * The following attributes are used by this function: 367*f169c0eaSGlenn Lagasse * 368*f169c0eaSGlenn Lagasse * BE_ATTR_ORIG_BE_NAME *required 369*f169c0eaSGlenn Lagasse * BE_ATTR_DESTROY_FLAGS *optional 370*f169c0eaSGlenn Lagasse * Return: 371*f169c0eaSGlenn Lagasse * BE_SUCCESS - Success 372*f169c0eaSGlenn Lagasse * be_errno_t - Failure 373*f169c0eaSGlenn Lagasse * Scope: 374*f169c0eaSGlenn Lagasse * Public 375*f169c0eaSGlenn Lagasse */ 376*f169c0eaSGlenn Lagasse int 377*f169c0eaSGlenn Lagasse be_destroy(nvlist_t *be_attrs) 378*f169c0eaSGlenn Lagasse { 379*f169c0eaSGlenn Lagasse zfs_handle_t *zhp = NULL; 380*f169c0eaSGlenn Lagasse be_transaction_data_t bt = { 0 }; 381*f169c0eaSGlenn Lagasse be_transaction_data_t cur_bt = { 0 }; 382*f169c0eaSGlenn Lagasse be_destroy_data_t dd = { 0 }; 383*f169c0eaSGlenn Lagasse int ret = BE_SUCCESS; 384*f169c0eaSGlenn Lagasse uint16_t flags = 0; 385*f169c0eaSGlenn Lagasse int zret; 386*f169c0eaSGlenn Lagasse char obe_root_ds[MAXPATHLEN]; 387*f169c0eaSGlenn Lagasse char *mp = NULL; 388*f169c0eaSGlenn Lagasse 389*f169c0eaSGlenn Lagasse /* Initialize libzfs handle */ 390*f169c0eaSGlenn Lagasse if (!be_zfs_init()) 391*f169c0eaSGlenn Lagasse return (BE_ERR_INIT); 392*f169c0eaSGlenn Lagasse 393*f169c0eaSGlenn Lagasse /* Get name of BE to delete */ 394*f169c0eaSGlenn Lagasse if (nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_NAME, &bt.obe_name) 395*f169c0eaSGlenn Lagasse != 0) { 396*f169c0eaSGlenn Lagasse be_print_err(gettext("be_destroy: failed to lookup " 397*f169c0eaSGlenn Lagasse "BE_ATTR_ORIG_BE_NAME attribute\n")); 398*f169c0eaSGlenn Lagasse return (BE_ERR_INVAL); 399*f169c0eaSGlenn Lagasse } 400*f169c0eaSGlenn Lagasse 401*f169c0eaSGlenn Lagasse /* 402*f169c0eaSGlenn Lagasse * Validate BE name. If valid, then check that the original BE is not 403*f169c0eaSGlenn Lagasse * the active BE. If it is the 'active' BE then return an error code 404*f169c0eaSGlenn Lagasse * since we can't destroy the active BE. 405*f169c0eaSGlenn Lagasse */ 406*f169c0eaSGlenn Lagasse if (!be_valid_be_name(bt.obe_name)) { 407*f169c0eaSGlenn Lagasse be_print_err(gettext("be_destroy: invalid BE name %s\n"), 408*f169c0eaSGlenn Lagasse bt.obe_name); 409*f169c0eaSGlenn Lagasse return (BE_ERR_INVAL); 410*f169c0eaSGlenn Lagasse } else if (bt.obe_name != NULL) { 411*f169c0eaSGlenn Lagasse if ((ret = be_find_current_be(&cur_bt)) != BE_SUCCESS) { 412*f169c0eaSGlenn Lagasse return (ret); 413*f169c0eaSGlenn Lagasse } 414*f169c0eaSGlenn Lagasse if (strcmp(cur_bt.obe_name, bt.obe_name) == 0) { 415*f169c0eaSGlenn Lagasse return (BE_ERR_DESTROY_CURR_BE); 416*f169c0eaSGlenn Lagasse } 417*f169c0eaSGlenn Lagasse } 418*f169c0eaSGlenn Lagasse 419*f169c0eaSGlenn Lagasse /* Get destroy flags if provided */ 420*f169c0eaSGlenn Lagasse if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK, 421*f169c0eaSGlenn Lagasse BE_ATTR_DESTROY_FLAGS, DATA_TYPE_UINT16, &flags, NULL) 422*f169c0eaSGlenn Lagasse != 0) { 423*f169c0eaSGlenn Lagasse be_print_err(gettext("be_destroy: failed to lookup " 424*f169c0eaSGlenn Lagasse "BE_ATTR_DESTROY_FLAGS attribute\n")); 425*f169c0eaSGlenn Lagasse return (BE_ERR_INVAL); 426*f169c0eaSGlenn Lagasse } 427*f169c0eaSGlenn Lagasse 428*f169c0eaSGlenn Lagasse dd.destroy_snaps = flags & BE_DESTROY_FLAG_SNAPSHOTS; 429*f169c0eaSGlenn Lagasse dd.force_unmount = flags & BE_DESTROY_FLAG_FORCE_UNMOUNT; 430*f169c0eaSGlenn Lagasse 431*f169c0eaSGlenn Lagasse /* Find which zpool obe_name lives in */ 432*f169c0eaSGlenn Lagasse if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) == 0) { 433*f169c0eaSGlenn Lagasse be_print_err(gettext("be_destroy: failed to find zpool " 434*f169c0eaSGlenn Lagasse "for BE (%s)\n"), bt.obe_name); 435*f169c0eaSGlenn Lagasse return (BE_ERR_BE_NOENT); 436*f169c0eaSGlenn Lagasse } else if (zret < 0) { 437*f169c0eaSGlenn Lagasse be_print_err(gettext("be_destroy: zpool_iter failed: %s\n"), 438*f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 439*f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs)); 440*f169c0eaSGlenn Lagasse } 441*f169c0eaSGlenn Lagasse 442*f169c0eaSGlenn Lagasse /* Generate string for obe_name's root dataset */ 443*f169c0eaSGlenn Lagasse be_make_root_ds(bt.obe_zpool, bt.obe_name, obe_root_ds, 444*f169c0eaSGlenn Lagasse sizeof (obe_root_ds)); 445*f169c0eaSGlenn Lagasse bt.obe_root_ds = obe_root_ds; 446*f169c0eaSGlenn Lagasse 447*f169c0eaSGlenn Lagasse /* 448*f169c0eaSGlenn Lagasse * Detect if the BE to destroy has the 'active on boot' property set. 449*f169c0eaSGlenn Lagasse * If so, set the 'active on boot' property on the the 'active' BE. 450*f169c0eaSGlenn Lagasse */ 451*f169c0eaSGlenn Lagasse if (be_is_active_on_boot(bt.obe_name)) { 452*f169c0eaSGlenn Lagasse if ((ret = be_activate_current_be()) != BE_SUCCESS) { 453*f169c0eaSGlenn Lagasse be_print_err(gettext("be_destroy: failed to " 454*f169c0eaSGlenn Lagasse "make the current BE 'active on boot'\n")); 455*f169c0eaSGlenn Lagasse return (ret); 456*f169c0eaSGlenn Lagasse } 457*f169c0eaSGlenn Lagasse } 458*f169c0eaSGlenn Lagasse 459*f169c0eaSGlenn Lagasse /* Get handle to BE's root dataset */ 460*f169c0eaSGlenn Lagasse if ((zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_FILESYSTEM)) == 461*f169c0eaSGlenn Lagasse NULL) { 462*f169c0eaSGlenn Lagasse be_print_err(gettext("be_destroy: failed to " 463*f169c0eaSGlenn Lagasse "open BE root dataset (%s): %s\n"), bt.obe_root_ds, 464*f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 465*f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs)); 466*f169c0eaSGlenn Lagasse } 467*f169c0eaSGlenn Lagasse 468*f169c0eaSGlenn Lagasse /* Get the UUID of the global BE */ 469*f169c0eaSGlenn Lagasse if (be_get_uuid(zfs_get_name(zhp), &dd.gz_be_uuid) != BE_SUCCESS) { 470*f169c0eaSGlenn Lagasse be_print_err(gettext("be_destroy: BE has no UUID (%s)\n"), 471*f169c0eaSGlenn Lagasse zfs_get_name(zhp)); 472*f169c0eaSGlenn Lagasse } 473*f169c0eaSGlenn Lagasse 474*f169c0eaSGlenn Lagasse /* 475*f169c0eaSGlenn Lagasse * If the global BE is mounted, make sure we've been given the 476*f169c0eaSGlenn Lagasse * flag to forcibly unmount it. 477*f169c0eaSGlenn Lagasse */ 478*f169c0eaSGlenn Lagasse if (zfs_is_mounted(zhp, &mp)) { 479*f169c0eaSGlenn Lagasse if (!(dd.force_unmount)) { 480*f169c0eaSGlenn Lagasse be_print_err(gettext("be_destroy: " 481*f169c0eaSGlenn Lagasse "%s is currently mounted at %s, cannot destroy\n"), 482*f169c0eaSGlenn Lagasse bt.obe_name, mp != NULL ? mp : "<unknown>"); 483*f169c0eaSGlenn Lagasse 484*f169c0eaSGlenn Lagasse free(mp); 485*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 486*f169c0eaSGlenn Lagasse return (BE_ERR_MOUNTED); 487*f169c0eaSGlenn Lagasse } 488*f169c0eaSGlenn Lagasse free(mp); 489*f169c0eaSGlenn Lagasse } 490*f169c0eaSGlenn Lagasse 491*f169c0eaSGlenn Lagasse /* 492*f169c0eaSGlenn Lagasse * Destroy the non-global zone BE's if we are in the global zone 493*f169c0eaSGlenn Lagasse * and there is a UUID associated with the global zone BE 494*f169c0eaSGlenn Lagasse */ 495*f169c0eaSGlenn Lagasse if (getzoneid() == GLOBAL_ZONEID && !uuid_is_null(dd.gz_be_uuid)) { 496*f169c0eaSGlenn Lagasse if ((ret = be_destroy_zones(bt.obe_name, bt.obe_root_ds, &dd)) 497*f169c0eaSGlenn Lagasse != BE_SUCCESS) { 498*f169c0eaSGlenn Lagasse be_print_err(gettext("be_destroy: failed to " 499*f169c0eaSGlenn Lagasse "destroy one or more zones for BE %s\n"), 500*f169c0eaSGlenn Lagasse bt.obe_name); 501*f169c0eaSGlenn Lagasse goto done; 502*f169c0eaSGlenn Lagasse } 503*f169c0eaSGlenn Lagasse } 504*f169c0eaSGlenn Lagasse 505*f169c0eaSGlenn Lagasse /* Unmount the BE if it was mounted */ 506*f169c0eaSGlenn Lagasse if (zfs_is_mounted(zhp, NULL)) { 507*f169c0eaSGlenn Lagasse if ((ret = _be_unmount(bt.obe_name, BE_UNMOUNT_FLAG_FORCE)) 508*f169c0eaSGlenn Lagasse != BE_SUCCESS) { 509*f169c0eaSGlenn Lagasse be_print_err(gettext("be_destroy: " 510*f169c0eaSGlenn Lagasse "failed to unmount %s\n"), bt.obe_name); 511*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 512*f169c0eaSGlenn Lagasse return (ret); 513*f169c0eaSGlenn Lagasse } 514*f169c0eaSGlenn Lagasse } 515*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 516*f169c0eaSGlenn Lagasse 517*f169c0eaSGlenn Lagasse /* Destroy this BE */ 518*f169c0eaSGlenn Lagasse if ((ret = _be_destroy((const char *)bt.obe_root_ds, &dd)) 519*f169c0eaSGlenn Lagasse != BE_SUCCESS) { 520*f169c0eaSGlenn Lagasse goto done; 521*f169c0eaSGlenn Lagasse } 522*f169c0eaSGlenn Lagasse 523*f169c0eaSGlenn Lagasse /* Remove BE's entry from the boot menu */ 524*f169c0eaSGlenn Lagasse if (getzoneid() == GLOBAL_ZONEID) { 525*f169c0eaSGlenn Lagasse if ((ret = be_remove_menu(bt.obe_name, bt.obe_zpool, NULL)) 526*f169c0eaSGlenn Lagasse != BE_SUCCESS) { 527*f169c0eaSGlenn Lagasse be_print_err(gettext("be_destroy: failed to " 528*f169c0eaSGlenn Lagasse "remove BE %s from the boot menu\n"), 529*f169c0eaSGlenn Lagasse bt.obe_root_ds); 530*f169c0eaSGlenn Lagasse goto done; 531*f169c0eaSGlenn Lagasse } 532*f169c0eaSGlenn Lagasse } 533*f169c0eaSGlenn Lagasse 534*f169c0eaSGlenn Lagasse done: 535*f169c0eaSGlenn Lagasse be_zfs_fini(); 536*f169c0eaSGlenn Lagasse 537*f169c0eaSGlenn Lagasse return (ret); 538*f169c0eaSGlenn Lagasse } 539*f169c0eaSGlenn Lagasse 540*f169c0eaSGlenn Lagasse /* 541*f169c0eaSGlenn Lagasse * Function: be_copy 542*f169c0eaSGlenn Lagasse * Description: This function makes a copy of an existing BE. If the original 543*f169c0eaSGlenn Lagasse * BE and the new BE are in the same pool, it uses zfs cloning to 544*f169c0eaSGlenn Lagasse * create the new BE, otherwise it does a physical copy. 545*f169c0eaSGlenn Lagasse * If the original BE name isn't provided, it uses the currently 546*f169c0eaSGlenn Lagasse * booted BE. If the new BE name isn't provided, it creates an 547*f169c0eaSGlenn Lagasse * auto named BE and returns that name to the caller. 548*f169c0eaSGlenn Lagasse * Parameters: 549*f169c0eaSGlenn Lagasse * be_attrs - pointer to nvlist_t of attributes being passed in. 550*f169c0eaSGlenn Lagasse * The following attributes are used by this function: 551*f169c0eaSGlenn Lagasse * 552*f169c0eaSGlenn Lagasse * BE_ATTR_ORIG_BE_NAME *optional 553*f169c0eaSGlenn Lagasse * BE_ATTR_SNAP_NAME *optional 554*f169c0eaSGlenn Lagasse * BE_ATTR_NEW_BE_NAME *optional 555*f169c0eaSGlenn Lagasse * BE_ATTR_NEW_BE_POOL *optional 556*f169c0eaSGlenn Lagasse * BE_ATTR_NEW_BE_DESC *optional 557*f169c0eaSGlenn Lagasse * BE_ATTR_ZFS_PROPERTIES *optional 558*f169c0eaSGlenn Lagasse * BE_ATTR_POLICY *optional 559*f169c0eaSGlenn Lagasse * 560*f169c0eaSGlenn Lagasse * If the BE_ATTR_NEW_BE_NAME was not passed in, upon 561*f169c0eaSGlenn Lagasse * successful BE creation, the following attribute values 562*f169c0eaSGlenn Lagasse * will be returned to the caller by setting them in the 563*f169c0eaSGlenn Lagasse * be_attrs parameter passed in: 564*f169c0eaSGlenn Lagasse * 565*f169c0eaSGlenn Lagasse * BE_ATTR_SNAP_NAME 566*f169c0eaSGlenn Lagasse * BE_ATTR_NEW_BE_NAME 567*f169c0eaSGlenn Lagasse * Return: 568*f169c0eaSGlenn Lagasse * BE_SUCCESS - Success 569*f169c0eaSGlenn Lagasse * be_errno_t - Failure 570*f169c0eaSGlenn Lagasse * Scope: 571*f169c0eaSGlenn Lagasse * Public 572*f169c0eaSGlenn Lagasse */ 573*f169c0eaSGlenn Lagasse int 574*f169c0eaSGlenn Lagasse be_copy(nvlist_t *be_attrs) 575*f169c0eaSGlenn Lagasse { 576*f169c0eaSGlenn Lagasse be_transaction_data_t bt = { 0 }; 577*f169c0eaSGlenn Lagasse be_fs_list_data_t fld = { 0 }; 578*f169c0eaSGlenn Lagasse zfs_handle_t *zhp = NULL; 579*f169c0eaSGlenn Lagasse nvlist_t *zfs_props = NULL; 580*f169c0eaSGlenn Lagasse uuid_t uu = { 0 }; 581*f169c0eaSGlenn Lagasse char obe_root_ds[MAXPATHLEN]; 582*f169c0eaSGlenn Lagasse char nbe_root_ds[MAXPATHLEN]; 583*f169c0eaSGlenn Lagasse char ss[MAXPATHLEN]; 584*f169c0eaSGlenn Lagasse char *new_mp = NULL; 585*f169c0eaSGlenn Lagasse boolean_t autoname = B_FALSE; 586*f169c0eaSGlenn Lagasse boolean_t be_created = B_FALSE; 587*f169c0eaSGlenn Lagasse int i; 588*f169c0eaSGlenn Lagasse int zret; 589*f169c0eaSGlenn Lagasse int ret = BE_SUCCESS; 590*f169c0eaSGlenn Lagasse 591*f169c0eaSGlenn Lagasse /* Initialize libzfs handle */ 592*f169c0eaSGlenn Lagasse if (!be_zfs_init()) 593*f169c0eaSGlenn Lagasse return (BE_ERR_INIT); 594*f169c0eaSGlenn Lagasse 595*f169c0eaSGlenn Lagasse /* Get original BE name */ 596*f169c0eaSGlenn Lagasse if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK, 597*f169c0eaSGlenn Lagasse BE_ATTR_ORIG_BE_NAME, DATA_TYPE_STRING, &bt.obe_name, NULL) != 0) { 598*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy: failed to lookup " 599*f169c0eaSGlenn Lagasse "BE_ATTR_ORIG_BE_NAME attribute\n")); 600*f169c0eaSGlenn Lagasse return (BE_ERR_INVAL); 601*f169c0eaSGlenn Lagasse } 602*f169c0eaSGlenn Lagasse 603*f169c0eaSGlenn Lagasse /* If original BE name not provided, use current BE */ 604*f169c0eaSGlenn Lagasse if (bt.obe_name == NULL) { 605*f169c0eaSGlenn Lagasse if ((ret = be_find_current_be(&bt)) != BE_SUCCESS) { 606*f169c0eaSGlenn Lagasse return (ret); 607*f169c0eaSGlenn Lagasse } 608*f169c0eaSGlenn Lagasse } else { 609*f169c0eaSGlenn Lagasse /* Validate original BE name */ 610*f169c0eaSGlenn Lagasse if (!be_valid_be_name(bt.obe_name)) { 611*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy: " 612*f169c0eaSGlenn Lagasse "invalid BE name %s\n"), bt.obe_name); 613*f169c0eaSGlenn Lagasse return (BE_ERR_INVAL); 614*f169c0eaSGlenn Lagasse } 615*f169c0eaSGlenn Lagasse } 616*f169c0eaSGlenn Lagasse 617*f169c0eaSGlenn Lagasse /* Find which zpool obe_name lives in */ 618*f169c0eaSGlenn Lagasse if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) == 0) { 619*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy: failed to " 620*f169c0eaSGlenn Lagasse "find zpool for BE (%s)\n"), bt.obe_name); 621*f169c0eaSGlenn Lagasse return (BE_ERR_BE_NOENT); 622*f169c0eaSGlenn Lagasse } else if (zret < 0) { 623*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy: " 624*f169c0eaSGlenn Lagasse "zpool_iter failed: %s\n"), 625*f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 626*f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs)); 627*f169c0eaSGlenn Lagasse } 628*f169c0eaSGlenn Lagasse 629*f169c0eaSGlenn Lagasse /* Get snapshot name of original BE if one was provided */ 630*f169c0eaSGlenn Lagasse if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK, 631*f169c0eaSGlenn Lagasse BE_ATTR_SNAP_NAME, DATA_TYPE_STRING, &bt.obe_snap_name, NULL) 632*f169c0eaSGlenn Lagasse != 0) { 633*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy: failed to lookup " 634*f169c0eaSGlenn Lagasse "BE_ATTR_SNAP_NAME attribute\n")); 635*f169c0eaSGlenn Lagasse return (BE_ERR_INVAL); 636*f169c0eaSGlenn Lagasse } 637*f169c0eaSGlenn Lagasse 638*f169c0eaSGlenn Lagasse /* Get new BE name */ 639*f169c0eaSGlenn Lagasse if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK, 640*f169c0eaSGlenn Lagasse BE_ATTR_NEW_BE_NAME, DATA_TYPE_STRING, &bt.nbe_name, NULL) 641*f169c0eaSGlenn Lagasse != 0) { 642*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy: failed to lookup " 643*f169c0eaSGlenn Lagasse "BE_ATTR_NEW_BE_NAME attribute\n")); 644*f169c0eaSGlenn Lagasse return (BE_ERR_INVAL); 645*f169c0eaSGlenn Lagasse } 646*f169c0eaSGlenn Lagasse 647*f169c0eaSGlenn Lagasse /* Get zpool name to create new BE in */ 648*f169c0eaSGlenn Lagasse if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK, 649*f169c0eaSGlenn Lagasse BE_ATTR_NEW_BE_POOL, DATA_TYPE_STRING, &bt.nbe_zpool, NULL) != 0) { 650*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy: failed to lookup " 651*f169c0eaSGlenn Lagasse "BE_ATTR_NEW_BE_POOL attribute\n")); 652*f169c0eaSGlenn Lagasse return (BE_ERR_INVAL); 653*f169c0eaSGlenn Lagasse } 654*f169c0eaSGlenn Lagasse 655*f169c0eaSGlenn Lagasse /* Get new BE's description if one was provided */ 656*f169c0eaSGlenn Lagasse if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK, 657*f169c0eaSGlenn Lagasse BE_ATTR_NEW_BE_DESC, DATA_TYPE_STRING, &bt.nbe_desc, NULL) != 0) { 658*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy: failed to lookup " 659*f169c0eaSGlenn Lagasse "BE_ATTR_NEW_BE_DESC attribute\n")); 660*f169c0eaSGlenn Lagasse return (BE_ERR_INVAL); 661*f169c0eaSGlenn Lagasse } 662*f169c0eaSGlenn Lagasse 663*f169c0eaSGlenn Lagasse /* Get BE policy to create this snapshot under */ 664*f169c0eaSGlenn Lagasse if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK, 665*f169c0eaSGlenn Lagasse BE_ATTR_POLICY, DATA_TYPE_STRING, &bt.policy, NULL) != 0) { 666*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy: failed to lookup " 667*f169c0eaSGlenn Lagasse "BE_ATTR_POLICY attribute\n")); 668*f169c0eaSGlenn Lagasse return (BE_ERR_INVAL); 669*f169c0eaSGlenn Lagasse } 670*f169c0eaSGlenn Lagasse 671*f169c0eaSGlenn Lagasse /* 672*f169c0eaSGlenn Lagasse * Create property list for new BE root dataset. If some 673*f169c0eaSGlenn Lagasse * zfs properties were already provided by the caller, dup 674*f169c0eaSGlenn Lagasse * that list. Otherwise initialize a new property list. 675*f169c0eaSGlenn Lagasse */ 676*f169c0eaSGlenn Lagasse if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK, 677*f169c0eaSGlenn Lagasse BE_ATTR_ZFS_PROPERTIES, DATA_TYPE_NVLIST, &zfs_props, NULL) 678*f169c0eaSGlenn Lagasse != 0) { 679*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy: failed to lookup " 680*f169c0eaSGlenn Lagasse "BE_ATTR_ZFS_PROPERTIES attribute\n")); 681*f169c0eaSGlenn Lagasse return (BE_ERR_INVAL); 682*f169c0eaSGlenn Lagasse } 683*f169c0eaSGlenn Lagasse if (zfs_props != NULL) { 684*f169c0eaSGlenn Lagasse /* Make sure its a unique nvlist */ 685*f169c0eaSGlenn Lagasse if (!(zfs_props->nvl_nvflag & NV_UNIQUE_NAME) && 686*f169c0eaSGlenn Lagasse !(zfs_props->nvl_nvflag & NV_UNIQUE_NAME_TYPE)) { 687*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy: ZFS property list " 688*f169c0eaSGlenn Lagasse "not unique\n")); 689*f169c0eaSGlenn Lagasse return (BE_ERR_INVAL); 690*f169c0eaSGlenn Lagasse } 691*f169c0eaSGlenn Lagasse 692*f169c0eaSGlenn Lagasse /* Dup the list */ 693*f169c0eaSGlenn Lagasse if (nvlist_dup(zfs_props, &bt.nbe_zfs_props, 0) != 0) { 694*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy: " 695*f169c0eaSGlenn Lagasse "failed to dup ZFS property list\n")); 696*f169c0eaSGlenn Lagasse return (BE_ERR_NOMEM); 697*f169c0eaSGlenn Lagasse } 698*f169c0eaSGlenn Lagasse } else { 699*f169c0eaSGlenn Lagasse /* Initialize new nvlist */ 700*f169c0eaSGlenn Lagasse if (nvlist_alloc(&bt.nbe_zfs_props, NV_UNIQUE_NAME, 0) != 0) { 701*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy: internal " 702*f169c0eaSGlenn Lagasse "error: out of memory\n")); 703*f169c0eaSGlenn Lagasse return (BE_ERR_NOMEM); 704*f169c0eaSGlenn Lagasse } 705*f169c0eaSGlenn Lagasse } 706*f169c0eaSGlenn Lagasse 707*f169c0eaSGlenn Lagasse /* 708*f169c0eaSGlenn Lagasse * If new BE name provided, validate the BE name and then verify 709*f169c0eaSGlenn Lagasse * that new BE name doesn't already exist in some pool. 710*f169c0eaSGlenn Lagasse */ 711*f169c0eaSGlenn Lagasse if (bt.nbe_name) { 712*f169c0eaSGlenn Lagasse /* Validate original BE name */ 713*f169c0eaSGlenn Lagasse if (!be_valid_be_name(bt.nbe_name)) { 714*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy: " 715*f169c0eaSGlenn Lagasse "invalid BE name %s\n"), bt.nbe_name); 716*f169c0eaSGlenn Lagasse ret = BE_ERR_INVAL; 717*f169c0eaSGlenn Lagasse goto done; 718*f169c0eaSGlenn Lagasse } 719*f169c0eaSGlenn Lagasse 720*f169c0eaSGlenn Lagasse /* Verify it doesn't already exist */ 721*f169c0eaSGlenn Lagasse if ((zret = zpool_iter(g_zfs, be_exists_callback, bt.nbe_name)) 722*f169c0eaSGlenn Lagasse > 0) { 723*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy: BE (%s) already " 724*f169c0eaSGlenn Lagasse "exists\n"), bt.nbe_name); 725*f169c0eaSGlenn Lagasse ret = BE_ERR_BE_EXISTS; 726*f169c0eaSGlenn Lagasse goto done; 727*f169c0eaSGlenn Lagasse } else if (zret < 0) { 728*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy: zpool_iter failed: " 729*f169c0eaSGlenn Lagasse "%s\n"), libzfs_error_description(g_zfs)); 730*f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 731*f169c0eaSGlenn Lagasse goto done; 732*f169c0eaSGlenn Lagasse } 733*f169c0eaSGlenn Lagasse } else { 734*f169c0eaSGlenn Lagasse /* 735*f169c0eaSGlenn Lagasse * If an auto named BE is desired, it must be in the same 736*f169c0eaSGlenn Lagasse * pool is the original BE. 737*f169c0eaSGlenn Lagasse */ 738*f169c0eaSGlenn Lagasse if (bt.nbe_zpool != NULL) { 739*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy: cannot specify pool " 740*f169c0eaSGlenn Lagasse "name when creating an auto named BE\n")); 741*f169c0eaSGlenn Lagasse ret = BE_ERR_INVAL; 742*f169c0eaSGlenn Lagasse goto done; 743*f169c0eaSGlenn Lagasse } 744*f169c0eaSGlenn Lagasse 745*f169c0eaSGlenn Lagasse /* 746*f169c0eaSGlenn Lagasse * Generate auto named BE 747*f169c0eaSGlenn Lagasse */ 748*f169c0eaSGlenn Lagasse if ((bt.nbe_name = be_auto_be_name(bt.obe_name)) 749*f169c0eaSGlenn Lagasse == NULL) { 750*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy: " 751*f169c0eaSGlenn Lagasse "failed to generate auto BE name\n")); 752*f169c0eaSGlenn Lagasse ret = BE_ERR_AUTONAME; 753*f169c0eaSGlenn Lagasse goto done; 754*f169c0eaSGlenn Lagasse } 755*f169c0eaSGlenn Lagasse 756*f169c0eaSGlenn Lagasse autoname = B_TRUE; 757*f169c0eaSGlenn Lagasse } 758*f169c0eaSGlenn Lagasse 759*f169c0eaSGlenn Lagasse /* 760*f169c0eaSGlenn Lagasse * If zpool name to create new BE in is not provided, 761*f169c0eaSGlenn Lagasse * create new BE in original BE's pool. 762*f169c0eaSGlenn Lagasse */ 763*f169c0eaSGlenn Lagasse if (bt.nbe_zpool == NULL) { 764*f169c0eaSGlenn Lagasse bt.nbe_zpool = bt.obe_zpool; 765*f169c0eaSGlenn Lagasse } 766*f169c0eaSGlenn Lagasse 767*f169c0eaSGlenn Lagasse /* Get root dataset names for obe_name and nbe_name */ 768*f169c0eaSGlenn Lagasse be_make_root_ds(bt.obe_zpool, bt.obe_name, obe_root_ds, 769*f169c0eaSGlenn Lagasse sizeof (obe_root_ds)); 770*f169c0eaSGlenn Lagasse be_make_root_ds(bt.nbe_zpool, bt.nbe_name, nbe_root_ds, 771*f169c0eaSGlenn Lagasse sizeof (nbe_root_ds)); 772*f169c0eaSGlenn Lagasse 773*f169c0eaSGlenn Lagasse bt.obe_root_ds = obe_root_ds; 774*f169c0eaSGlenn Lagasse bt.nbe_root_ds = nbe_root_ds; 775*f169c0eaSGlenn Lagasse 776*f169c0eaSGlenn Lagasse /* 777*f169c0eaSGlenn Lagasse * If an existing snapshot name has been provided to create from, 778*f169c0eaSGlenn Lagasse * verify that it exists for the original BE's root dataset. 779*f169c0eaSGlenn Lagasse */ 780*f169c0eaSGlenn Lagasse if (bt.obe_snap_name != NULL) { 781*f169c0eaSGlenn Lagasse 782*f169c0eaSGlenn Lagasse /* Generate dataset name for snapshot to use. */ 783*f169c0eaSGlenn Lagasse (void) snprintf(ss, sizeof (ss), "%s@%s", bt.obe_root_ds, 784*f169c0eaSGlenn Lagasse bt.obe_snap_name); 785*f169c0eaSGlenn Lagasse 786*f169c0eaSGlenn Lagasse /* Verify snapshot exists */ 787*f169c0eaSGlenn Lagasse if (!zfs_dataset_exists(g_zfs, ss, ZFS_TYPE_SNAPSHOT)) { 788*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy: " 789*f169c0eaSGlenn Lagasse "snapshot does not exist (%s): %s\n"), ss, 790*f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 791*f169c0eaSGlenn Lagasse ret = BE_ERR_SS_NOENT; 792*f169c0eaSGlenn Lagasse goto done; 793*f169c0eaSGlenn Lagasse } 794*f169c0eaSGlenn Lagasse } else { 795*f169c0eaSGlenn Lagasse /* 796*f169c0eaSGlenn Lagasse * Else snapshot name was not provided, generate an 797*f169c0eaSGlenn Lagasse * auto named snapshot to use as its origin. 798*f169c0eaSGlenn Lagasse */ 799*f169c0eaSGlenn Lagasse if ((ret = _be_create_snapshot(bt.obe_name, 800*f169c0eaSGlenn Lagasse &bt.obe_snap_name, bt.policy)) != BE_SUCCESS) { 801*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy: " 802*f169c0eaSGlenn Lagasse "failed to create auto named snapshot\n")); 803*f169c0eaSGlenn Lagasse goto done; 804*f169c0eaSGlenn Lagasse } 805*f169c0eaSGlenn Lagasse 806*f169c0eaSGlenn Lagasse if (nvlist_add_string(be_attrs, BE_ATTR_SNAP_NAME, 807*f169c0eaSGlenn Lagasse bt.obe_snap_name) != 0) { 808*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy: " 809*f169c0eaSGlenn Lagasse "failed to add snap name to be_attrs\n")); 810*f169c0eaSGlenn Lagasse ret = BE_ERR_NOMEM; 811*f169c0eaSGlenn Lagasse goto done; 812*f169c0eaSGlenn Lagasse } 813*f169c0eaSGlenn Lagasse } 814*f169c0eaSGlenn Lagasse 815*f169c0eaSGlenn Lagasse /* Get handle to original BE's root dataset. */ 816*f169c0eaSGlenn Lagasse if ((zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_FILESYSTEM)) 817*f169c0eaSGlenn Lagasse == NULL) { 818*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy: failed to " 819*f169c0eaSGlenn Lagasse "open BE root dataset (%s): %s\n"), bt.obe_root_ds, 820*f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 821*f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 822*f169c0eaSGlenn Lagasse goto done; 823*f169c0eaSGlenn Lagasse } 824*f169c0eaSGlenn Lagasse 825*f169c0eaSGlenn Lagasse /* If original BE is currently mounted, record its altroot. */ 826*f169c0eaSGlenn Lagasse if (zfs_is_mounted(zhp, &bt.obe_altroot) && bt.obe_altroot == NULL) { 827*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy: failed to " 828*f169c0eaSGlenn Lagasse "get altroot of mounted BE %s: %s\n"), 829*f169c0eaSGlenn Lagasse bt.obe_name, libzfs_error_description(g_zfs)); 830*f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 831*f169c0eaSGlenn Lagasse goto done; 832*f169c0eaSGlenn Lagasse } 833*f169c0eaSGlenn Lagasse 834*f169c0eaSGlenn Lagasse if (strcmp(bt.obe_zpool, bt.nbe_zpool) == 0) { 835*f169c0eaSGlenn Lagasse 836*f169c0eaSGlenn Lagasse /* Do clone */ 837*f169c0eaSGlenn Lagasse 838*f169c0eaSGlenn Lagasse /* 839*f169c0eaSGlenn Lagasse * Iterate through original BE's datasets and clone 840*f169c0eaSGlenn Lagasse * them to create new BE. This call will end up closing 841*f169c0eaSGlenn Lagasse * the zfs handle passed in whether it succeeds for fails. 842*f169c0eaSGlenn Lagasse */ 843*f169c0eaSGlenn Lagasse if ((ret = be_clone_fs_callback(zhp, &bt)) != 0) { 844*f169c0eaSGlenn Lagasse zhp = NULL; 845*f169c0eaSGlenn Lagasse /* Creating clone BE failed */ 846*f169c0eaSGlenn Lagasse if (!autoname || ret != BE_ERR_BE_EXISTS) { 847*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy: " 848*f169c0eaSGlenn Lagasse "failed to clone new BE (%s) from " 849*f169c0eaSGlenn Lagasse "orig BE (%s)\n"), 850*f169c0eaSGlenn Lagasse bt.nbe_name, bt.obe_name); 851*f169c0eaSGlenn Lagasse ret = BE_ERR_CLONE; 852*f169c0eaSGlenn Lagasse goto done; 853*f169c0eaSGlenn Lagasse } 854*f169c0eaSGlenn Lagasse 855*f169c0eaSGlenn Lagasse /* 856*f169c0eaSGlenn Lagasse * We failed to create the new BE because a BE with 857*f169c0eaSGlenn Lagasse * the auto-name we generated above has since come 858*f169c0eaSGlenn Lagasse * into existence. Regenerate a new auto-name 859*f169c0eaSGlenn Lagasse * and retry. 860*f169c0eaSGlenn Lagasse */ 861*f169c0eaSGlenn Lagasse for (i = 1; i < BE_AUTO_NAME_MAX_TRY; i++) { 862*f169c0eaSGlenn Lagasse 863*f169c0eaSGlenn Lagasse /* Sleep 1 before retrying */ 864*f169c0eaSGlenn Lagasse (void) sleep(1); 865*f169c0eaSGlenn Lagasse 866*f169c0eaSGlenn Lagasse /* Generate new auto BE name */ 867*f169c0eaSGlenn Lagasse free(bt.nbe_name); 868*f169c0eaSGlenn Lagasse if ((bt.nbe_name = be_auto_be_name(bt.obe_name)) 869*f169c0eaSGlenn Lagasse == NULL) { 870*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy: " 871*f169c0eaSGlenn Lagasse "failed to generate auto " 872*f169c0eaSGlenn Lagasse "BE name\n")); 873*f169c0eaSGlenn Lagasse ret = BE_ERR_AUTONAME; 874*f169c0eaSGlenn Lagasse goto done; 875*f169c0eaSGlenn Lagasse } 876*f169c0eaSGlenn Lagasse 877*f169c0eaSGlenn Lagasse /* 878*f169c0eaSGlenn Lagasse * Regenerate string for new BE's 879*f169c0eaSGlenn Lagasse * root dataset name 880*f169c0eaSGlenn Lagasse */ 881*f169c0eaSGlenn Lagasse be_make_root_ds(bt.nbe_zpool, bt.nbe_name, 882*f169c0eaSGlenn Lagasse nbe_root_ds, sizeof (nbe_root_ds)); 883*f169c0eaSGlenn Lagasse bt.nbe_root_ds = nbe_root_ds; 884*f169c0eaSGlenn Lagasse 885*f169c0eaSGlenn Lagasse /* 886*f169c0eaSGlenn Lagasse * Get handle to original BE's root dataset. 887*f169c0eaSGlenn Lagasse */ 888*f169c0eaSGlenn Lagasse if ((zhp = zfs_open(g_zfs, bt.obe_root_ds, 889*f169c0eaSGlenn Lagasse ZFS_TYPE_FILESYSTEM)) == NULL) { 890*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy: " 891*f169c0eaSGlenn Lagasse "failed to open BE root dataset " 892*f169c0eaSGlenn Lagasse "(%s): %s\n"), bt.obe_root_ds, 893*f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 894*f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 895*f169c0eaSGlenn Lagasse goto done; 896*f169c0eaSGlenn Lagasse } 897*f169c0eaSGlenn Lagasse 898*f169c0eaSGlenn Lagasse /* 899*f169c0eaSGlenn Lagasse * Try to clone the BE again. This 900*f169c0eaSGlenn Lagasse * call will end up closing the zfs 901*f169c0eaSGlenn Lagasse * handle passed in whether it 902*f169c0eaSGlenn Lagasse * succeeds or fails. 903*f169c0eaSGlenn Lagasse */ 904*f169c0eaSGlenn Lagasse ret = be_clone_fs_callback(zhp, &bt); 905*f169c0eaSGlenn Lagasse zhp = NULL; 906*f169c0eaSGlenn Lagasse if (ret == 0) { 907*f169c0eaSGlenn Lagasse break; 908*f169c0eaSGlenn Lagasse } else if (ret != BE_ERR_BE_EXISTS) { 909*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy: " 910*f169c0eaSGlenn Lagasse "failed to clone new BE " 911*f169c0eaSGlenn Lagasse "(%s) from orig BE (%s)\n"), 912*f169c0eaSGlenn Lagasse bt.nbe_name, bt.obe_name); 913*f169c0eaSGlenn Lagasse ret = BE_ERR_CLONE; 914*f169c0eaSGlenn Lagasse goto done; 915*f169c0eaSGlenn Lagasse } 916*f169c0eaSGlenn Lagasse } 917*f169c0eaSGlenn Lagasse 918*f169c0eaSGlenn Lagasse /* 919*f169c0eaSGlenn Lagasse * If we've exhausted the maximum number of 920*f169c0eaSGlenn Lagasse * tries, free the auto BE name and return 921*f169c0eaSGlenn Lagasse * error. 922*f169c0eaSGlenn Lagasse */ 923*f169c0eaSGlenn Lagasse if (i == BE_AUTO_NAME_MAX_TRY) { 924*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy: failed " 925*f169c0eaSGlenn Lagasse "to create unique auto BE name\n")); 926*f169c0eaSGlenn Lagasse free(bt.nbe_name); 927*f169c0eaSGlenn Lagasse bt.nbe_name = NULL; 928*f169c0eaSGlenn Lagasse ret = BE_ERR_AUTONAME; 929*f169c0eaSGlenn Lagasse goto done; 930*f169c0eaSGlenn Lagasse } 931*f169c0eaSGlenn Lagasse } 932*f169c0eaSGlenn Lagasse zhp = NULL; 933*f169c0eaSGlenn Lagasse 934*f169c0eaSGlenn Lagasse } else { 935*f169c0eaSGlenn Lagasse 936*f169c0eaSGlenn Lagasse /* Do copy (i.e. send BE datasets via zfs_send/recv) */ 937*f169c0eaSGlenn Lagasse 938*f169c0eaSGlenn Lagasse /* 939*f169c0eaSGlenn Lagasse * Verify BE container dataset in nbe_zpool exists. 940*f169c0eaSGlenn Lagasse * If not, create it. 941*f169c0eaSGlenn Lagasse */ 942*f169c0eaSGlenn Lagasse if (!be_create_container_ds(bt.nbe_zpool)) { 943*f169c0eaSGlenn Lagasse ret = BE_ERR_CREATDS; 944*f169c0eaSGlenn Lagasse goto done; 945*f169c0eaSGlenn Lagasse } 946*f169c0eaSGlenn Lagasse 947*f169c0eaSGlenn Lagasse /* 948*f169c0eaSGlenn Lagasse * Iterate through original BE's datasets and send 949*f169c0eaSGlenn Lagasse * them to the other pool. This call will end up closing 950*f169c0eaSGlenn Lagasse * the zfs handle passed in whether it succeeds or fails. 951*f169c0eaSGlenn Lagasse */ 952*f169c0eaSGlenn Lagasse if ((ret = be_send_fs_callback(zhp, &bt)) != 0) { 953*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy: failed to " 954*f169c0eaSGlenn Lagasse "send BE (%s) to pool (%s)\n"), bt.obe_name, 955*f169c0eaSGlenn Lagasse bt.nbe_zpool); 956*f169c0eaSGlenn Lagasse ret = BE_ERR_COPY; 957*f169c0eaSGlenn Lagasse zhp = NULL; 958*f169c0eaSGlenn Lagasse goto done; 959*f169c0eaSGlenn Lagasse } 960*f169c0eaSGlenn Lagasse zhp = NULL; 961*f169c0eaSGlenn Lagasse } 962*f169c0eaSGlenn Lagasse 963*f169c0eaSGlenn Lagasse /* 964*f169c0eaSGlenn Lagasse * Set flag to note that the dataset(s) for the new BE have been 965*f169c0eaSGlenn Lagasse * successfully created so that if a failure happens from this point 966*f169c0eaSGlenn Lagasse * on, we know to cleanup these datasets. 967*f169c0eaSGlenn Lagasse */ 968*f169c0eaSGlenn Lagasse be_created = B_TRUE; 969*f169c0eaSGlenn Lagasse 970*f169c0eaSGlenn Lagasse /* 971*f169c0eaSGlenn Lagasse * Validate that the new BE is mountable. 972*f169c0eaSGlenn Lagasse * Do not attempt to mount non-global zone datasets 973*f169c0eaSGlenn Lagasse * since they are not cloned yet. 974*f169c0eaSGlenn Lagasse */ 975*f169c0eaSGlenn Lagasse if ((ret = _be_mount(bt.nbe_name, &new_mp, BE_MOUNT_FLAG_NO_ZONES)) 976*f169c0eaSGlenn Lagasse != BE_SUCCESS) { 977*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy: failed to " 978*f169c0eaSGlenn Lagasse "mount newly created BE\n")); 979*f169c0eaSGlenn Lagasse (void) _be_unmount(bt.nbe_name, 0); 980*f169c0eaSGlenn Lagasse goto done; 981*f169c0eaSGlenn Lagasse } 982*f169c0eaSGlenn Lagasse 983*f169c0eaSGlenn Lagasse /* Set UUID for new BE */ 984*f169c0eaSGlenn Lagasse if (be_set_uuid(bt.nbe_root_ds) != BE_SUCCESS) { 985*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy: failed to " 986*f169c0eaSGlenn Lagasse "set uuid for new BE\n")); 987*f169c0eaSGlenn Lagasse } 988*f169c0eaSGlenn Lagasse 989*f169c0eaSGlenn Lagasse /* 990*f169c0eaSGlenn Lagasse * Process zones outside of the private BE namespace. 991*f169c0eaSGlenn Lagasse * This has to be done here because we need the uuid set in the 992*f169c0eaSGlenn Lagasse * root dataset of the new BE. The uuid is use to set the parentbe 993*f169c0eaSGlenn Lagasse * property for the new zones datasets. 994*f169c0eaSGlenn Lagasse */ 995*f169c0eaSGlenn Lagasse if (getzoneid() == GLOBAL_ZONEID && 996*f169c0eaSGlenn Lagasse be_get_uuid(bt.obe_root_ds, &uu) == BE_SUCCESS) { 997*f169c0eaSGlenn Lagasse if ((ret = be_copy_zones(bt.obe_name, bt.obe_root_ds, 998*f169c0eaSGlenn Lagasse bt.nbe_root_ds)) != BE_SUCCESS) { 999*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy: failed to process " 1000*f169c0eaSGlenn Lagasse "zones\n")); 1001*f169c0eaSGlenn Lagasse goto done; 1002*f169c0eaSGlenn Lagasse } 1003*f169c0eaSGlenn Lagasse } 1004*f169c0eaSGlenn Lagasse 1005*f169c0eaSGlenn Lagasse /* 1006*f169c0eaSGlenn Lagasse * Generate a list of file systems from the original BE that are 1007*f169c0eaSGlenn Lagasse * legacy mounted. We use this list to determine which entries in 1008*f169c0eaSGlenn Lagasse * vfstab we need to update for the new BE we've just created. 1009*f169c0eaSGlenn Lagasse */ 1010*f169c0eaSGlenn Lagasse if ((ret = be_get_legacy_fs(bt.obe_name, bt.obe_root_ds, NULL, NULL, 1011*f169c0eaSGlenn Lagasse &fld)) != BE_SUCCESS) { 1012*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy: failed to " 1013*f169c0eaSGlenn Lagasse "get legacy mounted file system list for %s\n"), 1014*f169c0eaSGlenn Lagasse bt.obe_name); 1015*f169c0eaSGlenn Lagasse goto done; 1016*f169c0eaSGlenn Lagasse } 1017*f169c0eaSGlenn Lagasse 1018*f169c0eaSGlenn Lagasse /* 1019*f169c0eaSGlenn Lagasse * Update new BE's vfstab. 1020*f169c0eaSGlenn Lagasse */ 1021*f169c0eaSGlenn Lagasse if ((ret = be_update_vfstab(bt.nbe_name, bt.obe_zpool, bt.nbe_zpool, 1022*f169c0eaSGlenn Lagasse &fld, new_mp)) != BE_SUCCESS) { 1023*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy: failed to " 1024*f169c0eaSGlenn Lagasse "update new BE's vfstab (%s)\n"), bt.nbe_name); 1025*f169c0eaSGlenn Lagasse goto done; 1026*f169c0eaSGlenn Lagasse } 1027*f169c0eaSGlenn Lagasse 1028*f169c0eaSGlenn Lagasse /* Unmount the new BE */ 1029*f169c0eaSGlenn Lagasse if ((ret = _be_unmount(bt.nbe_name, 0)) != BE_SUCCESS) { 1030*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy: failed to " 1031*f169c0eaSGlenn Lagasse "unmount newly created BE\n")); 1032*f169c0eaSGlenn Lagasse goto done; 1033*f169c0eaSGlenn Lagasse } 1034*f169c0eaSGlenn Lagasse 1035*f169c0eaSGlenn Lagasse /* 1036*f169c0eaSGlenn Lagasse * Add boot menu entry for newly created clone 1037*f169c0eaSGlenn Lagasse */ 1038*f169c0eaSGlenn Lagasse if (getzoneid() == GLOBAL_ZONEID && 1039*f169c0eaSGlenn Lagasse (ret = be_append_menu(bt.nbe_name, bt.nbe_zpool, 1040*f169c0eaSGlenn Lagasse NULL, bt.obe_root_ds, bt.nbe_desc)) != BE_SUCCESS) { 1041*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy: failed to " 1042*f169c0eaSGlenn Lagasse "add BE (%s) to boot menu\n"), bt.nbe_name); 1043*f169c0eaSGlenn Lagasse goto done; 1044*f169c0eaSGlenn Lagasse } 1045*f169c0eaSGlenn Lagasse 1046*f169c0eaSGlenn Lagasse /* 1047*f169c0eaSGlenn Lagasse * If we succeeded in creating an auto named BE, set its policy 1048*f169c0eaSGlenn Lagasse * type and return the auto generated name to the caller by storing 1049*f169c0eaSGlenn Lagasse * it in the nvlist passed in by the caller. 1050*f169c0eaSGlenn Lagasse */ 1051*f169c0eaSGlenn Lagasse if (autoname) { 1052*f169c0eaSGlenn Lagasse /* Get handle to new BE's root dataset. */ 1053*f169c0eaSGlenn Lagasse if ((zhp = zfs_open(g_zfs, bt.nbe_root_ds, 1054*f169c0eaSGlenn Lagasse ZFS_TYPE_FILESYSTEM)) == NULL) { 1055*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy: failed to " 1056*f169c0eaSGlenn Lagasse "open BE root dataset (%s): %s\n"), bt.nbe_root_ds, 1057*f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 1058*f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 1059*f169c0eaSGlenn Lagasse goto done; 1060*f169c0eaSGlenn Lagasse } 1061*f169c0eaSGlenn Lagasse 1062*f169c0eaSGlenn Lagasse /* 1063*f169c0eaSGlenn Lagasse * Set the policy type property into the new BE's root dataset 1064*f169c0eaSGlenn Lagasse */ 1065*f169c0eaSGlenn Lagasse if (bt.policy == NULL) { 1066*f169c0eaSGlenn Lagasse /* If no policy type provided, use default type */ 1067*f169c0eaSGlenn Lagasse bt.policy = be_default_policy(); 1068*f169c0eaSGlenn Lagasse } 1069*f169c0eaSGlenn Lagasse 1070*f169c0eaSGlenn Lagasse if (zfs_prop_set(zhp, BE_POLICY_PROPERTY, bt.policy) != 0) { 1071*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy: failed to " 1072*f169c0eaSGlenn Lagasse "set BE policy for %s: %s\n"), bt.nbe_name, 1073*f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 1074*f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 1075*f169c0eaSGlenn Lagasse goto done; 1076*f169c0eaSGlenn Lagasse } 1077*f169c0eaSGlenn Lagasse 1078*f169c0eaSGlenn Lagasse /* 1079*f169c0eaSGlenn Lagasse * Return the auto generated name to the caller 1080*f169c0eaSGlenn Lagasse */ 1081*f169c0eaSGlenn Lagasse if (bt.nbe_name) { 1082*f169c0eaSGlenn Lagasse if (nvlist_add_string(be_attrs, BE_ATTR_NEW_BE_NAME, 1083*f169c0eaSGlenn Lagasse bt.nbe_name) != 0) { 1084*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy: failed to " 1085*f169c0eaSGlenn Lagasse "add snap name to be_attrs\n")); 1086*f169c0eaSGlenn Lagasse } 1087*f169c0eaSGlenn Lagasse } 1088*f169c0eaSGlenn Lagasse } 1089*f169c0eaSGlenn Lagasse 1090*f169c0eaSGlenn Lagasse done: 1091*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 1092*f169c0eaSGlenn Lagasse be_free_fs_list(&fld); 1093*f169c0eaSGlenn Lagasse 1094*f169c0eaSGlenn Lagasse if (bt.nbe_zfs_props != NULL) 1095*f169c0eaSGlenn Lagasse nvlist_free(bt.nbe_zfs_props); 1096*f169c0eaSGlenn Lagasse 1097*f169c0eaSGlenn Lagasse free(bt.obe_altroot); 1098*f169c0eaSGlenn Lagasse free(new_mp); 1099*f169c0eaSGlenn Lagasse 1100*f169c0eaSGlenn Lagasse /* 1101*f169c0eaSGlenn Lagasse * If a failure occurred and we already created the datasets for 1102*f169c0eaSGlenn Lagasse * the new boot environment, destroy them. 1103*f169c0eaSGlenn Lagasse */ 1104*f169c0eaSGlenn Lagasse if (ret != BE_SUCCESS && be_created) { 1105*f169c0eaSGlenn Lagasse be_destroy_data_t cdd = { 0 }; 1106*f169c0eaSGlenn Lagasse 1107*f169c0eaSGlenn Lagasse cdd.force_unmount = B_TRUE; 1108*f169c0eaSGlenn Lagasse 1109*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy: " 1110*f169c0eaSGlenn Lagasse "destroying partially created boot environment\n")); 1111*f169c0eaSGlenn Lagasse 1112*f169c0eaSGlenn Lagasse if (getzoneid() == GLOBAL_ZONEID && be_get_uuid(bt.nbe_root_ds, 1113*f169c0eaSGlenn Lagasse &cdd.gz_be_uuid) == 0) 1114*f169c0eaSGlenn Lagasse (void) be_destroy_zones(bt.nbe_name, bt.nbe_root_ds, 1115*f169c0eaSGlenn Lagasse &cdd); 1116*f169c0eaSGlenn Lagasse 1117*f169c0eaSGlenn Lagasse (void) _be_destroy(bt.nbe_root_ds, &cdd); 1118*f169c0eaSGlenn Lagasse } 1119*f169c0eaSGlenn Lagasse 1120*f169c0eaSGlenn Lagasse be_zfs_fini(); 1121*f169c0eaSGlenn Lagasse 1122*f169c0eaSGlenn Lagasse return (ret); 1123*f169c0eaSGlenn Lagasse } 1124*f169c0eaSGlenn Lagasse 1125*f169c0eaSGlenn Lagasse /* ******************************************************************** */ 1126*f169c0eaSGlenn Lagasse /* Semi-Private Functions */ 1127*f169c0eaSGlenn Lagasse /* ******************************************************************** */ 1128*f169c0eaSGlenn Lagasse 1129*f169c0eaSGlenn Lagasse /* 1130*f169c0eaSGlenn Lagasse * Function: be_find_zpool_callback 1131*f169c0eaSGlenn Lagasse * Description: Callback function used to find the pool that a BE lives in. 1132*f169c0eaSGlenn Lagasse * Parameters: 1133*f169c0eaSGlenn Lagasse * zlp - zpool_handle_t pointer for the current pool being 1134*f169c0eaSGlenn Lagasse * looked at. 1135*f169c0eaSGlenn Lagasse * data - be_transaction_data_t pointer providing information 1136*f169c0eaSGlenn Lagasse * about the BE that's being searched for. 1137*f169c0eaSGlenn Lagasse * This function uses the obe_name member of this 1138*f169c0eaSGlenn Lagasse * parameter to use as the BE name to search for. 1139*f169c0eaSGlenn Lagasse * Upon successfully locating the BE, it populates 1140*f169c0eaSGlenn Lagasse * obe_zpool with the pool name that the BE is found in. 1141*f169c0eaSGlenn Lagasse * Returns: 1142*f169c0eaSGlenn Lagasse * 1 - BE exists in this pool. 1143*f169c0eaSGlenn Lagasse * 0 - BE does not exist in this pool. 1144*f169c0eaSGlenn Lagasse * Scope: 1145*f169c0eaSGlenn Lagasse * Semi-private (library wide use only) 1146*f169c0eaSGlenn Lagasse */ 1147*f169c0eaSGlenn Lagasse int 1148*f169c0eaSGlenn Lagasse be_find_zpool_callback(zpool_handle_t *zlp, void *data) 1149*f169c0eaSGlenn Lagasse { 1150*f169c0eaSGlenn Lagasse be_transaction_data_t *bt = data; 1151*f169c0eaSGlenn Lagasse const char *zpool = zpool_get_name(zlp); 1152*f169c0eaSGlenn Lagasse char be_root_ds[MAXPATHLEN]; 1153*f169c0eaSGlenn Lagasse 1154*f169c0eaSGlenn Lagasse /* 1155*f169c0eaSGlenn Lagasse * Generate string for the BE's root dataset 1156*f169c0eaSGlenn Lagasse */ 1157*f169c0eaSGlenn Lagasse be_make_root_ds(zpool, bt->obe_name, be_root_ds, sizeof (be_root_ds)); 1158*f169c0eaSGlenn Lagasse 1159*f169c0eaSGlenn Lagasse /* 1160*f169c0eaSGlenn Lagasse * Check if dataset exists 1161*f169c0eaSGlenn Lagasse */ 1162*f169c0eaSGlenn Lagasse if (zfs_dataset_exists(g_zfs, be_root_ds, ZFS_TYPE_FILESYSTEM)) { 1163*f169c0eaSGlenn Lagasse /* BE's root dataset exists in zpool */ 1164*f169c0eaSGlenn Lagasse bt->obe_zpool = strdup(zpool); 1165*f169c0eaSGlenn Lagasse zpool_close(zlp); 1166*f169c0eaSGlenn Lagasse return (1); 1167*f169c0eaSGlenn Lagasse } 1168*f169c0eaSGlenn Lagasse 1169*f169c0eaSGlenn Lagasse zpool_close(zlp); 1170*f169c0eaSGlenn Lagasse return (0); 1171*f169c0eaSGlenn Lagasse } 1172*f169c0eaSGlenn Lagasse 1173*f169c0eaSGlenn Lagasse /* 1174*f169c0eaSGlenn Lagasse * Function: be_exists_callback 1175*f169c0eaSGlenn Lagasse * Description: Callback function used to find out if a BE exists. 1176*f169c0eaSGlenn Lagasse * Parameters: 1177*f169c0eaSGlenn Lagasse * zlp - zpool_handle_t pointer to the current pool being 1178*f169c0eaSGlenn Lagasse * looked at. 1179*f169c0eaSGlenn Lagasse * data - BE name to look for. 1180*f169c0eaSGlenn Lagasse * Return: 1181*f169c0eaSGlenn Lagasse * 1 - BE exists in this pool. 1182*f169c0eaSGlenn Lagasse * 0 - BE does not exist in this pool. 1183*f169c0eaSGlenn Lagasse * Scope: 1184*f169c0eaSGlenn Lagasse * Semi-private (library wide use only) 1185*f169c0eaSGlenn Lagasse */ 1186*f169c0eaSGlenn Lagasse int 1187*f169c0eaSGlenn Lagasse be_exists_callback(zpool_handle_t *zlp, void *data) 1188*f169c0eaSGlenn Lagasse { 1189*f169c0eaSGlenn Lagasse const char *zpool = zpool_get_name(zlp); 1190*f169c0eaSGlenn Lagasse char *be_name = data; 1191*f169c0eaSGlenn Lagasse char be_root_ds[MAXPATHLEN]; 1192*f169c0eaSGlenn Lagasse 1193*f169c0eaSGlenn Lagasse /* 1194*f169c0eaSGlenn Lagasse * Generate string for the BE's root dataset 1195*f169c0eaSGlenn Lagasse */ 1196*f169c0eaSGlenn Lagasse be_make_root_ds(zpool, be_name, be_root_ds, sizeof (be_root_ds)); 1197*f169c0eaSGlenn Lagasse 1198*f169c0eaSGlenn Lagasse /* 1199*f169c0eaSGlenn Lagasse * Check if dataset exists 1200*f169c0eaSGlenn Lagasse */ 1201*f169c0eaSGlenn Lagasse if (zfs_dataset_exists(g_zfs, be_root_ds, ZFS_TYPE_FILESYSTEM)) { 1202*f169c0eaSGlenn Lagasse /* BE's root dataset exists in zpool */ 1203*f169c0eaSGlenn Lagasse zpool_close(zlp); 1204*f169c0eaSGlenn Lagasse return (1); 1205*f169c0eaSGlenn Lagasse } 1206*f169c0eaSGlenn Lagasse 1207*f169c0eaSGlenn Lagasse zpool_close(zlp); 1208*f169c0eaSGlenn Lagasse return (0); 1209*f169c0eaSGlenn Lagasse } 1210*f169c0eaSGlenn Lagasse 1211*f169c0eaSGlenn Lagasse /* 1212*f169c0eaSGlenn Lagasse * Function: be_set_uuid 1213*f169c0eaSGlenn Lagasse * Description: This function generates a uuid, unparses it into 1214*f169c0eaSGlenn Lagasse * string representation, and sets that string into 1215*f169c0eaSGlenn Lagasse * a zfs user property for a root dataset of a BE. 1216*f169c0eaSGlenn Lagasse * The name of the user property used to store the 1217*f169c0eaSGlenn Lagasse * uuid is org.opensolaris.libbe:uuid 1218*f169c0eaSGlenn Lagasse * 1219*f169c0eaSGlenn Lagasse * Parameters: 1220*f169c0eaSGlenn Lagasse * root_ds - Root dataset of the BE to set a uuid on. 1221*f169c0eaSGlenn Lagasse * Return: 1222*f169c0eaSGlenn Lagasse * be_errno_t - Failure 1223*f169c0eaSGlenn Lagasse * BE_SUCCESS - Success 1224*f169c0eaSGlenn Lagasse * Scope: 1225*f169c0eaSGlenn Lagasse * Semi-private (library wide ues only) 1226*f169c0eaSGlenn Lagasse */ 1227*f169c0eaSGlenn Lagasse int 1228*f169c0eaSGlenn Lagasse be_set_uuid(char *root_ds) 1229*f169c0eaSGlenn Lagasse { 1230*f169c0eaSGlenn Lagasse zfs_handle_t *zhp = NULL; 1231*f169c0eaSGlenn Lagasse uuid_t uu = { 0 }; 1232*f169c0eaSGlenn Lagasse char uu_string[UUID_PRINTABLE_STRING_LENGTH] = { 0 }; 1233*f169c0eaSGlenn Lagasse int ret = BE_SUCCESS; 1234*f169c0eaSGlenn Lagasse 1235*f169c0eaSGlenn Lagasse /* Generate a UUID and unparse it into string form */ 1236*f169c0eaSGlenn Lagasse uuid_generate(uu); 1237*f169c0eaSGlenn Lagasse if (uuid_is_null(uu) != 0) { 1238*f169c0eaSGlenn Lagasse be_print_err(gettext("be_set_uuid: failed to " 1239*f169c0eaSGlenn Lagasse "generate uuid\n")); 1240*f169c0eaSGlenn Lagasse return (BE_ERR_GEN_UUID); 1241*f169c0eaSGlenn Lagasse } 1242*f169c0eaSGlenn Lagasse uuid_unparse(uu, uu_string); 1243*f169c0eaSGlenn Lagasse 1244*f169c0eaSGlenn Lagasse /* Get handle to the BE's root dataset. */ 1245*f169c0eaSGlenn Lagasse if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) == NULL) { 1246*f169c0eaSGlenn Lagasse be_print_err(gettext("be_set_uuid: failed to " 1247*f169c0eaSGlenn Lagasse "open BE root dataset (%s): %s\n"), root_ds, 1248*f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 1249*f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs)); 1250*f169c0eaSGlenn Lagasse } 1251*f169c0eaSGlenn Lagasse 1252*f169c0eaSGlenn Lagasse /* Set uuid property for the BE */ 1253*f169c0eaSGlenn Lagasse if (zfs_prop_set(zhp, BE_UUID_PROPERTY, uu_string) != 0) { 1254*f169c0eaSGlenn Lagasse be_print_err(gettext("be_set_uuid: failed to " 1255*f169c0eaSGlenn Lagasse "set uuid property for BE: %s\n"), 1256*f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 1257*f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 1258*f169c0eaSGlenn Lagasse } 1259*f169c0eaSGlenn Lagasse 1260*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 1261*f169c0eaSGlenn Lagasse 1262*f169c0eaSGlenn Lagasse return (ret); 1263*f169c0eaSGlenn Lagasse } 1264*f169c0eaSGlenn Lagasse 1265*f169c0eaSGlenn Lagasse /* 1266*f169c0eaSGlenn Lagasse * Function: be_get_uuid 1267*f169c0eaSGlenn Lagasse * Description: This function gets the uuid string from a BE root 1268*f169c0eaSGlenn Lagasse * dataset, parses it into internal format, and returns 1269*f169c0eaSGlenn Lagasse * it the caller via a reference pointer passed in. 1270*f169c0eaSGlenn Lagasse * 1271*f169c0eaSGlenn Lagasse * Parameters: 1272*f169c0eaSGlenn Lagasse * rootds - Root dataset of the BE to get the uuid from. 1273*f169c0eaSGlenn Lagasse * uu - reference pointer to a uuid_t to return uuid in. 1274*f169c0eaSGlenn Lagasse * Return: 1275*f169c0eaSGlenn Lagasse * be_errno_t - Failure 1276*f169c0eaSGlenn Lagasse * BE_SUCCESS - Success 1277*f169c0eaSGlenn Lagasse * Scope: 1278*f169c0eaSGlenn Lagasse * Semi-private (library wide use only) 1279*f169c0eaSGlenn Lagasse */ 1280*f169c0eaSGlenn Lagasse int 1281*f169c0eaSGlenn Lagasse be_get_uuid(const char *root_ds, uuid_t *uu) 1282*f169c0eaSGlenn Lagasse { 1283*f169c0eaSGlenn Lagasse zfs_handle_t *zhp = NULL; 1284*f169c0eaSGlenn Lagasse nvlist_t *userprops = NULL; 1285*f169c0eaSGlenn Lagasse nvlist_t *propname = NULL; 1286*f169c0eaSGlenn Lagasse char *uu_string = NULL; 1287*f169c0eaSGlenn Lagasse int ret = BE_SUCCESS; 1288*f169c0eaSGlenn Lagasse 1289*f169c0eaSGlenn Lagasse /* Get handle to the BE's root dataset. */ 1290*f169c0eaSGlenn Lagasse if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) == NULL) { 1291*f169c0eaSGlenn Lagasse be_print_err(gettext("be_get_uuid: failed to " 1292*f169c0eaSGlenn Lagasse "open BE root dataset (%s): %s\n"), root_ds, 1293*f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 1294*f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs)); 1295*f169c0eaSGlenn Lagasse } 1296*f169c0eaSGlenn Lagasse 1297*f169c0eaSGlenn Lagasse /* Get user properties for BE's root dataset */ 1298*f169c0eaSGlenn Lagasse if ((userprops = zfs_get_user_props(zhp)) == NULL) { 1299*f169c0eaSGlenn Lagasse be_print_err(gettext("be_get_uuid: failed to " 1300*f169c0eaSGlenn Lagasse "get user properties for BE root dataset (%s): %s\n"), 1301*f169c0eaSGlenn Lagasse root_ds, libzfs_error_description(g_zfs)); 1302*f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 1303*f169c0eaSGlenn Lagasse goto done; 1304*f169c0eaSGlenn Lagasse } 1305*f169c0eaSGlenn Lagasse 1306*f169c0eaSGlenn Lagasse /* Get UUID string from BE's root dataset user properties */ 1307*f169c0eaSGlenn Lagasse if (nvlist_lookup_nvlist(userprops, BE_UUID_PROPERTY, &propname) != 0 || 1308*f169c0eaSGlenn Lagasse nvlist_lookup_string(propname, ZPROP_VALUE, &uu_string) != 0) { 1309*f169c0eaSGlenn Lagasse /* 1310*f169c0eaSGlenn Lagasse * This probably just means that the BE is simply too old 1311*f169c0eaSGlenn Lagasse * to have a uuid or that we haven't created a uuid for 1312*f169c0eaSGlenn Lagasse * this BE yet. 1313*f169c0eaSGlenn Lagasse */ 1314*f169c0eaSGlenn Lagasse be_print_err(gettext("be_get_uuid: failed to " 1315*f169c0eaSGlenn Lagasse "get uuid property from BE root dataset user " 1316*f169c0eaSGlenn Lagasse "properties.\n")); 1317*f169c0eaSGlenn Lagasse ret = BE_ERR_NO_UUID; 1318*f169c0eaSGlenn Lagasse goto done; 1319*f169c0eaSGlenn Lagasse } 1320*f169c0eaSGlenn Lagasse /* Parse uuid string into internal format */ 1321*f169c0eaSGlenn Lagasse if (uuid_parse(uu_string, *uu) != 0 || uuid_is_null(*uu)) { 1322*f169c0eaSGlenn Lagasse be_print_err(gettext("be_get_uuid: failed to " 1323*f169c0eaSGlenn Lagasse "parse uuid\n")); 1324*f169c0eaSGlenn Lagasse ret = BE_ERR_PARSE_UUID; 1325*f169c0eaSGlenn Lagasse goto done; 1326*f169c0eaSGlenn Lagasse } 1327*f169c0eaSGlenn Lagasse 1328*f169c0eaSGlenn Lagasse done: 1329*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 1330*f169c0eaSGlenn Lagasse return (ret); 1331*f169c0eaSGlenn Lagasse } 1332*f169c0eaSGlenn Lagasse 1333*f169c0eaSGlenn Lagasse /* ******************************************************************** */ 1334*f169c0eaSGlenn Lagasse /* Private Functions */ 1335*f169c0eaSGlenn Lagasse /* ******************************************************************** */ 1336*f169c0eaSGlenn Lagasse 1337*f169c0eaSGlenn Lagasse /* 1338*f169c0eaSGlenn Lagasse * Function: _be_destroy 1339*f169c0eaSGlenn Lagasse * Description: Destroy a BE and all of its children datasets and snapshots. 1340*f169c0eaSGlenn Lagasse * This function is called for both global BEs and non-global BEs. 1341*f169c0eaSGlenn Lagasse * The root dataset of either the global BE or non-global BE to be 1342*f169c0eaSGlenn Lagasse * destroyed is passed in. 1343*f169c0eaSGlenn Lagasse * Parameters: 1344*f169c0eaSGlenn Lagasse * root_ds - pointer to the name of the root dataset of the 1345*f169c0eaSGlenn Lagasse * BE to destroy. 1346*f169c0eaSGlenn Lagasse * dd - pointer to a be_destroy_data_t structure. 1347*f169c0eaSGlenn Lagasse * 1348*f169c0eaSGlenn Lagasse * Return: 1349*f169c0eaSGlenn Lagasse * BE_SUCCESS - Success 1350*f169c0eaSGlenn Lagasse * be_errno_t - Failure 1351*f169c0eaSGlenn Lagasse * Scope: 1352*f169c0eaSGlenn Lagasse * Private 1353*f169c0eaSGlenn Lagasse */ 1354*f169c0eaSGlenn Lagasse static int 1355*f169c0eaSGlenn Lagasse _be_destroy(const char *root_ds, be_destroy_data_t *dd) 1356*f169c0eaSGlenn Lagasse { 1357*f169c0eaSGlenn Lagasse zfs_handle_t *zhp = NULL; 1358*f169c0eaSGlenn Lagasse char origin[MAXPATHLEN]; 1359*f169c0eaSGlenn Lagasse char parent[MAXPATHLEN]; 1360*f169c0eaSGlenn Lagasse char *snap = NULL; 1361*f169c0eaSGlenn Lagasse boolean_t has_origin = B_FALSE; 1362*f169c0eaSGlenn Lagasse int ret = BE_SUCCESS; 1363*f169c0eaSGlenn Lagasse 1364*f169c0eaSGlenn Lagasse /* Get handle to BE's root dataset */ 1365*f169c0eaSGlenn Lagasse if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) == 1366*f169c0eaSGlenn Lagasse NULL) { 1367*f169c0eaSGlenn Lagasse be_print_err(gettext("be_destroy: failed to " 1368*f169c0eaSGlenn Lagasse "open BE root dataset (%s): %s\n"), root_ds, 1369*f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 1370*f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs)); 1371*f169c0eaSGlenn Lagasse } 1372*f169c0eaSGlenn Lagasse 1373*f169c0eaSGlenn Lagasse /* 1374*f169c0eaSGlenn Lagasse * Demote this BE in case it has dependent clones. This call 1375*f169c0eaSGlenn Lagasse * will end up closing the zfs handle passed in whether it 1376*f169c0eaSGlenn Lagasse * succeeds or fails. 1377*f169c0eaSGlenn Lagasse */ 1378*f169c0eaSGlenn Lagasse if (be_demote_callback(zhp, NULL) != 0) { 1379*f169c0eaSGlenn Lagasse be_print_err(gettext("be_destroy: " 1380*f169c0eaSGlenn Lagasse "failed to demote BE %s\n"), root_ds); 1381*f169c0eaSGlenn Lagasse return (BE_ERR_DEMOTE); 1382*f169c0eaSGlenn Lagasse } 1383*f169c0eaSGlenn Lagasse 1384*f169c0eaSGlenn Lagasse /* Get handle to BE's root dataset */ 1385*f169c0eaSGlenn Lagasse if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) == 1386*f169c0eaSGlenn Lagasse NULL) { 1387*f169c0eaSGlenn Lagasse be_print_err(gettext("be_destroy: failed to " 1388*f169c0eaSGlenn Lagasse "open BE root dataset (%s): %s\n"), root_ds, 1389*f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 1390*f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs)); 1391*f169c0eaSGlenn Lagasse } 1392*f169c0eaSGlenn Lagasse 1393*f169c0eaSGlenn Lagasse /* 1394*f169c0eaSGlenn Lagasse * Get the origin of this BE's root dataset. This will be used 1395*f169c0eaSGlenn Lagasse * later to destroy the snapshots originally used to create this BE. 1396*f169c0eaSGlenn Lagasse */ 1397*f169c0eaSGlenn Lagasse if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin, sizeof (origin), NULL, 1398*f169c0eaSGlenn Lagasse NULL, 0, B_FALSE) == 0) { 1399*f169c0eaSGlenn Lagasse (void) strlcpy(parent, origin, sizeof (parent)); 1400*f169c0eaSGlenn Lagasse if (be_get_snap(parent, &snap) != BE_SUCCESS) { 1401*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 1402*f169c0eaSGlenn Lagasse be_print_err(gettext("be_destroy: failed to " 1403*f169c0eaSGlenn Lagasse "get snapshot name from origin %s\n"), origin); 1404*f169c0eaSGlenn Lagasse return (BE_ERR_INVAL); 1405*f169c0eaSGlenn Lagasse } 1406*f169c0eaSGlenn Lagasse has_origin = B_TRUE; 1407*f169c0eaSGlenn Lagasse } 1408*f169c0eaSGlenn Lagasse 1409*f169c0eaSGlenn Lagasse /* 1410*f169c0eaSGlenn Lagasse * Destroy the BE's root and its hierarchical children. This call 1411*f169c0eaSGlenn Lagasse * will end up closing the zfs handle passed in whether it succeeds 1412*f169c0eaSGlenn Lagasse * or fails. 1413*f169c0eaSGlenn Lagasse */ 1414*f169c0eaSGlenn Lagasse if (be_destroy_callback(zhp, dd) != 0) { 1415*f169c0eaSGlenn Lagasse be_print_err(gettext("be_destroy: failed to " 1416*f169c0eaSGlenn Lagasse "destroy BE %s\n"), root_ds); 1417*f169c0eaSGlenn Lagasse return (BE_ERR_DESTROY); 1418*f169c0eaSGlenn Lagasse } 1419*f169c0eaSGlenn Lagasse 1420*f169c0eaSGlenn Lagasse /* If BE has an origin */ 1421*f169c0eaSGlenn Lagasse if (has_origin) { 1422*f169c0eaSGlenn Lagasse 1423*f169c0eaSGlenn Lagasse /* 1424*f169c0eaSGlenn Lagasse * If origin snapshot doesn't have any other 1425*f169c0eaSGlenn Lagasse * dependents, delete the origin. 1426*f169c0eaSGlenn Lagasse */ 1427*f169c0eaSGlenn Lagasse if ((zhp = zfs_open(g_zfs, origin, ZFS_TYPE_SNAPSHOT)) == 1428*f169c0eaSGlenn Lagasse NULL) { 1429*f169c0eaSGlenn Lagasse be_print_err(gettext("be_destroy: failed to " 1430*f169c0eaSGlenn Lagasse "open BE's origin (%s): %s\n"), origin, 1431*f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 1432*f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 1433*f169c0eaSGlenn Lagasse return (ret); 1434*f169c0eaSGlenn Lagasse } 1435*f169c0eaSGlenn Lagasse 1436*f169c0eaSGlenn Lagasse /* If origin has dependents, don't delete it. */ 1437*f169c0eaSGlenn Lagasse if (zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES) != 0) { 1438*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 1439*f169c0eaSGlenn Lagasse return (ret); 1440*f169c0eaSGlenn Lagasse } 1441*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 1442*f169c0eaSGlenn Lagasse 1443*f169c0eaSGlenn Lagasse /* Get handle to BE's parent's root dataset */ 1444*f169c0eaSGlenn Lagasse if ((zhp = zfs_open(g_zfs, parent, ZFS_TYPE_FILESYSTEM)) == 1445*f169c0eaSGlenn Lagasse NULL) { 1446*f169c0eaSGlenn Lagasse be_print_err(gettext("be_destroy: failed to " 1447*f169c0eaSGlenn Lagasse "open BE's parent root dataset (%s): %s\n"), parent, 1448*f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 1449*f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 1450*f169c0eaSGlenn Lagasse return (ret); 1451*f169c0eaSGlenn Lagasse } 1452*f169c0eaSGlenn Lagasse 1453*f169c0eaSGlenn Lagasse /* Destroy the snapshot origin used to create this BE. */ 1454*f169c0eaSGlenn Lagasse /* 1455*f169c0eaSGlenn Lagasse * The boolean set to B_FALSE and passed to zfs_destroy_snaps() 1456*f169c0eaSGlenn Lagasse * tells zfs to process and destroy the snapshots now. 1457*f169c0eaSGlenn Lagasse * Otherwise the call will potentially return where the 1458*f169c0eaSGlenn Lagasse * snapshot isn't actually destroyed yet, and ZFS is waiting 1459*f169c0eaSGlenn Lagasse * until all the references to the snapshot have been 1460*f169c0eaSGlenn Lagasse * released before actually destroying the snapshot. 1461*f169c0eaSGlenn Lagasse */ 1462*f169c0eaSGlenn Lagasse if (zfs_destroy_snaps(zhp, snap, B_FALSE) != 0) { 1463*f169c0eaSGlenn Lagasse be_print_err(gettext("be_destroy: failed to " 1464*f169c0eaSGlenn Lagasse "destroy original snapshots used to create " 1465*f169c0eaSGlenn Lagasse "BE: %s\n"), libzfs_error_description(g_zfs)); 1466*f169c0eaSGlenn Lagasse 1467*f169c0eaSGlenn Lagasse /* 1468*f169c0eaSGlenn Lagasse * If a failure happened because a clone exists, 1469*f169c0eaSGlenn Lagasse * don't return a failure to the user. Above, we're 1470*f169c0eaSGlenn Lagasse * only checking that the root dataset's origin 1471*f169c0eaSGlenn Lagasse * snapshot doesn't have dependent clones, but its 1472*f169c0eaSGlenn Lagasse * possible that a subordinate dataset origin snapshot 1473*f169c0eaSGlenn Lagasse * has a clone. We really need to check for that 1474*f169c0eaSGlenn Lagasse * before trying to destroy the origin snapshot. 1475*f169c0eaSGlenn Lagasse */ 1476*f169c0eaSGlenn Lagasse if (libzfs_errno(g_zfs) != EZFS_EXISTS) { 1477*f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 1478*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 1479*f169c0eaSGlenn Lagasse return (ret); 1480*f169c0eaSGlenn Lagasse } 1481*f169c0eaSGlenn Lagasse } 1482*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 1483*f169c0eaSGlenn Lagasse } 1484*f169c0eaSGlenn Lagasse 1485*f169c0eaSGlenn Lagasse return (ret); 1486*f169c0eaSGlenn Lagasse } 1487*f169c0eaSGlenn Lagasse 1488*f169c0eaSGlenn Lagasse /* 1489*f169c0eaSGlenn Lagasse * Function: be_destroy_zones 1490*f169c0eaSGlenn Lagasse * Description: Find valid zone's and call be_destroy_zone_roots to destroy its 1491*f169c0eaSGlenn Lagasse * corresponding dataset and all of its children datasets 1492*f169c0eaSGlenn Lagasse * and snapshots. 1493*f169c0eaSGlenn Lagasse * Parameters: 1494*f169c0eaSGlenn Lagasse * be_name - name of global boot environment being destroyed 1495*f169c0eaSGlenn Lagasse * be_root_ds - root dataset of global boot environment being 1496*f169c0eaSGlenn Lagasse * destroyed. 1497*f169c0eaSGlenn Lagasse * dd - be_destroy_data_t pointer 1498*f169c0eaSGlenn Lagasse * Return: 1499*f169c0eaSGlenn Lagasse * BE_SUCCESS - Success 1500*f169c0eaSGlenn Lagasse * be_errno_t - Failure 1501*f169c0eaSGlenn Lagasse * Scope: 1502*f169c0eaSGlenn Lagasse * Private 1503*f169c0eaSGlenn Lagasse * 1504*f169c0eaSGlenn Lagasse * NOTES - Requires that the BE being deleted has no dependent BEs. If it 1505*f169c0eaSGlenn Lagasse * does, the destroy will fail. 1506*f169c0eaSGlenn Lagasse */ 1507*f169c0eaSGlenn Lagasse static int 1508*f169c0eaSGlenn Lagasse be_destroy_zones(char *be_name, char *be_root_ds, be_destroy_data_t *dd) 1509*f169c0eaSGlenn Lagasse { 1510*f169c0eaSGlenn Lagasse int i; 1511*f169c0eaSGlenn Lagasse int ret = BE_SUCCESS; 1512*f169c0eaSGlenn Lagasse int force_umnt = BE_UNMOUNT_FLAG_NULL; 1513*f169c0eaSGlenn Lagasse char *zonepath = NULL; 1514*f169c0eaSGlenn Lagasse char *zonename = NULL; 1515*f169c0eaSGlenn Lagasse char *zonepath_ds = NULL; 1516*f169c0eaSGlenn Lagasse char *mp = NULL; 1517*f169c0eaSGlenn Lagasse zoneList_t zlist = NULL; 1518*f169c0eaSGlenn Lagasse zoneBrandList_t *brands = NULL; 1519*f169c0eaSGlenn Lagasse zfs_handle_t *zhp = NULL; 1520*f169c0eaSGlenn Lagasse 1521*f169c0eaSGlenn Lagasse /* If zones are not implemented, then get out. */ 1522*f169c0eaSGlenn Lagasse if (!z_zones_are_implemented()) { 1523*f169c0eaSGlenn Lagasse return (BE_SUCCESS); 1524*f169c0eaSGlenn Lagasse } 1525*f169c0eaSGlenn Lagasse 1526*f169c0eaSGlenn Lagasse /* Get list of supported brands */ 1527*f169c0eaSGlenn Lagasse if ((brands = be_get_supported_brandlist()) == NULL) { 1528*f169c0eaSGlenn Lagasse be_print_err(gettext("be_destroy_zones: " 1529*f169c0eaSGlenn Lagasse "no supported brands\n")); 1530*f169c0eaSGlenn Lagasse return (BE_SUCCESS); 1531*f169c0eaSGlenn Lagasse } 1532*f169c0eaSGlenn Lagasse 1533*f169c0eaSGlenn Lagasse /* Get handle to BE's root dataset */ 1534*f169c0eaSGlenn Lagasse if ((zhp = zfs_open(g_zfs, be_root_ds, ZFS_TYPE_FILESYSTEM)) == 1535*f169c0eaSGlenn Lagasse NULL) { 1536*f169c0eaSGlenn Lagasse be_print_err(gettext("be_destroy_zones: failed to " 1537*f169c0eaSGlenn Lagasse "open BE root dataset (%s): %s\n"), be_root_ds, 1538*f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 1539*f169c0eaSGlenn Lagasse z_free_brand_list(brands); 1540*f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs)); 1541*f169c0eaSGlenn Lagasse } 1542*f169c0eaSGlenn Lagasse 1543*f169c0eaSGlenn Lagasse /* 1544*f169c0eaSGlenn Lagasse * If the global BE is not mounted, we must mount it here to 1545*f169c0eaSGlenn Lagasse * gather data about the non-global zones in it. 1546*f169c0eaSGlenn Lagasse */ 1547*f169c0eaSGlenn Lagasse if (!zfs_is_mounted(zhp, &mp)) { 1548*f169c0eaSGlenn Lagasse if ((ret = _be_mount(be_name, &mp, 1549*f169c0eaSGlenn Lagasse BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) { 1550*f169c0eaSGlenn Lagasse be_print_err(gettext("be_destroy_zones: failed to " 1551*f169c0eaSGlenn Lagasse "mount the BE (%s) for zones processing.\n"), 1552*f169c0eaSGlenn Lagasse be_name); 1553*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 1554*f169c0eaSGlenn Lagasse z_free_brand_list(brands); 1555*f169c0eaSGlenn Lagasse return (ret); 1556*f169c0eaSGlenn Lagasse } 1557*f169c0eaSGlenn Lagasse } 1558*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 1559*f169c0eaSGlenn Lagasse 1560*f169c0eaSGlenn Lagasse z_set_zone_root(mp); 1561*f169c0eaSGlenn Lagasse free(mp); 1562*f169c0eaSGlenn Lagasse 1563*f169c0eaSGlenn Lagasse /* Get list of supported zones. */ 1564*f169c0eaSGlenn Lagasse if ((zlist = z_get_nonglobal_zone_list_by_brand(brands)) == NULL) { 1565*f169c0eaSGlenn Lagasse z_free_brand_list(brands); 1566*f169c0eaSGlenn Lagasse return (BE_SUCCESS); 1567*f169c0eaSGlenn Lagasse } 1568*f169c0eaSGlenn Lagasse 1569*f169c0eaSGlenn Lagasse /* Unmount the BE before destroying the zones in it. */ 1570*f169c0eaSGlenn Lagasse if (dd->force_unmount) 1571*f169c0eaSGlenn Lagasse force_umnt = BE_UNMOUNT_FLAG_FORCE; 1572*f169c0eaSGlenn Lagasse if ((ret = _be_unmount(be_name, force_umnt)) != BE_SUCCESS) { 1573*f169c0eaSGlenn Lagasse be_print_err(gettext("be_destroy_zones: failed to " 1574*f169c0eaSGlenn Lagasse "unmount the BE (%s)\n"), be_name); 1575*f169c0eaSGlenn Lagasse goto done; 1576*f169c0eaSGlenn Lagasse } 1577*f169c0eaSGlenn Lagasse 1578*f169c0eaSGlenn Lagasse /* Iterate through the zones and destroy them. */ 1579*f169c0eaSGlenn Lagasse for (i = 0; (zonename = z_zlist_get_zonename(zlist, i)) != NULL; i++) { 1580*f169c0eaSGlenn Lagasse 1581*f169c0eaSGlenn Lagasse /* Skip zones that aren't at least installed */ 1582*f169c0eaSGlenn Lagasse if (z_zlist_get_current_state(zlist, i) < ZONE_STATE_INSTALLED) 1583*f169c0eaSGlenn Lagasse continue; 1584*f169c0eaSGlenn Lagasse 1585*f169c0eaSGlenn Lagasse zonepath = z_zlist_get_zonepath(zlist, i); 1586*f169c0eaSGlenn Lagasse 1587*f169c0eaSGlenn Lagasse /* 1588*f169c0eaSGlenn Lagasse * Get the dataset of this zonepath. If its not 1589*f169c0eaSGlenn Lagasse * a dataset, skip it. 1590*f169c0eaSGlenn Lagasse */ 1591*f169c0eaSGlenn Lagasse if ((zonepath_ds = be_get_ds_from_dir(zonepath)) == NULL) 1592*f169c0eaSGlenn Lagasse continue; 1593*f169c0eaSGlenn Lagasse 1594*f169c0eaSGlenn Lagasse /* 1595*f169c0eaSGlenn Lagasse * Check if this zone is supported based on the 1596*f169c0eaSGlenn Lagasse * dataset of its zonepath. 1597*f169c0eaSGlenn Lagasse */ 1598*f169c0eaSGlenn Lagasse if (!be_zone_supported(zonepath_ds)) { 1599*f169c0eaSGlenn Lagasse free(zonepath_ds); 1600*f169c0eaSGlenn Lagasse continue; 1601*f169c0eaSGlenn Lagasse } 1602*f169c0eaSGlenn Lagasse 1603*f169c0eaSGlenn Lagasse /* Find the zone BE root datasets for this zone. */ 1604*f169c0eaSGlenn Lagasse if ((ret = be_destroy_zone_roots(zonepath_ds, dd)) 1605*f169c0eaSGlenn Lagasse != BE_SUCCESS) { 1606*f169c0eaSGlenn Lagasse be_print_err(gettext("be_destroy_zones: failed to " 1607*f169c0eaSGlenn Lagasse "find and destroy zone roots for zone %s\n"), 1608*f169c0eaSGlenn Lagasse zonename); 1609*f169c0eaSGlenn Lagasse free(zonepath_ds); 1610*f169c0eaSGlenn Lagasse goto done; 1611*f169c0eaSGlenn Lagasse } 1612*f169c0eaSGlenn Lagasse free(zonepath_ds); 1613*f169c0eaSGlenn Lagasse } 1614*f169c0eaSGlenn Lagasse 1615*f169c0eaSGlenn Lagasse done: 1616*f169c0eaSGlenn Lagasse z_free_brand_list(brands); 1617*f169c0eaSGlenn Lagasse z_free_zone_list(zlist); 1618*f169c0eaSGlenn Lagasse 1619*f169c0eaSGlenn Lagasse return (ret); 1620*f169c0eaSGlenn Lagasse } 1621*f169c0eaSGlenn Lagasse 1622*f169c0eaSGlenn Lagasse /* 1623*f169c0eaSGlenn Lagasse * Function: be_destroy_zone_roots 1624*f169c0eaSGlenn Lagasse * Description: This function will open the zone's root container dataset 1625*f169c0eaSGlenn Lagasse * and iterate the datasets within, looking for roots that 1626*f169c0eaSGlenn Lagasse * belong to the given global BE and destroying them. 1627*f169c0eaSGlenn Lagasse * If no other zone roots remain in the zone's root container 1628*f169c0eaSGlenn Lagasse * dataset, the function will destroy it and the zone's 1629*f169c0eaSGlenn Lagasse * zonepath dataset as well. 1630*f169c0eaSGlenn Lagasse * Parameters: 1631*f169c0eaSGlenn Lagasse * zonepath_ds - pointer to zone's zonepath dataset. 1632*f169c0eaSGlenn Lagasse * dd - pointer to a linked destroy data. 1633*f169c0eaSGlenn Lagasse * Returns: 1634*f169c0eaSGlenn Lagasse * BE_SUCCESS - Success 1635*f169c0eaSGlenn Lagasse * be_errno_t - Failure 1636*f169c0eaSGlenn Lagasse * Scope: 1637*f169c0eaSGlenn Lagasse * Private 1638*f169c0eaSGlenn Lagasse */ 1639*f169c0eaSGlenn Lagasse static int 1640*f169c0eaSGlenn Lagasse be_destroy_zone_roots(char *zonepath_ds, be_destroy_data_t *dd) 1641*f169c0eaSGlenn Lagasse { 1642*f169c0eaSGlenn Lagasse zfs_handle_t *zhp; 1643*f169c0eaSGlenn Lagasse char zone_container_ds[MAXPATHLEN]; 1644*f169c0eaSGlenn Lagasse int ret = BE_SUCCESS; 1645*f169c0eaSGlenn Lagasse 1646*f169c0eaSGlenn Lagasse /* Generate string for the root container dataset for this zone. */ 1647*f169c0eaSGlenn Lagasse be_make_container_ds(zonepath_ds, zone_container_ds, 1648*f169c0eaSGlenn Lagasse sizeof (zone_container_ds)); 1649*f169c0eaSGlenn Lagasse 1650*f169c0eaSGlenn Lagasse /* Get handle to this zone's root container dataset. */ 1651*f169c0eaSGlenn Lagasse if ((zhp = zfs_open(g_zfs, zone_container_ds, ZFS_TYPE_FILESYSTEM)) 1652*f169c0eaSGlenn Lagasse == NULL) { 1653*f169c0eaSGlenn Lagasse be_print_err(gettext("be_destroy_zone_roots: failed to " 1654*f169c0eaSGlenn Lagasse "open zone root container dataset (%s): %s\n"), 1655*f169c0eaSGlenn Lagasse zone_container_ds, libzfs_error_description(g_zfs)); 1656*f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs)); 1657*f169c0eaSGlenn Lagasse } 1658*f169c0eaSGlenn Lagasse 1659*f169c0eaSGlenn Lagasse /* 1660*f169c0eaSGlenn Lagasse * Iterate through all of this zone's BEs, destroying the ones 1661*f169c0eaSGlenn Lagasse * that belong to the parent global BE. 1662*f169c0eaSGlenn Lagasse */ 1663*f169c0eaSGlenn Lagasse if ((ret = zfs_iter_filesystems(zhp, be_destroy_zone_roots_callback, 1664*f169c0eaSGlenn Lagasse dd)) != 0) { 1665*f169c0eaSGlenn Lagasse be_print_err(gettext("be_destroy_zone_roots: failed to " 1666*f169c0eaSGlenn Lagasse "destroy zone roots under zonepath dataset %s: %s\n"), 1667*f169c0eaSGlenn Lagasse zonepath_ds, libzfs_error_description(g_zfs)); 1668*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 1669*f169c0eaSGlenn Lagasse return (ret); 1670*f169c0eaSGlenn Lagasse } 1671*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 1672*f169c0eaSGlenn Lagasse 1673*f169c0eaSGlenn Lagasse /* Get handle to this zone's root container dataset. */ 1674*f169c0eaSGlenn Lagasse if ((zhp = zfs_open(g_zfs, zone_container_ds, ZFS_TYPE_FILESYSTEM)) 1675*f169c0eaSGlenn Lagasse == NULL) { 1676*f169c0eaSGlenn Lagasse be_print_err(gettext("be_destroy_zone_roots: failed to " 1677*f169c0eaSGlenn Lagasse "open zone root container dataset (%s): %s\n"), 1678*f169c0eaSGlenn Lagasse zone_container_ds, libzfs_error_description(g_zfs)); 1679*f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs)); 1680*f169c0eaSGlenn Lagasse } 1681*f169c0eaSGlenn Lagasse 1682*f169c0eaSGlenn Lagasse /* 1683*f169c0eaSGlenn Lagasse * If there are no more zone roots in this zone's root container, 1684*f169c0eaSGlenn Lagasse * dataset, destroy it and the zonepath dataset as well. 1685*f169c0eaSGlenn Lagasse */ 1686*f169c0eaSGlenn Lagasse if (zfs_iter_filesystems(zhp, be_zone_root_exists_callback, NULL) 1687*f169c0eaSGlenn Lagasse == 0) { 1688*f169c0eaSGlenn Lagasse /* Destroy the zone root container dataset */ 1689*f169c0eaSGlenn Lagasse if (zfs_unmount(zhp, NULL, MS_FORCE) != 0 || 1690*f169c0eaSGlenn Lagasse zfs_destroy(zhp, B_FALSE) != 0) { 1691*f169c0eaSGlenn Lagasse be_print_err(gettext("be_destroy_zone_roots: failed to " 1692*f169c0eaSGlenn Lagasse "destroy zone root container dataset (%s): %s\n"), 1693*f169c0eaSGlenn Lagasse zone_container_ds, libzfs_error_description(g_zfs)); 1694*f169c0eaSGlenn Lagasse goto done; 1695*f169c0eaSGlenn Lagasse } 1696*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 1697*f169c0eaSGlenn Lagasse 1698*f169c0eaSGlenn Lagasse /* Get handle to zonepath dataset */ 1699*f169c0eaSGlenn Lagasse if ((zhp = zfs_open(g_zfs, zonepath_ds, ZFS_TYPE_FILESYSTEM)) 1700*f169c0eaSGlenn Lagasse == NULL) { 1701*f169c0eaSGlenn Lagasse be_print_err(gettext("be_destroy_zone_roots: failed to " 1702*f169c0eaSGlenn Lagasse "open zonepath dataset (%s): %s\n"), 1703*f169c0eaSGlenn Lagasse zonepath_ds, libzfs_error_description(g_zfs)); 1704*f169c0eaSGlenn Lagasse goto done; 1705*f169c0eaSGlenn Lagasse } 1706*f169c0eaSGlenn Lagasse 1707*f169c0eaSGlenn Lagasse /* Destroy zonepath dataset */ 1708*f169c0eaSGlenn Lagasse if (zfs_unmount(zhp, NULL, MS_FORCE) != 0 || 1709*f169c0eaSGlenn Lagasse zfs_destroy(zhp, B_FALSE) != 0) { 1710*f169c0eaSGlenn Lagasse be_print_err(gettext("be_destroy_zone_roots: " 1711*f169c0eaSGlenn Lagasse "failed to destroy zonepath dataest %s: %s\n"), 1712*f169c0eaSGlenn Lagasse zonepath_ds, libzfs_error_description(g_zfs)); 1713*f169c0eaSGlenn Lagasse goto done; 1714*f169c0eaSGlenn Lagasse } 1715*f169c0eaSGlenn Lagasse } 1716*f169c0eaSGlenn Lagasse 1717*f169c0eaSGlenn Lagasse done: 1718*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 1719*f169c0eaSGlenn Lagasse return (ret); 1720*f169c0eaSGlenn Lagasse } 1721*f169c0eaSGlenn Lagasse 1722*f169c0eaSGlenn Lagasse /* 1723*f169c0eaSGlenn Lagasse * Function: be_destroy_zone_roots_callback 1724*f169c0eaSGlenn Lagasse * Description: This function is used as a callback to iterate over all of 1725*f169c0eaSGlenn Lagasse * a zone's root datasets, finding the one's that 1726*f169c0eaSGlenn Lagasse * correspond to the current BE. The name's 1727*f169c0eaSGlenn Lagasse * of the zone root datasets are then destroyed by _be_destroy(). 1728*f169c0eaSGlenn Lagasse * Parameters: 1729*f169c0eaSGlenn Lagasse * zhp - zfs_handle_t pointer to current dataset being processed 1730*f169c0eaSGlenn Lagasse * data - be_destroy_data_t pointer 1731*f169c0eaSGlenn Lagasse * Returns: 1732*f169c0eaSGlenn Lagasse * 0 - Success 1733*f169c0eaSGlenn Lagasse * be_errno_t - Failure 1734*f169c0eaSGlenn Lagasse * Scope: 1735*f169c0eaSGlenn Lagasse * Private 1736*f169c0eaSGlenn Lagasse */ 1737*f169c0eaSGlenn Lagasse static int 1738*f169c0eaSGlenn Lagasse be_destroy_zone_roots_callback(zfs_handle_t *zhp, void *data) 1739*f169c0eaSGlenn Lagasse { 1740*f169c0eaSGlenn Lagasse be_destroy_data_t *dd = data; 1741*f169c0eaSGlenn Lagasse uuid_t parent_uuid = { 0 }; 1742*f169c0eaSGlenn Lagasse int ret = 0; 1743*f169c0eaSGlenn Lagasse 1744*f169c0eaSGlenn Lagasse if (be_zone_get_parent_uuid(zfs_get_name(zhp), &parent_uuid) 1745*f169c0eaSGlenn Lagasse != BE_SUCCESS) { 1746*f169c0eaSGlenn Lagasse be_print_err(gettext("be_destroy_zone_roots_callback: " 1747*f169c0eaSGlenn Lagasse "could not get parentuuid for zone root dataset %s\n"), 1748*f169c0eaSGlenn Lagasse zfs_get_name(zhp)); 1749*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 1750*f169c0eaSGlenn Lagasse return (0); 1751*f169c0eaSGlenn Lagasse } 1752*f169c0eaSGlenn Lagasse 1753*f169c0eaSGlenn Lagasse if (uuid_compare(dd->gz_be_uuid, parent_uuid) == 0) { 1754*f169c0eaSGlenn Lagasse /* 1755*f169c0eaSGlenn Lagasse * Found a zone root dataset belonging to the parent 1756*f169c0eaSGlenn Lagasse * BE being destroyed. Destroy this zone BE. 1757*f169c0eaSGlenn Lagasse */ 1758*f169c0eaSGlenn Lagasse if ((ret = _be_destroy(zfs_get_name(zhp), dd)) != BE_SUCCESS) { 1759*f169c0eaSGlenn Lagasse be_print_err(gettext("be_destroy_zone_root_callback: " 1760*f169c0eaSGlenn Lagasse "failed to destroy zone root %s\n"), 1761*f169c0eaSGlenn Lagasse zfs_get_name(zhp)); 1762*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 1763*f169c0eaSGlenn Lagasse return (ret); 1764*f169c0eaSGlenn Lagasse } 1765*f169c0eaSGlenn Lagasse } 1766*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 1767*f169c0eaSGlenn Lagasse 1768*f169c0eaSGlenn Lagasse return (ret); 1769*f169c0eaSGlenn Lagasse } 1770*f169c0eaSGlenn Lagasse 1771*f169c0eaSGlenn Lagasse /* 1772*f169c0eaSGlenn Lagasse * Function: be_copy_zones 1773*f169c0eaSGlenn Lagasse * Description: Find valid zones and clone them to create their 1774*f169c0eaSGlenn Lagasse * corresponding datasets for the BE being created. 1775*f169c0eaSGlenn Lagasse * Parameters: 1776*f169c0eaSGlenn Lagasse * obe_name - name of source global BE being copied. 1777*f169c0eaSGlenn Lagasse * obe_root_ds - root dataset of source global BE being copied. 1778*f169c0eaSGlenn Lagasse * nbe_root_ds - root dataset of target global BE. 1779*f169c0eaSGlenn Lagasse * Return: 1780*f169c0eaSGlenn Lagasse * BE_SUCCESS - Success 1781*f169c0eaSGlenn Lagasse * be_errno_t - Failure 1782*f169c0eaSGlenn Lagasse * Scope: 1783*f169c0eaSGlenn Lagasse * Private 1784*f169c0eaSGlenn Lagasse */ 1785*f169c0eaSGlenn Lagasse static int 1786*f169c0eaSGlenn Lagasse be_copy_zones(char *obe_name, char *obe_root_ds, char *nbe_root_ds) 1787*f169c0eaSGlenn Lagasse { 1788*f169c0eaSGlenn Lagasse int i, num_retries; 1789*f169c0eaSGlenn Lagasse int ret = BE_SUCCESS; 1790*f169c0eaSGlenn Lagasse int iret = 0; 1791*f169c0eaSGlenn Lagasse char *zonename = NULL; 1792*f169c0eaSGlenn Lagasse char *zonepath = NULL; 1793*f169c0eaSGlenn Lagasse char *zone_be_name = NULL; 1794*f169c0eaSGlenn Lagasse char *temp_mntpt = NULL; 1795*f169c0eaSGlenn Lagasse char *new_zone_be_name = NULL; 1796*f169c0eaSGlenn Lagasse char zoneroot[MAXPATHLEN]; 1797*f169c0eaSGlenn Lagasse char zoneroot_ds[MAXPATHLEN]; 1798*f169c0eaSGlenn Lagasse char zone_container_ds[MAXPATHLEN]; 1799*f169c0eaSGlenn Lagasse char new_zoneroot_ds[MAXPATHLEN]; 1800*f169c0eaSGlenn Lagasse char ss[MAXPATHLEN]; 1801*f169c0eaSGlenn Lagasse uuid_t uu = { 0 }; 1802*f169c0eaSGlenn Lagasse char uu_string[UUID_PRINTABLE_STRING_LENGTH] = { 0 }; 1803*f169c0eaSGlenn Lagasse be_transaction_data_t bt = { 0 }; 1804*f169c0eaSGlenn Lagasse zfs_handle_t *obe_zhp = NULL; 1805*f169c0eaSGlenn Lagasse zfs_handle_t *nbe_zhp = NULL; 1806*f169c0eaSGlenn Lagasse zfs_handle_t *z_zhp = NULL; 1807*f169c0eaSGlenn Lagasse zoneList_t zlist = NULL; 1808*f169c0eaSGlenn Lagasse zoneBrandList_t *brands = NULL; 1809*f169c0eaSGlenn Lagasse boolean_t mounted_here = B_FALSE; 1810*f169c0eaSGlenn Lagasse char *snap_name = NULL; 1811*f169c0eaSGlenn Lagasse 1812*f169c0eaSGlenn Lagasse /* If zones are not implemented, then get out. */ 1813*f169c0eaSGlenn Lagasse if (!z_zones_are_implemented()) { 1814*f169c0eaSGlenn Lagasse return (BE_SUCCESS); 1815*f169c0eaSGlenn Lagasse } 1816*f169c0eaSGlenn Lagasse 1817*f169c0eaSGlenn Lagasse /* Get list of supported brands */ 1818*f169c0eaSGlenn Lagasse if ((brands = be_get_supported_brandlist()) == NULL) { 1819*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy_zones: " 1820*f169c0eaSGlenn Lagasse "no supported brands\n")); 1821*f169c0eaSGlenn Lagasse return (BE_SUCCESS); 1822*f169c0eaSGlenn Lagasse } 1823*f169c0eaSGlenn Lagasse 1824*f169c0eaSGlenn Lagasse /* Get handle to origin BE's root dataset */ 1825*f169c0eaSGlenn Lagasse if ((obe_zhp = zfs_open(g_zfs, obe_root_ds, ZFS_TYPE_FILESYSTEM)) 1826*f169c0eaSGlenn Lagasse == NULL) { 1827*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy_zones: failed to open " 1828*f169c0eaSGlenn Lagasse "the origin BE root dataset (%s) for zones processing: " 1829*f169c0eaSGlenn Lagasse "%s\n"), obe_root_ds, libzfs_error_description(g_zfs)); 1830*f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs)); 1831*f169c0eaSGlenn Lagasse } 1832*f169c0eaSGlenn Lagasse 1833*f169c0eaSGlenn Lagasse /* Get handle to newly cloned BE's root dataset */ 1834*f169c0eaSGlenn Lagasse if ((nbe_zhp = zfs_open(g_zfs, nbe_root_ds, ZFS_TYPE_FILESYSTEM)) 1835*f169c0eaSGlenn Lagasse == NULL) { 1836*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy_zones: failed to open " 1837*f169c0eaSGlenn Lagasse "the new BE root dataset (%s): %s\n"), nbe_root_ds, 1838*f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 1839*f169c0eaSGlenn Lagasse ZFS_CLOSE(obe_zhp); 1840*f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs)); 1841*f169c0eaSGlenn Lagasse } 1842*f169c0eaSGlenn Lagasse 1843*f169c0eaSGlenn Lagasse /* Get the uuid of the newly cloned parent BE. */ 1844*f169c0eaSGlenn Lagasse if (be_get_uuid(zfs_get_name(nbe_zhp), &uu) != BE_SUCCESS) { 1845*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy_zones: " 1846*f169c0eaSGlenn Lagasse "failed to get uuid for BE root " 1847*f169c0eaSGlenn Lagasse "dataset %s\n"), zfs_get_name(nbe_zhp)); 1848*f169c0eaSGlenn Lagasse ZFS_CLOSE(nbe_zhp); 1849*f169c0eaSGlenn Lagasse goto done; 1850*f169c0eaSGlenn Lagasse } 1851*f169c0eaSGlenn Lagasse ZFS_CLOSE(nbe_zhp); 1852*f169c0eaSGlenn Lagasse uuid_unparse(uu, uu_string); 1853*f169c0eaSGlenn Lagasse 1854*f169c0eaSGlenn Lagasse /* 1855*f169c0eaSGlenn Lagasse * If the origin BE is not mounted, we must mount it here to 1856*f169c0eaSGlenn Lagasse * gather data about the non-global zones in it. 1857*f169c0eaSGlenn Lagasse */ 1858*f169c0eaSGlenn Lagasse if (!zfs_is_mounted(obe_zhp, &temp_mntpt)) { 1859*f169c0eaSGlenn Lagasse if ((ret = _be_mount(obe_name, &temp_mntpt, 1860*f169c0eaSGlenn Lagasse BE_MOUNT_FLAG_NULL)) != BE_SUCCESS) { 1861*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy_zones: failed to " 1862*f169c0eaSGlenn Lagasse "mount the BE (%s) for zones procesing.\n"), 1863*f169c0eaSGlenn Lagasse obe_name); 1864*f169c0eaSGlenn Lagasse goto done; 1865*f169c0eaSGlenn Lagasse } 1866*f169c0eaSGlenn Lagasse mounted_here = B_TRUE; 1867*f169c0eaSGlenn Lagasse } 1868*f169c0eaSGlenn Lagasse 1869*f169c0eaSGlenn Lagasse z_set_zone_root(temp_mntpt); 1870*f169c0eaSGlenn Lagasse 1871*f169c0eaSGlenn Lagasse /* Get list of supported zones. */ 1872*f169c0eaSGlenn Lagasse if ((zlist = z_get_nonglobal_zone_list_by_brand(brands)) == NULL) { 1873*f169c0eaSGlenn Lagasse ret = BE_SUCCESS; 1874*f169c0eaSGlenn Lagasse goto done; 1875*f169c0eaSGlenn Lagasse } 1876*f169c0eaSGlenn Lagasse 1877*f169c0eaSGlenn Lagasse for (i = 0; (zonename = z_zlist_get_zonename(zlist, i)) != NULL; i++) { 1878*f169c0eaSGlenn Lagasse 1879*f169c0eaSGlenn Lagasse be_fs_list_data_t fld = { 0 }; 1880*f169c0eaSGlenn Lagasse char zonepath_ds[MAXPATHLEN]; 1881*f169c0eaSGlenn Lagasse char *ds = NULL; 1882*f169c0eaSGlenn Lagasse 1883*f169c0eaSGlenn Lagasse /* Get zonepath of zone */ 1884*f169c0eaSGlenn Lagasse zonepath = z_zlist_get_zonepath(zlist, i); 1885*f169c0eaSGlenn Lagasse 1886*f169c0eaSGlenn Lagasse /* Skip zones that aren't at least installed */ 1887*f169c0eaSGlenn Lagasse if (z_zlist_get_current_state(zlist, i) < ZONE_STATE_INSTALLED) 1888*f169c0eaSGlenn Lagasse continue; 1889*f169c0eaSGlenn Lagasse 1890*f169c0eaSGlenn Lagasse /* 1891*f169c0eaSGlenn Lagasse * Get the dataset of this zonepath. If its not 1892*f169c0eaSGlenn Lagasse * a dataset, skip it. 1893*f169c0eaSGlenn Lagasse */ 1894*f169c0eaSGlenn Lagasse if ((ds = be_get_ds_from_dir(zonepath)) == NULL) 1895*f169c0eaSGlenn Lagasse continue; 1896*f169c0eaSGlenn Lagasse 1897*f169c0eaSGlenn Lagasse (void) strlcpy(zonepath_ds, ds, sizeof (zonepath_ds)); 1898*f169c0eaSGlenn Lagasse free(ds); 1899*f169c0eaSGlenn Lagasse ds = NULL; 1900*f169c0eaSGlenn Lagasse 1901*f169c0eaSGlenn Lagasse /* Get zoneroot directory */ 1902*f169c0eaSGlenn Lagasse be_make_zoneroot(zonepath, zoneroot, sizeof (zoneroot)); 1903*f169c0eaSGlenn Lagasse 1904*f169c0eaSGlenn Lagasse /* If zonepath dataset not supported, skip it. */ 1905*f169c0eaSGlenn Lagasse if (!be_zone_supported(zonepath_ds)) { 1906*f169c0eaSGlenn Lagasse continue; 1907*f169c0eaSGlenn Lagasse } 1908*f169c0eaSGlenn Lagasse 1909*f169c0eaSGlenn Lagasse if ((ret = be_find_active_zone_root(obe_zhp, zonepath_ds, 1910*f169c0eaSGlenn Lagasse zoneroot_ds, sizeof (zoneroot_ds))) != BE_SUCCESS) { 1911*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy_zones: " 1912*f169c0eaSGlenn Lagasse "failed to find active zone root for zone %s " 1913*f169c0eaSGlenn Lagasse "in BE %s\n"), zonename, obe_name); 1914*f169c0eaSGlenn Lagasse goto done; 1915*f169c0eaSGlenn Lagasse } 1916*f169c0eaSGlenn Lagasse 1917*f169c0eaSGlenn Lagasse be_make_container_ds(zonepath_ds, zone_container_ds, 1918*f169c0eaSGlenn Lagasse sizeof (zone_container_ds)); 1919*f169c0eaSGlenn Lagasse 1920*f169c0eaSGlenn Lagasse if ((z_zhp = zfs_open(g_zfs, zoneroot_ds, 1921*f169c0eaSGlenn Lagasse ZFS_TYPE_FILESYSTEM)) == NULL) { 1922*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy_zones: " 1923*f169c0eaSGlenn Lagasse "failed to open zone root dataset (%s): %s\n"), 1924*f169c0eaSGlenn Lagasse zoneroot_ds, libzfs_error_description(g_zfs)); 1925*f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 1926*f169c0eaSGlenn Lagasse goto done; 1927*f169c0eaSGlenn Lagasse } 1928*f169c0eaSGlenn Lagasse 1929*f169c0eaSGlenn Lagasse zone_be_name = 1930*f169c0eaSGlenn Lagasse be_get_zone_be_name(zoneroot_ds, zone_container_ds); 1931*f169c0eaSGlenn Lagasse 1932*f169c0eaSGlenn Lagasse if ((new_zone_be_name = be_auto_zone_be_name(zone_container_ds, 1933*f169c0eaSGlenn Lagasse zone_be_name)) == NULL) { 1934*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy_zones: failed " 1935*f169c0eaSGlenn Lagasse "to generate auto name for zone BE.\n")); 1936*f169c0eaSGlenn Lagasse ret = BE_ERR_AUTONAME; 1937*f169c0eaSGlenn Lagasse goto done; 1938*f169c0eaSGlenn Lagasse } 1939*f169c0eaSGlenn Lagasse 1940*f169c0eaSGlenn Lagasse if ((snap_name = be_auto_snap_name()) == NULL) { 1941*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy_zones: failed to " 1942*f169c0eaSGlenn Lagasse "generate snapshot name for zone BE.\n")); 1943*f169c0eaSGlenn Lagasse ret = BE_ERR_AUTONAME; 1944*f169c0eaSGlenn Lagasse goto done; 1945*f169c0eaSGlenn Lagasse } 1946*f169c0eaSGlenn Lagasse 1947*f169c0eaSGlenn Lagasse (void) snprintf(ss, sizeof (ss), "%s@%s", zoneroot_ds, 1948*f169c0eaSGlenn Lagasse snap_name); 1949*f169c0eaSGlenn Lagasse 1950*f169c0eaSGlenn Lagasse if (zfs_snapshot(g_zfs, ss, B_TRUE, NULL) != 0) { 1951*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy_zones: " 1952*f169c0eaSGlenn Lagasse "failed to snapshot zone BE (%s): %s\n"), 1953*f169c0eaSGlenn Lagasse ss, libzfs_error_description(g_zfs)); 1954*f169c0eaSGlenn Lagasse if (libzfs_errno(g_zfs) == EZFS_EXISTS) 1955*f169c0eaSGlenn Lagasse ret = BE_ERR_ZONE_SS_EXISTS; 1956*f169c0eaSGlenn Lagasse else 1957*f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 1958*f169c0eaSGlenn Lagasse 1959*f169c0eaSGlenn Lagasse goto done; 1960*f169c0eaSGlenn Lagasse } 1961*f169c0eaSGlenn Lagasse 1962*f169c0eaSGlenn Lagasse (void) snprintf(new_zoneroot_ds, sizeof (new_zoneroot_ds), 1963*f169c0eaSGlenn Lagasse "%s/%s", zone_container_ds, new_zone_be_name); 1964*f169c0eaSGlenn Lagasse 1965*f169c0eaSGlenn Lagasse bt.obe_name = zone_be_name; 1966*f169c0eaSGlenn Lagasse bt.obe_root_ds = zoneroot_ds; 1967*f169c0eaSGlenn Lagasse bt.obe_snap_name = snap_name; 1968*f169c0eaSGlenn Lagasse bt.obe_altroot = temp_mntpt; 1969*f169c0eaSGlenn Lagasse bt.nbe_name = new_zone_be_name; 1970*f169c0eaSGlenn Lagasse bt.nbe_root_ds = new_zoneroot_ds; 1971*f169c0eaSGlenn Lagasse 1972*f169c0eaSGlenn Lagasse if (nvlist_alloc(&bt.nbe_zfs_props, NV_UNIQUE_NAME, 0) != 0) { 1973*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy_zones: " 1974*f169c0eaSGlenn Lagasse "internal error: out of memory\n")); 1975*f169c0eaSGlenn Lagasse ret = BE_ERR_NOMEM; 1976*f169c0eaSGlenn Lagasse goto done; 1977*f169c0eaSGlenn Lagasse } 1978*f169c0eaSGlenn Lagasse 1979*f169c0eaSGlenn Lagasse /* 1980*f169c0eaSGlenn Lagasse * The call to be_clone_fs_callback always closes the 1981*f169c0eaSGlenn Lagasse * zfs_handle so there's no need to close z_zhp. 1982*f169c0eaSGlenn Lagasse */ 1983*f169c0eaSGlenn Lagasse if ((iret = be_clone_fs_callback(z_zhp, &bt)) != 0) { 1984*f169c0eaSGlenn Lagasse z_zhp = NULL; 1985*f169c0eaSGlenn Lagasse if (iret != BE_ERR_BE_EXISTS) { 1986*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy_zones: " 1987*f169c0eaSGlenn Lagasse "failed to create zone BE clone for new " 1988*f169c0eaSGlenn Lagasse "zone BE %s\n"), new_zone_be_name); 1989*f169c0eaSGlenn Lagasse ret = iret; 1990*f169c0eaSGlenn Lagasse if (bt.nbe_zfs_props != NULL) 1991*f169c0eaSGlenn Lagasse nvlist_free(bt.nbe_zfs_props); 1992*f169c0eaSGlenn Lagasse goto done; 1993*f169c0eaSGlenn Lagasse } 1994*f169c0eaSGlenn Lagasse /* 1995*f169c0eaSGlenn Lagasse * We failed to create the new zone BE because a zone 1996*f169c0eaSGlenn Lagasse * BE with the auto-name we generated above has since 1997*f169c0eaSGlenn Lagasse * come into existence. Regenerate a new auto-name 1998*f169c0eaSGlenn Lagasse * and retry. 1999*f169c0eaSGlenn Lagasse */ 2000*f169c0eaSGlenn Lagasse for (num_retries = 1; 2001*f169c0eaSGlenn Lagasse num_retries < BE_AUTO_NAME_MAX_TRY; 2002*f169c0eaSGlenn Lagasse num_retries++) { 2003*f169c0eaSGlenn Lagasse 2004*f169c0eaSGlenn Lagasse /* Sleep 1 before retrying */ 2005*f169c0eaSGlenn Lagasse (void) sleep(1); 2006*f169c0eaSGlenn Lagasse 2007*f169c0eaSGlenn Lagasse /* Generate new auto zone BE name */ 2008*f169c0eaSGlenn Lagasse free(new_zone_be_name); 2009*f169c0eaSGlenn Lagasse if ((new_zone_be_name = be_auto_zone_be_name( 2010*f169c0eaSGlenn Lagasse zone_container_ds, 2011*f169c0eaSGlenn Lagasse zone_be_name)) == NULL) { 2012*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy_zones: " 2013*f169c0eaSGlenn Lagasse "failed to generate auto name " 2014*f169c0eaSGlenn Lagasse "for zone BE.\n")); 2015*f169c0eaSGlenn Lagasse ret = BE_ERR_AUTONAME; 2016*f169c0eaSGlenn Lagasse if (bt.nbe_zfs_props != NULL) 2017*f169c0eaSGlenn Lagasse nvlist_free(bt.nbe_zfs_props); 2018*f169c0eaSGlenn Lagasse goto done; 2019*f169c0eaSGlenn Lagasse } 2020*f169c0eaSGlenn Lagasse 2021*f169c0eaSGlenn Lagasse (void) snprintf(new_zoneroot_ds, 2022*f169c0eaSGlenn Lagasse sizeof (new_zoneroot_ds), 2023*f169c0eaSGlenn Lagasse "%s/%s", zone_container_ds, 2024*f169c0eaSGlenn Lagasse new_zone_be_name); 2025*f169c0eaSGlenn Lagasse bt.nbe_name = new_zone_be_name; 2026*f169c0eaSGlenn Lagasse bt.nbe_root_ds = new_zoneroot_ds; 2027*f169c0eaSGlenn Lagasse 2028*f169c0eaSGlenn Lagasse /* 2029*f169c0eaSGlenn Lagasse * Get handle to original zone BE's root 2030*f169c0eaSGlenn Lagasse * dataset. 2031*f169c0eaSGlenn Lagasse */ 2032*f169c0eaSGlenn Lagasse if ((z_zhp = zfs_open(g_zfs, zoneroot_ds, 2033*f169c0eaSGlenn Lagasse ZFS_TYPE_FILESYSTEM)) == NULL) { 2034*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy_zones: " 2035*f169c0eaSGlenn Lagasse "failed to open zone root " 2036*f169c0eaSGlenn Lagasse "dataset (%s): %s\n"), 2037*f169c0eaSGlenn Lagasse zoneroot_ds, 2038*f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 2039*f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 2040*f169c0eaSGlenn Lagasse if (bt.nbe_zfs_props != NULL) 2041*f169c0eaSGlenn Lagasse nvlist_free(bt.nbe_zfs_props); 2042*f169c0eaSGlenn Lagasse goto done; 2043*f169c0eaSGlenn Lagasse } 2044*f169c0eaSGlenn Lagasse 2045*f169c0eaSGlenn Lagasse /* 2046*f169c0eaSGlenn Lagasse * Try to clone the zone BE again. This 2047*f169c0eaSGlenn Lagasse * call will end up closing the zfs 2048*f169c0eaSGlenn Lagasse * handle passed in whether it 2049*f169c0eaSGlenn Lagasse * succeeds or fails. 2050*f169c0eaSGlenn Lagasse */ 2051*f169c0eaSGlenn Lagasse iret = be_clone_fs_callback(z_zhp, &bt); 2052*f169c0eaSGlenn Lagasse z_zhp = NULL; 2053*f169c0eaSGlenn Lagasse if (iret == 0) { 2054*f169c0eaSGlenn Lagasse break; 2055*f169c0eaSGlenn Lagasse } else if (iret != BE_ERR_BE_EXISTS) { 2056*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy_zones: " 2057*f169c0eaSGlenn Lagasse "failed to create zone BE clone " 2058*f169c0eaSGlenn Lagasse "for new zone BE %s\n"), 2059*f169c0eaSGlenn Lagasse new_zone_be_name); 2060*f169c0eaSGlenn Lagasse ret = iret; 2061*f169c0eaSGlenn Lagasse if (bt.nbe_zfs_props != NULL) 2062*f169c0eaSGlenn Lagasse nvlist_free(bt.nbe_zfs_props); 2063*f169c0eaSGlenn Lagasse goto done; 2064*f169c0eaSGlenn Lagasse } 2065*f169c0eaSGlenn Lagasse } 2066*f169c0eaSGlenn Lagasse /* 2067*f169c0eaSGlenn Lagasse * If we've exhausted the maximum number of 2068*f169c0eaSGlenn Lagasse * tries, free the auto zone BE name and return 2069*f169c0eaSGlenn Lagasse * error. 2070*f169c0eaSGlenn Lagasse */ 2071*f169c0eaSGlenn Lagasse if (num_retries == BE_AUTO_NAME_MAX_TRY) { 2072*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy_zones: failed " 2073*f169c0eaSGlenn Lagasse "to create a unique auto zone BE name\n")); 2074*f169c0eaSGlenn Lagasse free(bt.nbe_name); 2075*f169c0eaSGlenn Lagasse bt.nbe_name = NULL; 2076*f169c0eaSGlenn Lagasse ret = BE_ERR_AUTONAME; 2077*f169c0eaSGlenn Lagasse if (bt.nbe_zfs_props != NULL) 2078*f169c0eaSGlenn Lagasse nvlist_free(bt.nbe_zfs_props); 2079*f169c0eaSGlenn Lagasse goto done; 2080*f169c0eaSGlenn Lagasse } 2081*f169c0eaSGlenn Lagasse } 2082*f169c0eaSGlenn Lagasse 2083*f169c0eaSGlenn Lagasse if (bt.nbe_zfs_props != NULL) 2084*f169c0eaSGlenn Lagasse nvlist_free(bt.nbe_zfs_props); 2085*f169c0eaSGlenn Lagasse 2086*f169c0eaSGlenn Lagasse z_zhp = NULL; 2087*f169c0eaSGlenn Lagasse 2088*f169c0eaSGlenn Lagasse if ((z_zhp = zfs_open(g_zfs, new_zoneroot_ds, 2089*f169c0eaSGlenn Lagasse ZFS_TYPE_FILESYSTEM)) == NULL) { 2090*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy_zones: " 2091*f169c0eaSGlenn Lagasse "failed to open the new zone BE root dataset " 2092*f169c0eaSGlenn Lagasse "(%s): %s\n"), new_zoneroot_ds, 2093*f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 2094*f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 2095*f169c0eaSGlenn Lagasse goto done; 2096*f169c0eaSGlenn Lagasse } 2097*f169c0eaSGlenn Lagasse 2098*f169c0eaSGlenn Lagasse if (zfs_prop_set(z_zhp, BE_ZONE_PARENTBE_PROPERTY, 2099*f169c0eaSGlenn Lagasse uu_string) != 0) { 2100*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy_zones: " 2101*f169c0eaSGlenn Lagasse "failed to set parentbe property\n")); 2102*f169c0eaSGlenn Lagasse ZFS_CLOSE(z_zhp); 2103*f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 2104*f169c0eaSGlenn Lagasse goto done; 2105*f169c0eaSGlenn Lagasse } 2106*f169c0eaSGlenn Lagasse 2107*f169c0eaSGlenn Lagasse if (zfs_prop_set(z_zhp, BE_ZONE_ACTIVE_PROPERTY, "on") != 0) { 2108*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy_zones: " 2109*f169c0eaSGlenn Lagasse "failed to set active property\n")); 2110*f169c0eaSGlenn Lagasse ZFS_CLOSE(z_zhp); 2111*f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 2112*f169c0eaSGlenn Lagasse goto done; 2113*f169c0eaSGlenn Lagasse } 2114*f169c0eaSGlenn Lagasse 2115*f169c0eaSGlenn Lagasse /* 2116*f169c0eaSGlenn Lagasse * Generate a list of file systems from the original 2117*f169c0eaSGlenn Lagasse * zone BE that are legacy mounted. We use this list 2118*f169c0eaSGlenn Lagasse * to determine which entries in the vfstab we need to 2119*f169c0eaSGlenn Lagasse * update for the new zone BE we've just created. 2120*f169c0eaSGlenn Lagasse */ 2121*f169c0eaSGlenn Lagasse if ((ret = be_get_legacy_fs(obe_name, obe_root_ds, 2122*f169c0eaSGlenn Lagasse zoneroot_ds, zoneroot, &fld)) != BE_SUCCESS) { 2123*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy_zones: " 2124*f169c0eaSGlenn Lagasse "failed to get legacy mounted file system " 2125*f169c0eaSGlenn Lagasse "list for zone %s\n"), zonename); 2126*f169c0eaSGlenn Lagasse ZFS_CLOSE(z_zhp); 2127*f169c0eaSGlenn Lagasse goto done; 2128*f169c0eaSGlenn Lagasse } 2129*f169c0eaSGlenn Lagasse 2130*f169c0eaSGlenn Lagasse /* 2131*f169c0eaSGlenn Lagasse * Update new zone BE's vfstab. 2132*f169c0eaSGlenn Lagasse */ 2133*f169c0eaSGlenn Lagasse if ((ret = be_update_zone_vfstab(z_zhp, bt.nbe_name, 2134*f169c0eaSGlenn Lagasse zonepath_ds, zonepath_ds, &fld)) != BE_SUCCESS) { 2135*f169c0eaSGlenn Lagasse be_print_err(gettext("be_copy_zones: " 2136*f169c0eaSGlenn Lagasse "failed to update new BE's vfstab (%s)\n"), 2137*f169c0eaSGlenn Lagasse bt.nbe_name); 2138*f169c0eaSGlenn Lagasse ZFS_CLOSE(z_zhp); 2139*f169c0eaSGlenn Lagasse be_free_fs_list(&fld); 2140*f169c0eaSGlenn Lagasse goto done; 2141*f169c0eaSGlenn Lagasse } 2142*f169c0eaSGlenn Lagasse 2143*f169c0eaSGlenn Lagasse be_free_fs_list(&fld); 2144*f169c0eaSGlenn Lagasse ZFS_CLOSE(z_zhp); 2145*f169c0eaSGlenn Lagasse } 2146*f169c0eaSGlenn Lagasse 2147*f169c0eaSGlenn Lagasse done: 2148*f169c0eaSGlenn Lagasse free(snap_name); 2149*f169c0eaSGlenn Lagasse if (brands != NULL) 2150*f169c0eaSGlenn Lagasse z_free_brand_list(brands); 2151*f169c0eaSGlenn Lagasse if (zlist != NULL) 2152*f169c0eaSGlenn Lagasse z_free_zone_list(zlist); 2153*f169c0eaSGlenn Lagasse 2154*f169c0eaSGlenn Lagasse if (mounted_here) 2155*f169c0eaSGlenn Lagasse (void) _be_unmount(obe_name, 0); 2156*f169c0eaSGlenn Lagasse 2157*f169c0eaSGlenn Lagasse ZFS_CLOSE(obe_zhp); 2158*f169c0eaSGlenn Lagasse return (ret); 2159*f169c0eaSGlenn Lagasse } 2160*f169c0eaSGlenn Lagasse 2161*f169c0eaSGlenn Lagasse /* 2162*f169c0eaSGlenn Lagasse * Function: be_clone_fs_callback 2163*f169c0eaSGlenn Lagasse * Description: Callback function used to iterate through a BE's filesystems 2164*f169c0eaSGlenn Lagasse * to clone them for the new BE. 2165*f169c0eaSGlenn Lagasse * Parameters: 2166*f169c0eaSGlenn Lagasse * zhp - zfs_handle_t pointer for the filesystem being processed. 2167*f169c0eaSGlenn Lagasse * data - be_transaction_data_t pointer providing information 2168*f169c0eaSGlenn Lagasse * about original BE and new BE. 2169*f169c0eaSGlenn Lagasse * Return: 2170*f169c0eaSGlenn Lagasse * 0 - Success 2171*f169c0eaSGlenn Lagasse * be_errno_t - Failure 2172*f169c0eaSGlenn Lagasse * Scope: 2173*f169c0eaSGlenn Lagasse * Private 2174*f169c0eaSGlenn Lagasse */ 2175*f169c0eaSGlenn Lagasse static int 2176*f169c0eaSGlenn Lagasse be_clone_fs_callback(zfs_handle_t *zhp, void *data) 2177*f169c0eaSGlenn Lagasse { 2178*f169c0eaSGlenn Lagasse be_transaction_data_t *bt = data; 2179*f169c0eaSGlenn Lagasse zfs_handle_t *zhp_ss = NULL; 2180*f169c0eaSGlenn Lagasse char prop_buf[MAXPATHLEN]; 2181*f169c0eaSGlenn Lagasse char zhp_name[ZFS_MAXNAMELEN]; 2182*f169c0eaSGlenn Lagasse char clone_ds[MAXPATHLEN]; 2183*f169c0eaSGlenn Lagasse char ss[MAXPATHLEN]; 2184*f169c0eaSGlenn Lagasse int ret = 0; 2185*f169c0eaSGlenn Lagasse 2186*f169c0eaSGlenn Lagasse if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, prop_buf, 2187*f169c0eaSGlenn Lagasse ZFS_MAXPROPLEN, NULL, NULL, 0, B_FALSE) != 0) { 2188*f169c0eaSGlenn Lagasse be_print_err(gettext("be_clone_fs_callback: " 2189*f169c0eaSGlenn Lagasse "failed to get dataset mountpoint (%s): %s\n"), 2190*f169c0eaSGlenn Lagasse zfs_get_name(zhp), libzfs_error_description(g_zfs)); 2191*f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 2192*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 2193*f169c0eaSGlenn Lagasse return (ret); 2194*f169c0eaSGlenn Lagasse } 2195*f169c0eaSGlenn Lagasse 2196*f169c0eaSGlenn Lagasse if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED) != 0 && 2197*f169c0eaSGlenn Lagasse strcmp(prop_buf, "legacy") != 0) { 2198*f169c0eaSGlenn Lagasse /* 2199*f169c0eaSGlenn Lagasse * Since zfs can't currently handle setting the 2200*f169c0eaSGlenn Lagasse * mountpoint for a zoned dataset we'll have to skip 2201*f169c0eaSGlenn Lagasse * this dataset. This is because the mountpoint is not 2202*f169c0eaSGlenn Lagasse * set to "legacy". 2203*f169c0eaSGlenn Lagasse */ 2204*f169c0eaSGlenn Lagasse goto zoned; 2205*f169c0eaSGlenn Lagasse } 2206*f169c0eaSGlenn Lagasse /* 2207*f169c0eaSGlenn Lagasse * Get a copy of the dataset name from the zfs handle 2208*f169c0eaSGlenn Lagasse */ 2209*f169c0eaSGlenn Lagasse (void) strlcpy(zhp_name, zfs_get_name(zhp), sizeof (zhp_name)); 2210*f169c0eaSGlenn Lagasse 2211*f169c0eaSGlenn Lagasse /* 2212*f169c0eaSGlenn Lagasse * Get the clone dataset name and prepare the zfs properties for it. 2213*f169c0eaSGlenn Lagasse */ 2214*f169c0eaSGlenn Lagasse if ((ret = be_prep_clone_send_fs(zhp, bt, clone_ds, 2215*f169c0eaSGlenn Lagasse sizeof (clone_ds))) != BE_SUCCESS) { 2216*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 2217*f169c0eaSGlenn Lagasse return (ret); 2218*f169c0eaSGlenn Lagasse } 2219*f169c0eaSGlenn Lagasse 2220*f169c0eaSGlenn Lagasse /* 2221*f169c0eaSGlenn Lagasse * Generate the name of the snapshot to use. 2222*f169c0eaSGlenn Lagasse */ 2223*f169c0eaSGlenn Lagasse (void) snprintf(ss, sizeof (ss), "%s@%s", zhp_name, 2224*f169c0eaSGlenn Lagasse bt->obe_snap_name); 2225*f169c0eaSGlenn Lagasse 2226*f169c0eaSGlenn Lagasse /* 2227*f169c0eaSGlenn Lagasse * Get handle to snapshot. 2228*f169c0eaSGlenn Lagasse */ 2229*f169c0eaSGlenn Lagasse if ((zhp_ss = zfs_open(g_zfs, ss, ZFS_TYPE_SNAPSHOT)) == NULL) { 2230*f169c0eaSGlenn Lagasse be_print_err(gettext("be_clone_fs_callback: " 2231*f169c0eaSGlenn Lagasse "failed to get handle to snapshot (%s): %s\n"), ss, 2232*f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 2233*f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 2234*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 2235*f169c0eaSGlenn Lagasse return (ret); 2236*f169c0eaSGlenn Lagasse } 2237*f169c0eaSGlenn Lagasse 2238*f169c0eaSGlenn Lagasse /* 2239*f169c0eaSGlenn Lagasse * Clone the dataset. 2240*f169c0eaSGlenn Lagasse */ 2241*f169c0eaSGlenn Lagasse if (zfs_clone(zhp_ss, clone_ds, bt->nbe_zfs_props) != 0) { 2242*f169c0eaSGlenn Lagasse be_print_err(gettext("be_clone_fs_callback: " 2243*f169c0eaSGlenn Lagasse "failed to create clone dataset (%s): %s\n"), 2244*f169c0eaSGlenn Lagasse clone_ds, libzfs_error_description(g_zfs)); 2245*f169c0eaSGlenn Lagasse 2246*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp_ss); 2247*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 2248*f169c0eaSGlenn Lagasse 2249*f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs)); 2250*f169c0eaSGlenn Lagasse } 2251*f169c0eaSGlenn Lagasse 2252*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp_ss); 2253*f169c0eaSGlenn Lagasse 2254*f169c0eaSGlenn Lagasse zoned: 2255*f169c0eaSGlenn Lagasse /* 2256*f169c0eaSGlenn Lagasse * Iterate through zhp's children datasets (if any) 2257*f169c0eaSGlenn Lagasse * and clone them accordingly. 2258*f169c0eaSGlenn Lagasse */ 2259*f169c0eaSGlenn Lagasse if ((ret = zfs_iter_filesystems(zhp, be_clone_fs_callback, bt)) != 0) { 2260*f169c0eaSGlenn Lagasse /* 2261*f169c0eaSGlenn Lagasse * Error occurred while processing a child dataset. 2262*f169c0eaSGlenn Lagasse * Destroy this dataset and return error. 2263*f169c0eaSGlenn Lagasse */ 2264*f169c0eaSGlenn Lagasse zfs_handle_t *d_zhp = NULL; 2265*f169c0eaSGlenn Lagasse 2266*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 2267*f169c0eaSGlenn Lagasse 2268*f169c0eaSGlenn Lagasse if ((d_zhp = zfs_open(g_zfs, clone_ds, ZFS_TYPE_FILESYSTEM)) 2269*f169c0eaSGlenn Lagasse == NULL) { 2270*f169c0eaSGlenn Lagasse return (ret); 2271*f169c0eaSGlenn Lagasse } 2272*f169c0eaSGlenn Lagasse 2273*f169c0eaSGlenn Lagasse (void) zfs_destroy(d_zhp, B_FALSE); 2274*f169c0eaSGlenn Lagasse ZFS_CLOSE(d_zhp); 2275*f169c0eaSGlenn Lagasse return (ret); 2276*f169c0eaSGlenn Lagasse } 2277*f169c0eaSGlenn Lagasse 2278*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 2279*f169c0eaSGlenn Lagasse return (0); 2280*f169c0eaSGlenn Lagasse } 2281*f169c0eaSGlenn Lagasse 2282*f169c0eaSGlenn Lagasse /* 2283*f169c0eaSGlenn Lagasse * Function: be_send_fs_callback 2284*f169c0eaSGlenn Lagasse * Description: Callback function used to iterate through a BE's filesystems 2285*f169c0eaSGlenn Lagasse * to copy them for the new BE. 2286*f169c0eaSGlenn Lagasse * Parameters: 2287*f169c0eaSGlenn Lagasse * zhp - zfs_handle_t pointer for the filesystem being processed. 2288*f169c0eaSGlenn Lagasse * data - be_transaction_data_t pointer providing information 2289*f169c0eaSGlenn Lagasse * about original BE and new BE. 2290*f169c0eaSGlenn Lagasse * Return: 2291*f169c0eaSGlenn Lagasse * 0 - Success 2292*f169c0eaSGlenn Lagasse * be_errnot_t - Failure 2293*f169c0eaSGlenn Lagasse * Scope: 2294*f169c0eaSGlenn Lagasse * Private 2295*f169c0eaSGlenn Lagasse */ 2296*f169c0eaSGlenn Lagasse static int 2297*f169c0eaSGlenn Lagasse be_send_fs_callback(zfs_handle_t *zhp, void *data) 2298*f169c0eaSGlenn Lagasse { 2299*f169c0eaSGlenn Lagasse be_transaction_data_t *bt = data; 2300*f169c0eaSGlenn Lagasse recvflags_t flags = { 0 }; 2301*f169c0eaSGlenn Lagasse char zhp_name[ZFS_MAXNAMELEN]; 2302*f169c0eaSGlenn Lagasse char clone_ds[MAXPATHLEN]; 2303*f169c0eaSGlenn Lagasse sendflags_t send_flags = { 0 }; 2304*f169c0eaSGlenn Lagasse int pid, status, retval; 2305*f169c0eaSGlenn Lagasse int srpipe[2]; 2306*f169c0eaSGlenn Lagasse int ret = 0; 2307*f169c0eaSGlenn Lagasse 2308*f169c0eaSGlenn Lagasse /* 2309*f169c0eaSGlenn Lagasse * Get a copy of the dataset name from the zfs handle 2310*f169c0eaSGlenn Lagasse */ 2311*f169c0eaSGlenn Lagasse (void) strlcpy(zhp_name, zfs_get_name(zhp), sizeof (zhp_name)); 2312*f169c0eaSGlenn Lagasse 2313*f169c0eaSGlenn Lagasse /* 2314*f169c0eaSGlenn Lagasse * Get the clone dataset name and prepare the zfs properties for it. 2315*f169c0eaSGlenn Lagasse */ 2316*f169c0eaSGlenn Lagasse if ((ret = be_prep_clone_send_fs(zhp, bt, clone_ds, 2317*f169c0eaSGlenn Lagasse sizeof (clone_ds))) != BE_SUCCESS) { 2318*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 2319*f169c0eaSGlenn Lagasse return (ret); 2320*f169c0eaSGlenn Lagasse } 2321*f169c0eaSGlenn Lagasse 2322*f169c0eaSGlenn Lagasse /* 2323*f169c0eaSGlenn Lagasse * Create the new dataset. 2324*f169c0eaSGlenn Lagasse */ 2325*f169c0eaSGlenn Lagasse if (zfs_create(g_zfs, clone_ds, ZFS_TYPE_FILESYSTEM, bt->nbe_zfs_props) 2326*f169c0eaSGlenn Lagasse != 0) { 2327*f169c0eaSGlenn Lagasse be_print_err(gettext("be_send_fs_callback: " 2328*f169c0eaSGlenn Lagasse "failed to create new dataset '%s': %s\n"), 2329*f169c0eaSGlenn Lagasse clone_ds, libzfs_error_description(g_zfs)); 2330*f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 2331*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 2332*f169c0eaSGlenn Lagasse return (ret); 2333*f169c0eaSGlenn Lagasse } 2334*f169c0eaSGlenn Lagasse 2335*f169c0eaSGlenn Lagasse /* 2336*f169c0eaSGlenn Lagasse * Destination file system is already created 2337*f169c0eaSGlenn Lagasse * hence we need to set the force flag on 2338*f169c0eaSGlenn Lagasse */ 2339*f169c0eaSGlenn Lagasse flags.force = B_TRUE; 2340*f169c0eaSGlenn Lagasse 2341*f169c0eaSGlenn Lagasse /* 2342*f169c0eaSGlenn Lagasse * Initiate the pipe to be used for the send and recv 2343*f169c0eaSGlenn Lagasse */ 2344*f169c0eaSGlenn Lagasse if (pipe(srpipe) != 0) { 2345*f169c0eaSGlenn Lagasse int err = errno; 2346*f169c0eaSGlenn Lagasse be_print_err(gettext("be_send_fs_callback: failed to " 2347*f169c0eaSGlenn Lagasse "open pipe\n")); 2348*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 2349*f169c0eaSGlenn Lagasse return (errno_to_be_err(err)); 2350*f169c0eaSGlenn Lagasse } 2351*f169c0eaSGlenn Lagasse 2352*f169c0eaSGlenn Lagasse /* 2353*f169c0eaSGlenn Lagasse * Fork off a child to send the dataset 2354*f169c0eaSGlenn Lagasse */ 2355*f169c0eaSGlenn Lagasse if ((pid = fork()) == -1) { 2356*f169c0eaSGlenn Lagasse int err = errno; 2357*f169c0eaSGlenn Lagasse be_print_err(gettext("be_send_fs_callback: failed to fork\n")); 2358*f169c0eaSGlenn Lagasse (void) close(srpipe[0]); 2359*f169c0eaSGlenn Lagasse (void) close(srpipe[1]); 2360*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 2361*f169c0eaSGlenn Lagasse return (errno_to_be_err(err)); 2362*f169c0eaSGlenn Lagasse } else if (pid == 0) { /* child process */ 2363*f169c0eaSGlenn Lagasse (void) close(srpipe[0]); 2364*f169c0eaSGlenn Lagasse 2365*f169c0eaSGlenn Lagasse /* Send dataset */ 2366*f169c0eaSGlenn Lagasse if (zfs_send(zhp, NULL, bt->obe_snap_name, send_flags, 2367*f169c0eaSGlenn Lagasse srpipe[1], NULL, NULL, NULL) != 0) { 2368*f169c0eaSGlenn Lagasse _exit(1); 2369*f169c0eaSGlenn Lagasse } 2370*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 2371*f169c0eaSGlenn Lagasse 2372*f169c0eaSGlenn Lagasse _exit(0); 2373*f169c0eaSGlenn Lagasse } 2374*f169c0eaSGlenn Lagasse 2375*f169c0eaSGlenn Lagasse (void) close(srpipe[1]); 2376*f169c0eaSGlenn Lagasse 2377*f169c0eaSGlenn Lagasse /* Receive dataset */ 2378*f169c0eaSGlenn Lagasse if (zfs_receive(g_zfs, clone_ds, flags, srpipe[0], NULL) != 0) { 2379*f169c0eaSGlenn Lagasse be_print_err(gettext("be_send_fs_callback: failed to " 2380*f169c0eaSGlenn Lagasse "recv dataset (%s)\n"), clone_ds); 2381*f169c0eaSGlenn Lagasse } 2382*f169c0eaSGlenn Lagasse (void) close(srpipe[0]); 2383*f169c0eaSGlenn Lagasse 2384*f169c0eaSGlenn Lagasse /* wait for child to exit */ 2385*f169c0eaSGlenn Lagasse do { 2386*f169c0eaSGlenn Lagasse retval = waitpid(pid, &status, 0); 2387*f169c0eaSGlenn Lagasse if (retval == -1) { 2388*f169c0eaSGlenn Lagasse status = 0; 2389*f169c0eaSGlenn Lagasse } 2390*f169c0eaSGlenn Lagasse } while (retval != pid); 2391*f169c0eaSGlenn Lagasse 2392*f169c0eaSGlenn Lagasse if (WEXITSTATUS(status) != 0) { 2393*f169c0eaSGlenn Lagasse be_print_err(gettext("be_send_fs_callback: failed to " 2394*f169c0eaSGlenn Lagasse "send dataset (%s)\n"), zhp_name); 2395*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 2396*f169c0eaSGlenn Lagasse return (BE_ERR_ZFS); 2397*f169c0eaSGlenn Lagasse } 2398*f169c0eaSGlenn Lagasse 2399*f169c0eaSGlenn Lagasse 2400*f169c0eaSGlenn Lagasse /* 2401*f169c0eaSGlenn Lagasse * Iterate through zhp's children datasets (if any) 2402*f169c0eaSGlenn Lagasse * and send them accordingly. 2403*f169c0eaSGlenn Lagasse */ 2404*f169c0eaSGlenn Lagasse if ((ret = zfs_iter_filesystems(zhp, be_send_fs_callback, bt)) != 0) { 2405*f169c0eaSGlenn Lagasse /* 2406*f169c0eaSGlenn Lagasse * Error occurred while processing a child dataset. 2407*f169c0eaSGlenn Lagasse * Destroy this dataset and return error. 2408*f169c0eaSGlenn Lagasse */ 2409*f169c0eaSGlenn Lagasse zfs_handle_t *d_zhp = NULL; 2410*f169c0eaSGlenn Lagasse 2411*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 2412*f169c0eaSGlenn Lagasse 2413*f169c0eaSGlenn Lagasse if ((d_zhp = zfs_open(g_zfs, clone_ds, ZFS_TYPE_FILESYSTEM)) 2414*f169c0eaSGlenn Lagasse == NULL) { 2415*f169c0eaSGlenn Lagasse return (ret); 2416*f169c0eaSGlenn Lagasse } 2417*f169c0eaSGlenn Lagasse 2418*f169c0eaSGlenn Lagasse (void) zfs_destroy(d_zhp, B_FALSE); 2419*f169c0eaSGlenn Lagasse ZFS_CLOSE(d_zhp); 2420*f169c0eaSGlenn Lagasse return (ret); 2421*f169c0eaSGlenn Lagasse } 2422*f169c0eaSGlenn Lagasse 2423*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 2424*f169c0eaSGlenn Lagasse return (0); 2425*f169c0eaSGlenn Lagasse } 2426*f169c0eaSGlenn Lagasse 2427*f169c0eaSGlenn Lagasse /* 2428*f169c0eaSGlenn Lagasse * Function: be_destroy_callback 2429*f169c0eaSGlenn Lagasse * Description: Callback function used to destroy a BEs children datasets 2430*f169c0eaSGlenn Lagasse * and snapshots. 2431*f169c0eaSGlenn Lagasse * Parameters: 2432*f169c0eaSGlenn Lagasse * zhp - zfs_handle_t pointer to the filesystem being processed. 2433*f169c0eaSGlenn Lagasse * data - Not used. 2434*f169c0eaSGlenn Lagasse * Returns: 2435*f169c0eaSGlenn Lagasse * 0 - Success 2436*f169c0eaSGlenn Lagasse * be_errno_t - Failure 2437*f169c0eaSGlenn Lagasse * Scope: 2438*f169c0eaSGlenn Lagasse * Private 2439*f169c0eaSGlenn Lagasse */ 2440*f169c0eaSGlenn Lagasse static int 2441*f169c0eaSGlenn Lagasse be_destroy_callback(zfs_handle_t *zhp, void *data) 2442*f169c0eaSGlenn Lagasse { 2443*f169c0eaSGlenn Lagasse be_destroy_data_t *dd = data; 2444*f169c0eaSGlenn Lagasse int ret = 0; 2445*f169c0eaSGlenn Lagasse 2446*f169c0eaSGlenn Lagasse /* 2447*f169c0eaSGlenn Lagasse * Iterate down this file system's hierarchical children 2448*f169c0eaSGlenn Lagasse * and destroy them first. 2449*f169c0eaSGlenn Lagasse */ 2450*f169c0eaSGlenn Lagasse if ((ret = zfs_iter_filesystems(zhp, be_destroy_callback, dd)) != 0) { 2451*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 2452*f169c0eaSGlenn Lagasse return (ret); 2453*f169c0eaSGlenn Lagasse } 2454*f169c0eaSGlenn Lagasse 2455*f169c0eaSGlenn Lagasse if (dd->destroy_snaps) { 2456*f169c0eaSGlenn Lagasse /* 2457*f169c0eaSGlenn Lagasse * Iterate through this file system's snapshots and 2458*f169c0eaSGlenn Lagasse * destroy them before destroying the file system itself. 2459*f169c0eaSGlenn Lagasse */ 2460*f169c0eaSGlenn Lagasse if ((ret = zfs_iter_snapshots(zhp, be_destroy_callback, dd)) 2461*f169c0eaSGlenn Lagasse != 0) { 2462*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 2463*f169c0eaSGlenn Lagasse return (ret); 2464*f169c0eaSGlenn Lagasse } 2465*f169c0eaSGlenn Lagasse } 2466*f169c0eaSGlenn Lagasse 2467*f169c0eaSGlenn Lagasse /* Attempt to unmount the dataset before destroying it */ 2468*f169c0eaSGlenn Lagasse if (dd->force_unmount) { 2469*f169c0eaSGlenn Lagasse if ((ret = zfs_unmount(zhp, NULL, MS_FORCE)) != 0) { 2470*f169c0eaSGlenn Lagasse be_print_err(gettext("be_destroy_callback: " 2471*f169c0eaSGlenn Lagasse "failed to unmount %s: %s\n"), zfs_get_name(zhp), 2472*f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 2473*f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 2474*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 2475*f169c0eaSGlenn Lagasse return (ret); 2476*f169c0eaSGlenn Lagasse } 2477*f169c0eaSGlenn Lagasse } 2478*f169c0eaSGlenn Lagasse 2479*f169c0eaSGlenn Lagasse if (zfs_destroy(zhp, B_FALSE) != 0) { 2480*f169c0eaSGlenn Lagasse be_print_err(gettext("be_destroy_callback: " 2481*f169c0eaSGlenn Lagasse "failed to destroy %s: %s\n"), zfs_get_name(zhp), 2482*f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 2483*f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 2484*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 2485*f169c0eaSGlenn Lagasse return (ret); 2486*f169c0eaSGlenn Lagasse } 2487*f169c0eaSGlenn Lagasse 2488*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 2489*f169c0eaSGlenn Lagasse return (0); 2490*f169c0eaSGlenn Lagasse } 2491*f169c0eaSGlenn Lagasse 2492*f169c0eaSGlenn Lagasse /* 2493*f169c0eaSGlenn Lagasse * Function: be_demote_callback 2494*f169c0eaSGlenn Lagasse * Description: This callback function is used to iterate through the file 2495*f169c0eaSGlenn Lagasse * systems of a BE, looking for the right clone to promote such 2496*f169c0eaSGlenn Lagasse * that this file system is left without any dependent clones. 2497*f169c0eaSGlenn Lagasse * If the file system has no dependent clones, it doesn't need 2498*f169c0eaSGlenn Lagasse * to get demoted, and the function will return success. 2499*f169c0eaSGlenn Lagasse * 2500*f169c0eaSGlenn Lagasse * The demotion will be done in two passes. The first pass 2501*f169c0eaSGlenn Lagasse * will attempt to find the youngest snapshot that has a clone 2502*f169c0eaSGlenn Lagasse * that is part of some other BE. The second pass will attempt 2503*f169c0eaSGlenn Lagasse * to find the youngest snapshot that has a clone that is not 2504*f169c0eaSGlenn Lagasse * part of a BE. Doing this helps ensure the aggregated set of 2505*f169c0eaSGlenn Lagasse * file systems that compose a BE stay coordinated wrt BE 2506*f169c0eaSGlenn Lagasse * snapshots and BE dependents. It also prevents a random user 2507*f169c0eaSGlenn Lagasse * generated clone of a BE dataset to become the parent of other 2508*f169c0eaSGlenn Lagasse * BE datasets after demoting this dataset. 2509*f169c0eaSGlenn Lagasse * 2510*f169c0eaSGlenn Lagasse * Parameters: 2511*f169c0eaSGlenn Lagasse * zhp - zfs_handle_t pointer to the current file system being 2512*f169c0eaSGlenn Lagasse * processed. 2513*f169c0eaSGlenn Lagasse * data - not used. 2514*f169c0eaSGlenn Lagasse * Return: 2515*f169c0eaSGlenn Lagasse * 0 - Success 2516*f169c0eaSGlenn Lagasse * be_errno_t - Failure 2517*f169c0eaSGlenn Lagasse * Scope: 2518*f169c0eaSGlenn Lagasse * Private 2519*f169c0eaSGlenn Lagasse */ 2520*f169c0eaSGlenn Lagasse static int 2521*f169c0eaSGlenn Lagasse /* LINTED */ 2522*f169c0eaSGlenn Lagasse be_demote_callback(zfs_handle_t *zhp, void *data) 2523*f169c0eaSGlenn Lagasse { 2524*f169c0eaSGlenn Lagasse be_demote_data_t dd = { 0 }; 2525*f169c0eaSGlenn Lagasse int i, ret = 0; 2526*f169c0eaSGlenn Lagasse 2527*f169c0eaSGlenn Lagasse /* 2528*f169c0eaSGlenn Lagasse * Initialize be_demote_data for the first pass - this will find a 2529*f169c0eaSGlenn Lagasse * clone in another BE, if one exists. 2530*f169c0eaSGlenn Lagasse */ 2531*f169c0eaSGlenn Lagasse dd.find_in_BE = B_TRUE; 2532*f169c0eaSGlenn Lagasse 2533*f169c0eaSGlenn Lagasse for (i = 0; i < 2; i++) { 2534*f169c0eaSGlenn Lagasse 2535*f169c0eaSGlenn Lagasse if (zfs_iter_snapshots(zhp, be_demote_find_clone_callback, &dd) 2536*f169c0eaSGlenn Lagasse != 0) { 2537*f169c0eaSGlenn Lagasse be_print_err(gettext("be_demote_callback: " 2538*f169c0eaSGlenn Lagasse "failed to iterate snapshots for %s: %s\n"), 2539*f169c0eaSGlenn Lagasse zfs_get_name(zhp), libzfs_error_description(g_zfs)); 2540*f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 2541*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 2542*f169c0eaSGlenn Lagasse return (ret); 2543*f169c0eaSGlenn Lagasse } 2544*f169c0eaSGlenn Lagasse if (dd.clone_zhp != NULL) { 2545*f169c0eaSGlenn Lagasse /* Found the clone to promote. Promote it. */ 2546*f169c0eaSGlenn Lagasse if (zfs_promote(dd.clone_zhp) != 0) { 2547*f169c0eaSGlenn Lagasse be_print_err(gettext("be_demote_callback: " 2548*f169c0eaSGlenn Lagasse "failed to promote %s: %s\n"), 2549*f169c0eaSGlenn Lagasse zfs_get_name(dd.clone_zhp), 2550*f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 2551*f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 2552*f169c0eaSGlenn Lagasse ZFS_CLOSE(dd.clone_zhp); 2553*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 2554*f169c0eaSGlenn Lagasse return (ret); 2555*f169c0eaSGlenn Lagasse } 2556*f169c0eaSGlenn Lagasse 2557*f169c0eaSGlenn Lagasse ZFS_CLOSE(dd.clone_zhp); 2558*f169c0eaSGlenn Lagasse } 2559*f169c0eaSGlenn Lagasse 2560*f169c0eaSGlenn Lagasse /* 2561*f169c0eaSGlenn Lagasse * Reinitialize be_demote_data for the second pass. 2562*f169c0eaSGlenn Lagasse * This will find a user created clone outside of any BE 2563*f169c0eaSGlenn Lagasse * namespace, if one exists. 2564*f169c0eaSGlenn Lagasse */ 2565*f169c0eaSGlenn Lagasse dd.clone_zhp = NULL; 2566*f169c0eaSGlenn Lagasse dd.origin_creation = 0; 2567*f169c0eaSGlenn Lagasse dd.snapshot = NULL; 2568*f169c0eaSGlenn Lagasse dd.find_in_BE = B_FALSE; 2569*f169c0eaSGlenn Lagasse } 2570*f169c0eaSGlenn Lagasse 2571*f169c0eaSGlenn Lagasse /* Iterate down this file system's children and demote them */ 2572*f169c0eaSGlenn Lagasse if ((ret = zfs_iter_filesystems(zhp, be_demote_callback, NULL)) != 0) { 2573*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 2574*f169c0eaSGlenn Lagasse return (ret); 2575*f169c0eaSGlenn Lagasse } 2576*f169c0eaSGlenn Lagasse 2577*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 2578*f169c0eaSGlenn Lagasse return (0); 2579*f169c0eaSGlenn Lagasse } 2580*f169c0eaSGlenn Lagasse 2581*f169c0eaSGlenn Lagasse /* 2582*f169c0eaSGlenn Lagasse * Function: be_demote_find_clone_callback 2583*f169c0eaSGlenn Lagasse * Description: This callback function is used to iterate through the 2584*f169c0eaSGlenn Lagasse * snapshots of a dataset, looking for the youngest snapshot 2585*f169c0eaSGlenn Lagasse * that has a clone. If found, it returns a reference to the 2586*f169c0eaSGlenn Lagasse * clone back to the caller in the callback data. 2587*f169c0eaSGlenn Lagasse * Parameters: 2588*f169c0eaSGlenn Lagasse * zhp - zfs_handle_t pointer to current snapshot being looked at 2589*f169c0eaSGlenn Lagasse * data - be_demote_data_t pointer used to store the clone that 2590*f169c0eaSGlenn Lagasse * is found. 2591*f169c0eaSGlenn Lagasse * Returns: 2592*f169c0eaSGlenn Lagasse * 0 - Successfully iterated through all snapshots. 2593*f169c0eaSGlenn Lagasse * 1 - Failed to iterate through all snapshots. 2594*f169c0eaSGlenn Lagasse * Scope: 2595*f169c0eaSGlenn Lagasse * Private 2596*f169c0eaSGlenn Lagasse */ 2597*f169c0eaSGlenn Lagasse static int 2598*f169c0eaSGlenn Lagasse be_demote_find_clone_callback(zfs_handle_t *zhp, void *data) 2599*f169c0eaSGlenn Lagasse { 2600*f169c0eaSGlenn Lagasse be_demote_data_t *dd = data; 2601*f169c0eaSGlenn Lagasse time_t snap_creation; 2602*f169c0eaSGlenn Lagasse int zret = 0; 2603*f169c0eaSGlenn Lagasse 2604*f169c0eaSGlenn Lagasse /* If snapshot has no clones, no need to look at it */ 2605*f169c0eaSGlenn Lagasse if (zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES) == 0) { 2606*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 2607*f169c0eaSGlenn Lagasse return (0); 2608*f169c0eaSGlenn Lagasse } 2609*f169c0eaSGlenn Lagasse 2610*f169c0eaSGlenn Lagasse dd->snapshot = zfs_get_name(zhp); 2611*f169c0eaSGlenn Lagasse 2612*f169c0eaSGlenn Lagasse /* Get the creation time of this snapshot */ 2613*f169c0eaSGlenn Lagasse snap_creation = (time_t)zfs_prop_get_int(zhp, ZFS_PROP_CREATION); 2614*f169c0eaSGlenn Lagasse 2615*f169c0eaSGlenn Lagasse /* 2616*f169c0eaSGlenn Lagasse * If this snapshot's creation time is greater than (or younger than) 2617*f169c0eaSGlenn Lagasse * the current youngest snapshot found, iterate this snapshot to 2618*f169c0eaSGlenn Lagasse * check if it has a clone that we're looking for. 2619*f169c0eaSGlenn Lagasse */ 2620*f169c0eaSGlenn Lagasse if (snap_creation >= dd->origin_creation) { 2621*f169c0eaSGlenn Lagasse /* 2622*f169c0eaSGlenn Lagasse * Iterate the dependents of this snapshot to find a 2623*f169c0eaSGlenn Lagasse * a clone that's a direct dependent. 2624*f169c0eaSGlenn Lagasse */ 2625*f169c0eaSGlenn Lagasse if ((zret = zfs_iter_dependents(zhp, B_FALSE, 2626*f169c0eaSGlenn Lagasse be_demote_get_one_clone, dd)) == -1) { 2627*f169c0eaSGlenn Lagasse be_print_err(gettext("be_demote_find_clone_callback: " 2628*f169c0eaSGlenn Lagasse "failed to iterate dependents of %s\n"), 2629*f169c0eaSGlenn Lagasse zfs_get_name(zhp)); 2630*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 2631*f169c0eaSGlenn Lagasse return (1); 2632*f169c0eaSGlenn Lagasse } else if (zret == 1) { 2633*f169c0eaSGlenn Lagasse /* 2634*f169c0eaSGlenn Lagasse * Found a clone, update the origin_creation time 2635*f169c0eaSGlenn Lagasse * in the callback data. 2636*f169c0eaSGlenn Lagasse */ 2637*f169c0eaSGlenn Lagasse dd->origin_creation = snap_creation; 2638*f169c0eaSGlenn Lagasse } 2639*f169c0eaSGlenn Lagasse } 2640*f169c0eaSGlenn Lagasse 2641*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 2642*f169c0eaSGlenn Lagasse return (0); 2643*f169c0eaSGlenn Lagasse } 2644*f169c0eaSGlenn Lagasse 2645*f169c0eaSGlenn Lagasse /* 2646*f169c0eaSGlenn Lagasse * Function: be_demote_get_one_clone 2647*f169c0eaSGlenn Lagasse * Description: This callback function is used to iterate through a 2648*f169c0eaSGlenn Lagasse * snapshot's dependencies to find a filesystem that is a 2649*f169c0eaSGlenn Lagasse * direct clone of the snapshot being iterated. 2650*f169c0eaSGlenn Lagasse * Parameters: 2651*f169c0eaSGlenn Lagasse * zhp - zfs_handle_t pointer to current dataset being looked at 2652*f169c0eaSGlenn Lagasse * data - be_demote_data_t pointer used to store the clone 2653*f169c0eaSGlenn Lagasse * that is found, and also provides flag to note 2654*f169c0eaSGlenn Lagasse * whether or not the clone filesystem being searched 2655*f169c0eaSGlenn Lagasse * for needs to be found in a BE dataset hierarchy. 2656*f169c0eaSGlenn Lagasse * Return: 2657*f169c0eaSGlenn Lagasse * 1 - Success, found clone and its also a BE's root dataset. 2658*f169c0eaSGlenn Lagasse * 0 - Failure, clone not found. 2659*f169c0eaSGlenn Lagasse * Scope: 2660*f169c0eaSGlenn Lagasse * Private 2661*f169c0eaSGlenn Lagasse */ 2662*f169c0eaSGlenn Lagasse static int 2663*f169c0eaSGlenn Lagasse be_demote_get_one_clone(zfs_handle_t *zhp, void *data) 2664*f169c0eaSGlenn Lagasse { 2665*f169c0eaSGlenn Lagasse be_demote_data_t *dd = data; 2666*f169c0eaSGlenn Lagasse char origin[ZFS_MAXNAMELEN]; 2667*f169c0eaSGlenn Lagasse char ds_path[ZFS_MAXNAMELEN]; 2668*f169c0eaSGlenn Lagasse 2669*f169c0eaSGlenn Lagasse if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) { 2670*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 2671*f169c0eaSGlenn Lagasse return (0); 2672*f169c0eaSGlenn Lagasse } 2673*f169c0eaSGlenn Lagasse 2674*f169c0eaSGlenn Lagasse (void) strlcpy(ds_path, zfs_get_name(zhp), sizeof (ds_path)); 2675*f169c0eaSGlenn Lagasse 2676*f169c0eaSGlenn Lagasse /* 2677*f169c0eaSGlenn Lagasse * Make sure this is a direct clone of the snapshot 2678*f169c0eaSGlenn Lagasse * we're iterating. 2679*f169c0eaSGlenn Lagasse */ 2680*f169c0eaSGlenn Lagasse if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin, sizeof (origin), NULL, 2681*f169c0eaSGlenn Lagasse NULL, 0, B_FALSE) != 0) { 2682*f169c0eaSGlenn Lagasse be_print_err(gettext("be_demote_get_one_clone: " 2683*f169c0eaSGlenn Lagasse "failed to get origin of %s: %s\n"), ds_path, 2684*f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 2685*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 2686*f169c0eaSGlenn Lagasse return (0); 2687*f169c0eaSGlenn Lagasse } 2688*f169c0eaSGlenn Lagasse if (strcmp(origin, dd->snapshot) != 0) { 2689*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 2690*f169c0eaSGlenn Lagasse return (0); 2691*f169c0eaSGlenn Lagasse } 2692*f169c0eaSGlenn Lagasse 2693*f169c0eaSGlenn Lagasse if (dd->find_in_BE) { 2694*f169c0eaSGlenn Lagasse if ((zpool_iter(g_zfs, be_check_be_roots_callback, ds_path)) 2695*f169c0eaSGlenn Lagasse > 0) { 2696*f169c0eaSGlenn Lagasse if (dd->clone_zhp != NULL) 2697*f169c0eaSGlenn Lagasse ZFS_CLOSE(dd->clone_zhp); 2698*f169c0eaSGlenn Lagasse dd->clone_zhp = zhp; 2699*f169c0eaSGlenn Lagasse return (1); 2700*f169c0eaSGlenn Lagasse } 2701*f169c0eaSGlenn Lagasse 2702*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 2703*f169c0eaSGlenn Lagasse return (0); 2704*f169c0eaSGlenn Lagasse } 2705*f169c0eaSGlenn Lagasse 2706*f169c0eaSGlenn Lagasse if (dd->clone_zhp != NULL) 2707*f169c0eaSGlenn Lagasse ZFS_CLOSE(dd->clone_zhp); 2708*f169c0eaSGlenn Lagasse 2709*f169c0eaSGlenn Lagasse dd->clone_zhp = zhp; 2710*f169c0eaSGlenn Lagasse return (1); 2711*f169c0eaSGlenn Lagasse } 2712*f169c0eaSGlenn Lagasse 2713*f169c0eaSGlenn Lagasse /* 2714*f169c0eaSGlenn Lagasse * Function: be_get_snap 2715*f169c0eaSGlenn Lagasse * Description: This function takes a snapshot dataset name and separates 2716*f169c0eaSGlenn Lagasse * out the parent dataset portion from the snapshot name. 2717*f169c0eaSGlenn Lagasse * I.e. it finds the '@' in the snapshot dataset name and 2718*f169c0eaSGlenn Lagasse * replaces it with a '\0'. 2719*f169c0eaSGlenn Lagasse * Parameters: 2720*f169c0eaSGlenn Lagasse * origin - char pointer to a snapshot dataset name. Its 2721*f169c0eaSGlenn Lagasse * contents will be modified by this function. 2722*f169c0eaSGlenn Lagasse * *snap - pointer to a char pointer. Will be set to the 2723*f169c0eaSGlenn Lagasse * snapshot name portion upon success. 2724*f169c0eaSGlenn Lagasse * Return: 2725*f169c0eaSGlenn Lagasse * BE_SUCCESS - Success 2726*f169c0eaSGlenn Lagasse * 1 - Failure 2727*f169c0eaSGlenn Lagasse * Scope: 2728*f169c0eaSGlenn Lagasse * Private 2729*f169c0eaSGlenn Lagasse */ 2730*f169c0eaSGlenn Lagasse static int 2731*f169c0eaSGlenn Lagasse be_get_snap(char *origin, char **snap) 2732*f169c0eaSGlenn Lagasse { 2733*f169c0eaSGlenn Lagasse char *cp; 2734*f169c0eaSGlenn Lagasse 2735*f169c0eaSGlenn Lagasse /* 2736*f169c0eaSGlenn Lagasse * Separate out the origin's dataset and snapshot portions by 2737*f169c0eaSGlenn Lagasse * replacing the @ with a '\0' 2738*f169c0eaSGlenn Lagasse */ 2739*f169c0eaSGlenn Lagasse cp = strrchr(origin, '@'); 2740*f169c0eaSGlenn Lagasse if (cp != NULL) { 2741*f169c0eaSGlenn Lagasse if (cp[1] != NULL && cp[1] != '\0') { 2742*f169c0eaSGlenn Lagasse cp[0] = '\0'; 2743*f169c0eaSGlenn Lagasse *snap = cp+1; 2744*f169c0eaSGlenn Lagasse } else { 2745*f169c0eaSGlenn Lagasse return (1); 2746*f169c0eaSGlenn Lagasse } 2747*f169c0eaSGlenn Lagasse } else { 2748*f169c0eaSGlenn Lagasse return (1); 2749*f169c0eaSGlenn Lagasse } 2750*f169c0eaSGlenn Lagasse 2751*f169c0eaSGlenn Lagasse return (BE_SUCCESS); 2752*f169c0eaSGlenn Lagasse } 2753*f169c0eaSGlenn Lagasse 2754*f169c0eaSGlenn Lagasse /* 2755*f169c0eaSGlenn Lagasse * Function: be_create_container_ds 2756*f169c0eaSGlenn Lagasse * Description: This function checks that the zpool passed has the BE 2757*f169c0eaSGlenn Lagasse * container dataset, and if not, then creates it. 2758*f169c0eaSGlenn Lagasse * Parameters: 2759*f169c0eaSGlenn Lagasse * zpool - name of pool to create BE container dataset in. 2760*f169c0eaSGlenn Lagasse * Return: 2761*f169c0eaSGlenn Lagasse * B_TRUE - Successfully created BE container dataset, or it 2762*f169c0eaSGlenn Lagasse * already existed. 2763*f169c0eaSGlenn Lagasse * B_FALSE - Failed to create container dataset. 2764*f169c0eaSGlenn Lagasse * Scope: 2765*f169c0eaSGlenn Lagasse * Private 2766*f169c0eaSGlenn Lagasse */ 2767*f169c0eaSGlenn Lagasse static boolean_t 2768*f169c0eaSGlenn Lagasse be_create_container_ds(char *zpool) 2769*f169c0eaSGlenn Lagasse { 2770*f169c0eaSGlenn Lagasse nvlist_t *props = NULL; 2771*f169c0eaSGlenn Lagasse char be_container_ds[MAXPATHLEN]; 2772*f169c0eaSGlenn Lagasse 2773*f169c0eaSGlenn Lagasse /* Generate string for BE container dataset for this pool */ 2774*f169c0eaSGlenn Lagasse be_make_container_ds(zpool, be_container_ds, 2775*f169c0eaSGlenn Lagasse sizeof (be_container_ds)); 2776*f169c0eaSGlenn Lagasse 2777*f169c0eaSGlenn Lagasse if (!zfs_dataset_exists(g_zfs, be_container_ds, ZFS_TYPE_FILESYSTEM)) { 2778*f169c0eaSGlenn Lagasse 2779*f169c0eaSGlenn Lagasse if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) { 2780*f169c0eaSGlenn Lagasse be_print_err(gettext("be_create_container_ds: " 2781*f169c0eaSGlenn Lagasse "nvlist_alloc failed\n")); 2782*f169c0eaSGlenn Lagasse return (B_FALSE); 2783*f169c0eaSGlenn Lagasse } 2784*f169c0eaSGlenn Lagasse 2785*f169c0eaSGlenn Lagasse if (nvlist_add_string(props, 2786*f169c0eaSGlenn Lagasse zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), 2787*f169c0eaSGlenn Lagasse ZFS_MOUNTPOINT_LEGACY) != 0) { 2788*f169c0eaSGlenn Lagasse be_print_err(gettext("be_create_container_ds: " 2789*f169c0eaSGlenn Lagasse "internal error: out of memory\n")); 2790*f169c0eaSGlenn Lagasse nvlist_free(props); 2791*f169c0eaSGlenn Lagasse return (B_FALSE); 2792*f169c0eaSGlenn Lagasse } 2793*f169c0eaSGlenn Lagasse 2794*f169c0eaSGlenn Lagasse if (nvlist_add_string(props, 2795*f169c0eaSGlenn Lagasse zfs_prop_to_name(ZFS_PROP_CANMOUNT), "off") != 0) { 2796*f169c0eaSGlenn Lagasse be_print_err(gettext("be_create_container_ds: " 2797*f169c0eaSGlenn Lagasse "internal error: out of memory\n")); 2798*f169c0eaSGlenn Lagasse nvlist_free(props); 2799*f169c0eaSGlenn Lagasse return (B_FALSE); 2800*f169c0eaSGlenn Lagasse } 2801*f169c0eaSGlenn Lagasse 2802*f169c0eaSGlenn Lagasse if (zfs_create(g_zfs, be_container_ds, ZFS_TYPE_FILESYSTEM, 2803*f169c0eaSGlenn Lagasse props) != 0) { 2804*f169c0eaSGlenn Lagasse be_print_err(gettext("be_create_container_ds: " 2805*f169c0eaSGlenn Lagasse "failed to create container dataset (%s): %s\n"), 2806*f169c0eaSGlenn Lagasse be_container_ds, libzfs_error_description(g_zfs)); 2807*f169c0eaSGlenn Lagasse nvlist_free(props); 2808*f169c0eaSGlenn Lagasse return (B_FALSE); 2809*f169c0eaSGlenn Lagasse } 2810*f169c0eaSGlenn Lagasse 2811*f169c0eaSGlenn Lagasse nvlist_free(props); 2812*f169c0eaSGlenn Lagasse } 2813*f169c0eaSGlenn Lagasse 2814*f169c0eaSGlenn Lagasse return (B_TRUE); 2815*f169c0eaSGlenn Lagasse } 2816*f169c0eaSGlenn Lagasse 2817*f169c0eaSGlenn Lagasse /* 2818*f169c0eaSGlenn Lagasse * Function: be_prep_clone_send_fs 2819*f169c0eaSGlenn Lagasse * Description: This function takes a zfs handle to a dataset from the 2820*f169c0eaSGlenn Lagasse * original BE, and generates the name of the clone dataset 2821*f169c0eaSGlenn Lagasse * to create for the new BE. It also prepares the zfs 2822*f169c0eaSGlenn Lagasse * properties to be used for the new BE. 2823*f169c0eaSGlenn Lagasse * Parameters: 2824*f169c0eaSGlenn Lagasse * zhp - pointer to zfs_handle_t of the file system being 2825*f169c0eaSGlenn Lagasse * cloned/copied. 2826*f169c0eaSGlenn Lagasse * bt - be_transaction_data pointer providing information 2827*f169c0eaSGlenn Lagasse * about the original BE and new BE. 2828*f169c0eaSGlenn Lagasse * clone_ds - buffer to store the name of the dataset 2829*f169c0eaSGlenn Lagasse * for the new BE. 2830*f169c0eaSGlenn Lagasse * clone_ds_len - length of clone_ds buffer 2831*f169c0eaSGlenn Lagasse * Return: 2832*f169c0eaSGlenn Lagasse * BE_SUCCESS - Success 2833*f169c0eaSGlenn Lagasse * be_errno_t - Failure 2834*f169c0eaSGlenn Lagasse * Scope: 2835*f169c0eaSGlenn Lagasse * Private 2836*f169c0eaSGlenn Lagasse */ 2837*f169c0eaSGlenn Lagasse static int 2838*f169c0eaSGlenn Lagasse be_prep_clone_send_fs(zfs_handle_t *zhp, be_transaction_data_t *bt, 2839*f169c0eaSGlenn Lagasse char *clone_ds, int clone_ds_len) 2840*f169c0eaSGlenn Lagasse { 2841*f169c0eaSGlenn Lagasse zprop_source_t sourcetype; 2842*f169c0eaSGlenn Lagasse char source[ZFS_MAXNAMELEN]; 2843*f169c0eaSGlenn Lagasse char zhp_name[ZFS_MAXNAMELEN]; 2844*f169c0eaSGlenn Lagasse char mountpoint[MAXPATHLEN]; 2845*f169c0eaSGlenn Lagasse char *child_fs = NULL; 2846*f169c0eaSGlenn Lagasse char *zhp_mountpoint = NULL; 2847*f169c0eaSGlenn Lagasse int err = 0; 2848*f169c0eaSGlenn Lagasse 2849*f169c0eaSGlenn Lagasse /* 2850*f169c0eaSGlenn Lagasse * Get a copy of the dataset name zfs_name from zhp 2851*f169c0eaSGlenn Lagasse */ 2852*f169c0eaSGlenn Lagasse (void) strlcpy(zhp_name, zfs_get_name(zhp), sizeof (zhp_name)); 2853*f169c0eaSGlenn Lagasse 2854*f169c0eaSGlenn Lagasse /* 2855*f169c0eaSGlenn Lagasse * Get file system name relative to the root. 2856*f169c0eaSGlenn Lagasse */ 2857*f169c0eaSGlenn Lagasse if (strncmp(zhp_name, bt->obe_root_ds, strlen(bt->obe_root_ds)) 2858*f169c0eaSGlenn Lagasse == 0) { 2859*f169c0eaSGlenn Lagasse child_fs = zhp_name + strlen(bt->obe_root_ds); 2860*f169c0eaSGlenn Lagasse 2861*f169c0eaSGlenn Lagasse /* 2862*f169c0eaSGlenn Lagasse * if child_fs is NULL, this means we're processing the 2863*f169c0eaSGlenn Lagasse * root dataset itself; set child_fs to the empty string. 2864*f169c0eaSGlenn Lagasse */ 2865*f169c0eaSGlenn Lagasse if (child_fs == NULL) 2866*f169c0eaSGlenn Lagasse child_fs = ""; 2867*f169c0eaSGlenn Lagasse } else { 2868*f169c0eaSGlenn Lagasse return (BE_ERR_INVAL); 2869*f169c0eaSGlenn Lagasse } 2870*f169c0eaSGlenn Lagasse 2871*f169c0eaSGlenn Lagasse /* 2872*f169c0eaSGlenn Lagasse * Generate the name of the clone file system. 2873*f169c0eaSGlenn Lagasse */ 2874*f169c0eaSGlenn Lagasse (void) snprintf(clone_ds, clone_ds_len, "%s%s", bt->nbe_root_ds, 2875*f169c0eaSGlenn Lagasse child_fs); 2876*f169c0eaSGlenn Lagasse 2877*f169c0eaSGlenn Lagasse /* Get the mountpoint and source properties of the existing dataset */ 2878*f169c0eaSGlenn Lagasse if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint, 2879*f169c0eaSGlenn Lagasse sizeof (mountpoint), &sourcetype, source, sizeof (source), 2880*f169c0eaSGlenn Lagasse B_FALSE) != 0) { 2881*f169c0eaSGlenn Lagasse be_print_err(gettext("be_prep_clone_send_fs: " 2882*f169c0eaSGlenn Lagasse "failed to get mountpoint for (%s): %s\n"), 2883*f169c0eaSGlenn Lagasse zhp_name, libzfs_error_description(g_zfs)); 2884*f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs)); 2885*f169c0eaSGlenn Lagasse } 2886*f169c0eaSGlenn Lagasse 2887*f169c0eaSGlenn Lagasse /* 2888*f169c0eaSGlenn Lagasse * Workaround for 6668667 where a mountpoint property of "/" comes 2889*f169c0eaSGlenn Lagasse * back as "". 2890*f169c0eaSGlenn Lagasse */ 2891*f169c0eaSGlenn Lagasse if (strcmp(mountpoint, "") == 0) { 2892*f169c0eaSGlenn Lagasse (void) snprintf(mountpoint, sizeof (mountpoint), "/"); 2893*f169c0eaSGlenn Lagasse } 2894*f169c0eaSGlenn Lagasse 2895*f169c0eaSGlenn Lagasse /* 2896*f169c0eaSGlenn Lagasse * Figure out what to set as the mountpoint for the new dataset. 2897*f169c0eaSGlenn Lagasse * If the source of the mountpoint property is local, use the 2898*f169c0eaSGlenn Lagasse * mountpoint value itself. Otherwise, remove it from the 2899*f169c0eaSGlenn Lagasse * zfs properties list so that it gets inherited. 2900*f169c0eaSGlenn Lagasse */ 2901*f169c0eaSGlenn Lagasse if (sourcetype & ZPROP_SRC_LOCAL) { 2902*f169c0eaSGlenn Lagasse /* 2903*f169c0eaSGlenn Lagasse * If the BE that this file system is a part of is 2904*f169c0eaSGlenn Lagasse * currently mounted, strip off the BE altroot portion 2905*f169c0eaSGlenn Lagasse * from the mountpoint. 2906*f169c0eaSGlenn Lagasse */ 2907*f169c0eaSGlenn Lagasse zhp_mountpoint = mountpoint; 2908*f169c0eaSGlenn Lagasse 2909*f169c0eaSGlenn Lagasse if (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 && 2910*f169c0eaSGlenn Lagasse bt->obe_altroot != NULL && strcmp(bt->obe_altroot, 2911*f169c0eaSGlenn Lagasse "/") != 0 && zfs_is_mounted(zhp, NULL)) { 2912*f169c0eaSGlenn Lagasse 2913*f169c0eaSGlenn Lagasse int altroot_len = strlen(bt->obe_altroot); 2914*f169c0eaSGlenn Lagasse 2915*f169c0eaSGlenn Lagasse if (strncmp(bt->obe_altroot, mountpoint, altroot_len) 2916*f169c0eaSGlenn Lagasse == 0) { 2917*f169c0eaSGlenn Lagasse if (mountpoint[altroot_len] == '/') 2918*f169c0eaSGlenn Lagasse zhp_mountpoint = mountpoint + 2919*f169c0eaSGlenn Lagasse altroot_len; 2920*f169c0eaSGlenn Lagasse else if (mountpoint[altroot_len] == '\0') 2921*f169c0eaSGlenn Lagasse (void) snprintf(mountpoint, 2922*f169c0eaSGlenn Lagasse sizeof (mountpoint), "/"); 2923*f169c0eaSGlenn Lagasse } 2924*f169c0eaSGlenn Lagasse } 2925*f169c0eaSGlenn Lagasse 2926*f169c0eaSGlenn Lagasse if (nvlist_add_string(bt->nbe_zfs_props, 2927*f169c0eaSGlenn Lagasse zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), 2928*f169c0eaSGlenn Lagasse zhp_mountpoint) != 0) { 2929*f169c0eaSGlenn Lagasse be_print_err(gettext("be_prep_clone_send_fs: " 2930*f169c0eaSGlenn Lagasse "internal error: out of memory\n")); 2931*f169c0eaSGlenn Lagasse return (BE_ERR_NOMEM); 2932*f169c0eaSGlenn Lagasse } 2933*f169c0eaSGlenn Lagasse } else { 2934*f169c0eaSGlenn Lagasse err = nvlist_remove_all(bt->nbe_zfs_props, 2935*f169c0eaSGlenn Lagasse zfs_prop_to_name(ZFS_PROP_MOUNTPOINT)); 2936*f169c0eaSGlenn Lagasse if (err != 0 && err != ENOENT) { 2937*f169c0eaSGlenn Lagasse be_print_err(gettext("be_prep_clone_send_fs: " 2938*f169c0eaSGlenn Lagasse "failed to remove mountpoint from " 2939*f169c0eaSGlenn Lagasse "nvlist\n")); 2940*f169c0eaSGlenn Lagasse return (BE_ERR_INVAL); 2941*f169c0eaSGlenn Lagasse } 2942*f169c0eaSGlenn Lagasse } 2943*f169c0eaSGlenn Lagasse 2944*f169c0eaSGlenn Lagasse /* 2945*f169c0eaSGlenn Lagasse * Set the 'canmount' property 2946*f169c0eaSGlenn Lagasse */ 2947*f169c0eaSGlenn Lagasse if (nvlist_add_string(bt->nbe_zfs_props, 2948*f169c0eaSGlenn Lagasse zfs_prop_to_name(ZFS_PROP_CANMOUNT), "noauto") != 0) { 2949*f169c0eaSGlenn Lagasse be_print_err(gettext("be_prep_clone_send_fs: " 2950*f169c0eaSGlenn Lagasse "internal error: out of memory\n")); 2951*f169c0eaSGlenn Lagasse return (BE_ERR_NOMEM); 2952*f169c0eaSGlenn Lagasse } 2953*f169c0eaSGlenn Lagasse 2954*f169c0eaSGlenn Lagasse return (BE_SUCCESS); 2955*f169c0eaSGlenn Lagasse } 2956*f169c0eaSGlenn Lagasse 2957*f169c0eaSGlenn Lagasse /* 2958*f169c0eaSGlenn Lagasse * Function: be_get_zone_be_name 2959*f169c0eaSGlenn Lagasse * Description: This function takes the zones root dataset, the container 2960*f169c0eaSGlenn Lagasse * dataset and returns the zones BE name based on the zone 2961*f169c0eaSGlenn Lagasse * root dataset. 2962*f169c0eaSGlenn Lagasse * Parameters: 2963*f169c0eaSGlenn Lagasse * root_ds - the zones root dataset. 2964*f169c0eaSGlenn Lagasse * container_ds - the container dataset for the zone. 2965*f169c0eaSGlenn Lagasse * Returns: 2966*f169c0eaSGlenn Lagasse * char * - the BE name of this zone based on the root dataset. 2967*f169c0eaSGlenn Lagasse */ 2968*f169c0eaSGlenn Lagasse static char * 2969*f169c0eaSGlenn Lagasse be_get_zone_be_name(char *root_ds, char *container_ds) 2970*f169c0eaSGlenn Lagasse { 2971*f169c0eaSGlenn Lagasse return (root_ds + (strlen(container_ds) + 1)); 2972*f169c0eaSGlenn Lagasse } 2973*f169c0eaSGlenn Lagasse 2974*f169c0eaSGlenn Lagasse /* 2975*f169c0eaSGlenn Lagasse * Function: be_zone_root_exists_callback 2976*f169c0eaSGlenn Lagasse * Description: This callback function is used to determine if a 2977*f169c0eaSGlenn Lagasse * zone root container dataset has any children. It always 2978*f169c0eaSGlenn Lagasse * returns 1, signifying a hierarchical child of the zone 2979*f169c0eaSGlenn Lagasse * root container dataset has been traversed and therefore 2980*f169c0eaSGlenn Lagasse * it has children. 2981*f169c0eaSGlenn Lagasse * Parameters: 2982*f169c0eaSGlenn Lagasse * zhp - zfs_handle_t pointer to current dataset being processed. 2983*f169c0eaSGlenn Lagasse * data - not used. 2984*f169c0eaSGlenn Lagasse * Returns: 2985*f169c0eaSGlenn Lagasse * 1 - dataset exists 2986*f169c0eaSGlenn Lagasse * Scope: 2987*f169c0eaSGlenn Lagasse * Private 2988*f169c0eaSGlenn Lagasse */ 2989*f169c0eaSGlenn Lagasse static int 2990*f169c0eaSGlenn Lagasse /* LINTED */ 2991*f169c0eaSGlenn Lagasse be_zone_root_exists_callback(zfs_handle_t *zhp, void *data) 2992*f169c0eaSGlenn Lagasse { 2993*f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 2994*f169c0eaSGlenn Lagasse return (1); 2995*f169c0eaSGlenn Lagasse } 2996