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