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