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