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