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