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