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