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.
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.
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]
23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
26 * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
30 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
31 * Copyright 2016 Toomas Soome <tsoome@me.com>
36 #include <libnvpair.h>
43 #include <sys/mnttab.h>
44 #include <sys/types.h>
48 #include <sys/efi_partition.h>
51 #include <libbe_priv.h>
53 char *mnttab
= MNTTAB
;
56 * Private function prototypes
58 static int set_bootfs(char *boot_rpool
, char *be_root_ds
);
59 static int set_canmount(be_node_list_t
*, char *);
60 static boolean_t
be_do_install_mbr(char *, nvlist_t
*);
61 static int be_do_installboot_helper(zpool_handle_t
*, nvlist_t
*, char *,
63 static int be_do_installboot(be_transaction_data_t
*, uint16_t);
64 static int be_promote_zone_ds(char *, char *);
65 static int be_promote_ds_callback(zfs_handle_t
*, void *);
67 /* ******************************************************************** */
68 /* Public Functions */
69 /* ******************************************************************** */
72 * Function: be_activate
73 * Description: Calls _be_activate which activates the BE named in the
74 * attributes passed in through be_attrs. The process of
75 * activation sets the bootfs property of the root pool, resets
76 * the canmount property to noauto, and sets the default in the
77 * menu to the entry corresponding to the entry for the named BE.
79 * be_attrs - pointer to nvlist_t of attributes being passed in.
80 * The follow attribute values are used by this function:
82 * BE_ATTR_ORIG_BE_NAME *required
84 * BE_SUCCESS - Success
85 * be_errno_t - Failure
90 be_activate(nvlist_t
*be_attrs
)
95 /* Initialize libzfs handle */
99 /* Get the BE name to activate */
100 if (nvlist_lookup_string(be_attrs
, BE_ATTR_ORIG_BE_NAME
, &be_name
)
102 be_print_err(gettext("be_activate: failed to "
103 "lookup BE_ATTR_ORIG_BE_NAME attribute\n"));
105 return (BE_ERR_INVAL
);
108 /* Validate BE name */
109 if (!be_valid_be_name(be_name
)) {
110 be_print_err(gettext("be_activate: invalid BE name %s\n"),
113 return (BE_ERR_INVAL
);
116 ret
= _be_activate(be_name
);
124 * Function: be_installboot
125 * Description: Calls be_do_installboot to install/update bootloader on
126 * pool passed in through be_attrs. The primary consumer is
127 * bootadm command to avoid duplication of the code.
129 * be_attrs - pointer to nvlist_t of attributes being passed in.
130 * The following attribute values are used:
132 * BE_ATTR_ORIG_BE_NAME *required
133 * BE_ATTR_ORIG_BE_POOL *required
134 * BE_ATTR_ORIG_BE_ROOT *required
135 * BE_ATTR_INSTALL_FLAGS optional
138 * BE_SUCCESS - Success
139 * be_errno_t - Failure
144 be_installboot(nvlist_t
*be_attrs
)
146 int ret
= BE_SUCCESS
;
149 be_transaction_data_t bt
= { 0 };
152 if (nvlist_lookup_pairs(be_attrs
, NV_FLAG_NOENTOK
,
153 BE_ATTR_INSTALL_FLAGS
, DATA_TYPE_UINT16
, &flags
, NULL
) != 0) {
154 be_print_err(gettext("be_installboot: failed to lookup "
155 "BE_ATTR_INSTALL_FLAGS attribute\n"));
156 return (BE_ERR_INVAL
);
159 /* Set verbose early, so we get all messages */
160 verbose
= flags
& BE_INSTALLBOOT_FLAG_VERBOSE
;
161 if (verbose
== BE_INSTALLBOOT_FLAG_VERBOSE
)
162 libbe_print_errors(B_TRUE
);
164 ret
= nvlist_lookup_string(be_attrs
, BE_ATTR_ORIG_BE_NAME
,
167 be_print_err(gettext("be_installboot: failed to "
168 "lookup BE_ATTR_ORIG_BE_NAME attribute\n"));
169 return (BE_ERR_INVAL
);
172 ret
= nvlist_lookup_string(be_attrs
, BE_ATTR_ORIG_BE_POOL
,
175 be_print_err(gettext("be_installboot: failed to "
176 "lookup BE_ATTR_ORIG_BE_POOL attribute\n"));
177 return (BE_ERR_INVAL
);
180 ret
= nvlist_lookup_string(be_attrs
, BE_ATTR_ORIG_BE_ROOT
,
183 be_print_err(gettext("be_installboot: failed to "
184 "lookup BE_ATTR_ORIG_BE_ROOT attribute\n"));
185 return (BE_ERR_INVAL
);
188 /* Initialize libzfs handle */
190 return (BE_ERR_INIT
);
192 ret
= be_do_installboot(&bt
, flags
);
199 /* ******************************************************************** */
200 /* Semi Private Functions */
201 /* ******************************************************************** */
204 * Function: _be_activate
205 * Description: This does the actual work described in be_activate.
207 * be_name - pointer to the name of BE to activate.
210 * BE_SUCCESS - Success
211 * be_errnot_t - Failure
216 _be_activate(char *be_name
)
218 be_transaction_data_t cb
= { 0 };
219 zfs_handle_t
*zhp
= NULL
;
220 char root_ds
[MAXPATHLEN
];
221 char active_ds
[MAXPATHLEN
];
222 be_node_list_t
*be_nodes
= NULL
;
224 int entry
, ret
= BE_SUCCESS
;
228 * TODO: The BE needs to be validated to make sure that it is actually
233 return (BE_ERR_INVAL
);
235 /* Set obe_name to be_name in the cb structure */
236 cb
.obe_name
= be_name
;
238 /* find which zpool the be is in */
239 if ((zret
= zpool_iter(g_zfs
, be_find_zpool_callback
, &cb
)) == 0) {
240 be_print_err(gettext("be_activate: failed to "
241 "find zpool for BE (%s)\n"), cb
.obe_name
);
242 return (BE_ERR_BE_NOENT
);
243 } else if (zret
< 0) {
244 be_print_err(gettext("be_activate: "
245 "zpool_iter failed: %s\n"),
246 libzfs_error_description(g_zfs
));
247 ret
= zfs_err_to_be_err(g_zfs
);
251 be_make_root_ds(cb
.obe_zpool
, cb
.obe_name
, root_ds
, sizeof (root_ds
));
252 cb
.obe_root_ds
= strdup(root_ds
);
254 if (getzoneid() == GLOBAL_ZONEID
) {
255 ret
= be_do_installboot(&cb
, BE_INSTALLBOOT_FLAG_NULL
);
256 if (ret
!= BE_SUCCESS
)
259 if (!be_has_menu_entry(root_ds
, cb
.obe_zpool
, &entry
)) {
260 if ((ret
= be_append_menu(cb
.obe_name
, cb
.obe_zpool
,
261 NULL
, NULL
, NULL
)) != BE_SUCCESS
) {
262 be_print_err(gettext("be_activate: Failed to "
263 "add BE (%s) to the menu\n"),
270 if ((ret
= _be_list(cb
.obe_name
, &be_nodes
)) != BE_SUCCESS
) {
274 if ((ret
= set_canmount(be_nodes
, "noauto")) != BE_SUCCESS
) {
275 be_print_err(gettext("be_activate: failed to set "
276 "canmount dataset property\n"));
280 if (getzoneid() == GLOBAL_ZONEID
) {
281 if ((ret
= set_bootfs(be_nodes
->be_rpool
,
282 root_ds
)) != BE_SUCCESS
) {
283 be_print_err(gettext("be_activate: failed to set "
284 "bootfs pool property for %s\n"), root_ds
);
289 if ((zhp
= zfs_open(g_zfs
, root_ds
, ZFS_TYPE_FILESYSTEM
)) != NULL
) {
291 * We don't need to close the zfs handle at this
292 * point because The callback funtion
293 * be_promote_ds_callback() will close it for us.
295 if (be_promote_ds_callback(zhp
, NULL
) != 0) {
296 be_print_err(gettext("be_activate: "
297 "failed to activate the "
298 "datasets for %s: %s\n"),
300 libzfs_error_description(g_zfs
));
301 ret
= BE_ERR_PROMOTE
;
305 be_print_err(gettext("be_activate: failed to open "
306 "dataset (%s): %s\n"), root_ds
,
307 libzfs_error_description(g_zfs
));
308 ret
= zfs_err_to_be_err(g_zfs
);
312 if (getzoneid() == GLOBAL_ZONEID
&&
313 be_get_uuid(cb
.obe_root_ds
, &uu
) == BE_SUCCESS
&&
314 (ret
= be_promote_zone_ds(cb
.obe_name
, cb
.obe_root_ds
))
316 be_print_err(gettext("be_activate: failed to promote "
317 "the active zonepath datasets for zones in BE %s\n"),
321 if (getzoneid() != GLOBAL_ZONEID
) {
322 if (!be_zone_compare_uuids(root_ds
)) {
323 be_print_err(gettext("be_activate: activating zone "
324 "root dataset from non-active global BE is not "
329 if ((zhp
= zfs_open(g_zfs
, root_ds
,
330 ZFS_TYPE_FILESYSTEM
)) == NULL
) {
331 be_print_err(gettext("be_activate: failed to open "
332 "dataset (%s): %s\n"), root_ds
,
333 libzfs_error_description(g_zfs
));
334 ret
= zfs_err_to_be_err(g_zfs
);
337 /* Find current active zone root dataset */
338 if ((ret
= be_find_active_zone_root(zhp
, cb
.obe_zpool
,
339 active_ds
, sizeof (active_ds
))) != BE_SUCCESS
) {
340 be_print_err(gettext("be_activate: failed to find "
341 "active zone root dataset\n"));
345 /* Do nothing if requested BE is already active */
346 if (strcmp(root_ds
, active_ds
) == 0) {
352 /* Set active property for BE */
353 if (zfs_prop_set(zhp
, BE_ZONE_ACTIVE_PROPERTY
, "on") != 0) {
354 be_print_err(gettext("be_activate: failed to set "
355 "active property (%s): %s\n"), root_ds
,
356 libzfs_error_description(g_zfs
));
357 ret
= zfs_err_to_be_err(g_zfs
);
363 /* Unset active property for old active root dataset */
364 if ((zhp
= zfs_open(g_zfs
, active_ds
,
365 ZFS_TYPE_FILESYSTEM
)) == NULL
) {
366 be_print_err(gettext("be_activate: failed to open "
367 "dataset (%s): %s\n"), active_ds
,
368 libzfs_error_description(g_zfs
));
369 ret
= zfs_err_to_be_err(g_zfs
);
372 if (zfs_prop_set(zhp
, BE_ZONE_ACTIVE_PROPERTY
, "off") != 0) {
373 be_print_err(gettext("be_activate: failed to unset "
374 "active property (%s): %s\n"), active_ds
,
375 libzfs_error_description(g_zfs
));
376 ret
= zfs_err_to_be_err(g_zfs
);
383 be_free_list(be_nodes
);
388 * Function: be_activate_current_be
389 * Description: Set the currently "active" BE to be "active on boot"
393 * BE_SUCCESS - Success
394 * be_errnot_t - Failure
396 * Semi-private (library wide use only)
399 be_activate_current_be(void)
401 int ret
= BE_SUCCESS
;
402 be_transaction_data_t bt
= { 0 };
404 if ((ret
= be_find_current_be(&bt
)) != BE_SUCCESS
) {
408 if ((ret
= _be_activate(bt
.obe_name
)) != BE_SUCCESS
) {
409 be_print_err(gettext("be_activate_current_be: failed to "
410 "activate %s\n"), bt
.obe_name
);
418 * Function: be_is_active_on_boot
419 * Description: Checks if the BE name passed in has the "active on boot"
420 * property set to B_TRUE.
422 * be_name - the name of the BE to check
424 * B_TRUE - if active on boot.
425 * B_FALSE - if not active on boot.
427 * Semi-private (library wide use only)
430 be_is_active_on_boot(char *be_name
)
432 be_node_list_t
*be_node
= NULL
;
434 if (be_name
== NULL
) {
435 be_print_err(gettext("be_is_active_on_boot: "
436 "be_name must not be NULL\n"));
440 if (_be_list(be_name
, &be_node
) != BE_SUCCESS
) {
444 if (be_node
== NULL
) {
448 if (be_node
->be_active_on_boot
) {
449 be_free_list(be_node
);
452 be_free_list(be_node
);
457 /* ******************************************************************** */
458 /* Private Functions */
459 /* ******************************************************************** */
462 * Function: set_bootfs
463 * Description: Sets the bootfs property on the boot pool to be the
464 * root dataset of the activated BE.
466 * boot_pool - The pool we're setting bootfs in.
467 * be_root_ds - The main dataset for the BE.
469 * BE_SUCCESS - Success
470 * be_errno_t - Failure
475 set_bootfs(char *boot_rpool
, char *be_root_ds
)
478 int err
= BE_SUCCESS
;
480 if ((zhp
= zpool_open(g_zfs
, boot_rpool
)) == NULL
) {
481 be_print_err(gettext("set_bootfs: failed to open pool "
482 "(%s): %s\n"), boot_rpool
, libzfs_error_description(g_zfs
));
483 err
= zfs_err_to_be_err(g_zfs
);
487 err
= zpool_set_prop(zhp
, "bootfs", be_root_ds
);
489 be_print_err(gettext("set_bootfs: failed to set "
490 "bootfs property for pool %s: %s\n"), boot_rpool
,
491 libzfs_error_description(g_zfs
));
492 err
= zfs_err_to_be_err(g_zfs
);
502 * Function: set_canmount
503 * Description: Sets the canmount property on the datasets of the
506 * be_nodes - The be_node_t returned from be_list
507 * value - The value of canmount we setting, on|off|noauto.
509 * BE_SUCCESS - Success
510 * be_errno_t - Failure
515 set_canmount(be_node_list_t
*be_nodes
, char *value
)
517 char ds_path
[MAXPATHLEN
];
518 zfs_handle_t
*zhp
= NULL
;
519 be_node_list_t
*list
= be_nodes
;
520 int err
= BE_SUCCESS
;
522 while (list
!= NULL
) {
523 be_dataset_list_t
*datasets
= list
->be_node_datasets
;
525 be_make_root_ds(list
->be_rpool
, list
->be_node_name
, ds_path
,
528 if ((zhp
= zfs_open(g_zfs
, ds_path
, ZFS_TYPE_DATASET
)) ==
530 be_print_err(gettext("set_canmount: failed to open "
531 "dataset (%s): %s\n"), ds_path
,
532 libzfs_error_description(g_zfs
));
533 err
= zfs_err_to_be_err(g_zfs
);
536 if (zfs_prop_get_int(zhp
, ZFS_PROP_MOUNTED
)) {
538 * it's already mounted so we can't change the
539 * canmount property anyway.
543 err
= zfs_prop_set(zhp
,
544 zfs_prop_to_name(ZFS_PROP_CANMOUNT
), value
);
547 be_print_err(gettext("set_canmount: failed to "
548 "set dataset property (%s): %s\n"),
549 ds_path
, libzfs_error_description(g_zfs
));
550 err
= zfs_err_to_be_err(g_zfs
);
556 while (datasets
!= NULL
) {
557 be_make_root_ds(list
->be_rpool
,
558 datasets
->be_dataset_name
, ds_path
,
561 if ((zhp
= zfs_open(g_zfs
, ds_path
, ZFS_TYPE_DATASET
))
563 be_print_err(gettext("set_canmount: failed to "
564 "open dataset %s: %s\n"), ds_path
,
565 libzfs_error_description(g_zfs
));
566 err
= zfs_err_to_be_err(g_zfs
);
569 if (zfs_prop_get_int(zhp
, ZFS_PROP_MOUNTED
)) {
571 * it's already mounted so we can't change the
572 * canmount property anyway.
578 err
= zfs_prop_set(zhp
,
579 zfs_prop_to_name(ZFS_PROP_CANMOUNT
), value
);
582 be_print_err(gettext("set_canmount: "
583 "Failed to set property value %s "
584 "for dataset %s: %s\n"), value
, ds_path
,
585 libzfs_error_description(g_zfs
));
586 err
= zfs_err_to_be_err(g_zfs
);
590 datasets
= datasets
->be_next_dataset
;
592 list
= list
->be_next_node
;
598 * To be able to boot EFI labeled disks, stage1 needs to be written
599 * into the MBR. We do not do this if we're on disks with a traditional
600 * fdisk partition table only, or if any foreign EFI partitions exist.
601 * In the trivial case of a whole-disk vdev we always write stage1 into
605 be_do_install_mbr(char *diskname
, nvlist_t
*child
)
607 struct uuid allowed_uuids
[] = {
631 (void) nvlist_lookup_uint64(child
, ZPOOL_CONFIG_WHOLE_DISK
,
637 if ((fd
= open(diskname
, O_RDONLY
|O_NDELAY
)) < 0)
640 if ((npart
= efi_alloc_and_read(fd
, &gpt
)) <= 0)
643 for (i
= 0; i
!= npart
; i
++) {
646 u
= &gpt
->efi_parts
[i
].p_guid
;
649 j
!= sizeof (allowed_uuids
) / sizeof (struct uuid
);
651 if (bcmp(u
, &allowed_uuids
[j
],
652 sizeof (struct uuid
)) == 0)
663 be_do_installboot_helper(zpool_handle_t
*zphp
, nvlist_t
*child
, char *stage1
,
664 char *stage2
, uint16_t flags
)
666 char install_cmd
[MAXPATHLEN
];
667 char be_run_cmd_errbuf
[BUFSIZ
];
668 char be_run_cmd_outbuf
[BUFSIZ
];
669 char diskname
[MAXPATHLEN
];
671 char *path
, *dsk_ptr
;
677 if (nvlist_lookup_string(child
, ZPOOL_CONFIG_PATH
, &path
) != 0) {
678 be_print_err(gettext("be_do_installboot: "
679 "failed to get device path\n"));
680 return (BE_ERR_NODEV
);
683 if ((nvlist_lookup_uint64_array(child
, ZPOOL_CONFIG_VDEV_STATS
,
684 (uint64_t **)&vs
, &vsc
) != 0) ||
685 vs
->vs_state
< VDEV_STATE_DEGRADED
) {
687 * Don't try to run installboot on a vdev that is not ONLINE
688 * or DEGRADED. Try to print a warning for each such vdev.
690 be_print_err(gettext("be_do_installboot: "
691 "vdev %s is %s, can't install boot loader\n"),
692 path
, zpool_state_to_name(vs
->vs_state
, vs
->vs_aux
));
697 * Modify the vdev path to point to the raw disk.
701 return (BE_ERR_NOMEM
);
703 dsk_ptr
= strstr(path
, "/dsk/");
704 if (dsk_ptr
!= NULL
) {
711 (void) snprintf(diskname
, sizeof (diskname
), "%s/r%s", path
, dsk_ptr
);
714 vname
= zpool_vdev_name(g_zfs
, zphp
, child
, B_FALSE
);
716 be_print_err(gettext("be_do_installboot: "
717 "failed to get device name: %s\n"),
718 libzfs_error_description(g_zfs
));
719 return (zfs_err_to_be_err(g_zfs
));
722 if (be_is_isa("i386")) {
723 uint16_t force
= flags
& BE_INSTALLBOOT_FLAG_FORCE
;
724 uint16_t mbr
= flags
& BE_INSTALLBOOT_FLAG_MBR
;
726 if (force
== BE_INSTALLBOOT_FLAG_FORCE
) {
727 if (mbr
== BE_INSTALLBOOT_FLAG_MBR
||
728 be_do_install_mbr(diskname
, child
))
733 if (mbr
== BE_INSTALLBOOT_FLAG_MBR
||
734 be_do_install_mbr(diskname
, child
))
738 (void) snprintf(install_cmd
, sizeof (install_cmd
),
739 "%s %s %s %s %s", BE_INSTALL_BOOT
, flag
,
740 stage1
, stage2
, diskname
);
741 } else if (be_is_isa("sparc")) {
742 if ((flags
& BE_INSTALLBOOT_FLAG_FORCE
) ==
743 BE_INSTALLBOOT_FLAG_FORCE
)
748 (void) snprintf(install_cmd
, sizeof (install_cmd
),
749 "%s %s %s %s", BE_INSTALL_BOOT
, flag
, stage2
, diskname
);
751 be_print_err(gettext("be_do_installboot: unsupported "
753 return (BE_ERR_BOOTFILE_INST
);
756 *be_run_cmd_outbuf
= '\0';
757 *be_run_cmd_errbuf
= '\0';
759 ret
= be_run_cmd(install_cmd
, be_run_cmd_errbuf
, BUFSIZ
,
760 be_run_cmd_outbuf
, BUFSIZ
);
762 if (ret
!= BE_SUCCESS
) {
763 be_print_err(gettext("be_do_installboot: install "
764 "failed for device %s.\n"), vname
);
765 ret
= BE_ERR_BOOTFILE_INST
;
768 be_print_err(gettext(" Command: \"%s\"\n"), install_cmd
);
769 if (be_run_cmd_outbuf
[0] != 0) {
770 be_print_err(gettext(" Output:\n"));
771 be_print_err("%s", be_run_cmd_outbuf
);
774 if (be_run_cmd_errbuf
[0] != 0) {
775 be_print_err(gettext(" Errors:\n"));
776 be_print_err("%s", be_run_cmd_errbuf
);
784 * Function: be_do_installboot
785 * Description: This function runs installboot using the boot
786 * loader files from the BE we're activating and installing
787 * them on the pool the BE lives in.
790 * bt - The transaction data for the BE we're activating.
791 * flags - flags for bootloader install
793 * BE_SUCCESS - Success
794 * be_errno_t - Failure
800 be_do_installboot(be_transaction_data_t
*bt
, uint16_t flags
)
802 zpool_handle_t
*zphp
= NULL
;
803 zfs_handle_t
*zhp
= NULL
;
804 nvlist_t
**child
, *nv
, *config
;
805 uint_t c
, children
= 0;
806 char *tmp_mntpt
= NULL
;
807 char stage1
[MAXPATHLEN
];
808 char stage2
[MAXPATHLEN
];
810 int ret
= BE_SUCCESS
;
811 boolean_t be_mounted
= B_FALSE
;
812 boolean_t verbose
= B_FALSE
;
814 if ((zhp
= zfs_open(g_zfs
, bt
->obe_root_ds
, ZFS_TYPE_FILESYSTEM
)) ==
816 be_print_err(gettext("be_do_installboot: failed to "
817 "open BE root dataset (%s): %s\n"), bt
->obe_root_ds
,
818 libzfs_error_description(g_zfs
));
819 ret
= zfs_err_to_be_err(g_zfs
);
822 if (!zfs_is_mounted(zhp
, &tmp_mntpt
)) {
823 if ((ret
= _be_mount(bt
->obe_name
, &tmp_mntpt
,
824 BE_MOUNT_FLAG_NO_ZONES
)) != BE_SUCCESS
) {
825 be_print_err(gettext("be_do_installboot: failed to "
826 "mount BE (%s)\n"), bt
->obe_name
);
834 if (be_is_isa("i386")) {
835 (void) snprintf(stage1
, sizeof (stage1
), "%s%s",
836 tmp_mntpt
, BE_LOADER_STAGE_1
);
837 (void) snprintf(stage2
, sizeof (stage2
), "%s%s",
838 tmp_mntpt
, BE_LOADER_STAGE_2
);
839 } else if (be_is_isa("sparc")) {
840 char *platform
= be_get_platform();
842 if (platform
== NULL
) {
843 be_print_err(gettext("be_do_installboot: "
844 "failed to detect system platform name\n"));
846 (void) _be_unmount(bt
->obe_name
, 0);
848 return (BE_ERR_BOOTFILE_INST
);
850 stage1
[0] = '\0'; /* sparc has no stage1 */
851 (void) snprintf(stage2
, sizeof (stage2
),
852 "%s/usr/platform/%s%s", tmp_mntpt
,
853 platform
, BE_SPARC_BOOTBLK
);
855 be_print_err(gettext("be_do_installboot: unsupported "
857 return (BE_ERR_BOOTFILE_INST
);
860 if ((zphp
= zpool_open(g_zfs
, bt
->obe_zpool
)) == NULL
) {
861 be_print_err(gettext("be_do_installboot: failed to open "
862 "pool (%s): %s\n"), bt
->obe_zpool
,
863 libzfs_error_description(g_zfs
));
864 ret
= zfs_err_to_be_err(g_zfs
);
866 (void) _be_unmount(bt
->obe_name
, 0);
871 if ((config
= zpool_get_config(zphp
, NULL
)) == NULL
) {
872 be_print_err(gettext("be_do_installboot: failed to get zpool "
873 "configuration information. %s\n"),
874 libzfs_error_description(g_zfs
));
875 ret
= zfs_err_to_be_err(g_zfs
);
882 if (nvlist_lookup_nvlist(config
, ZPOOL_CONFIG_VDEV_TREE
, &nv
) != 0) {
883 be_print_err(gettext("be_do_installboot: failed to get vdev "
884 "tree: %s\n"), libzfs_error_description(g_zfs
));
885 ret
= zfs_err_to_be_err(g_zfs
);
889 if (nvlist_lookup_nvlist_array(nv
, ZPOOL_CONFIG_CHILDREN
, &child
,
891 be_print_err(gettext("be_do_installboot: failed to traverse "
892 "the vdev tree: %s\n"), libzfs_error_description(g_zfs
));
893 ret
= zfs_err_to_be_err(g_zfs
);
896 for (c
= 0; c
< children
; c
++) {
897 uint_t i
, nchildren
= 0;
900 /* ensure update on child status */
901 vname
= zpool_vdev_name(g_zfs
, zphp
, child
[c
], verbose
);
903 be_print_err(gettext(
904 "be_do_installboot: "
905 "failed to get device name: %s\n"),
906 libzfs_error_description(g_zfs
));
907 ret
= zfs_err_to_be_err(g_zfs
);
909 } else if (verbose
== B_TRUE
) {
910 be_print_err(gettext("be_do_installboot: "
911 "device %s\n"), vname
);
915 ret
= nvlist_lookup_nvlist_array(child
[c
],
916 ZPOOL_CONFIG_CHILDREN
, &nvchild
, &nchildren
);
919 be_print_err(gettext("be_do_installboot: "
920 "failed to traverse the vdev tree: %s\n"),
921 libzfs_error_description(g_zfs
));
922 ret
= zfs_err_to_be_err(g_zfs
);
925 nchildren
= 0; /* This is leaf device. */
928 if (nchildren
!= 0) {
929 for (i
= 0; i
< nchildren
; i
++) {
930 /* ensure update on child status */
931 vname
= zpool_vdev_name(g_zfs
, zphp
,
932 nvchild
[i
], verbose
);
934 be_print_err(gettext(
935 "be_do_installboot: "
936 "failed to get device name: %s\n"),
937 libzfs_error_description(g_zfs
));
938 ret
= zfs_err_to_be_err(g_zfs
);
940 } else if (verbose
== B_TRUE
) {
941 be_print_err(gettext(
942 "be_do_installboot: device %s\n"),
946 ret
= be_do_installboot_helper(zphp
, nvchild
[i
],
947 stage1
, stage2
, flags
);
948 if (ret
!= BE_SUCCESS
)
952 ret
= be_do_installboot_helper(zphp
, child
[c
], stage1
,
954 if (ret
!= BE_SUCCESS
)
962 (void) _be_unmount(bt
->obe_name
, 0);
969 * Function: be_promote_zone_ds
970 * Description: This function finds the zones for the BE being activated
971 * and the active zonepath dataset for each zone. Then each
972 * active zonepath dataset is promoted.
975 * be_name - the name of the global zone BE that we need to
976 * find the zones for.
977 * be_root_ds - the root dataset for be_name.
979 * BE_SUCCESS - Success
980 * be_errno_t - Failure
986 be_promote_zone_ds(char *be_name
, char *be_root_ds
)
988 char *zone_ds
= NULL
;
989 char *temp_mntpt
= NULL
;
990 char origin
[MAXPATHLEN
];
991 char zoneroot_ds
[MAXPATHLEN
];
992 zfs_handle_t
*zhp
= NULL
;
993 zfs_handle_t
*z_zhp
= NULL
;
994 boolean_t be_mounted
= B_FALSE
;
995 int err
= BE_SUCCESS
;
999 if ((zhp
= zfs_open(g_zfs
, be_root_ds
,
1000 ZFS_TYPE_FILESYSTEM
)) == NULL
) {
1001 be_print_err(gettext("be_promote_zone_ds: Failed to open "
1002 "dataset (%s): %s\n"), be_root_ds
,
1003 libzfs_error_description(g_zfs
));
1004 err
= zfs_err_to_be_err(g_zfs
);
1008 if (!zfs_is_mounted(zhp
, &temp_mntpt
)) {
1009 if ((err
= _be_mount(be_name
, &temp_mntpt
,
1010 BE_MOUNT_FLAG_NO_ZONES
)) != BE_SUCCESS
) {
1011 be_print_err(gettext("be_promote_zone_ds: failed to "
1012 "mount the BE for zones procesing.\n"));
1016 be_mounted
= B_TRUE
;
1020 * Set the zone root to the temp mount point for the BE we just mounted.
1022 zonecfg_set_root((const char *)temp_mntpt
);
1024 cookie
= setzoneent();
1025 while((ze
= getzoneent_private(cookie
)) != NULL
) {
1027 if (strcmp(ze
->zone_name
, "global") == 0)
1030 /* Skip zones that aren't at least installed */
1031 if (ze
->zone_state
< ZONE_STATE_INSTALLED
)
1034 if (((zone_ds
= be_get_ds_from_dir(ze
->zone_path
)) == NULL
) ||
1035 !be_zone_supported(zone_ds
)) {
1041 if (be_find_active_zone_root(zhp
, zone_ds
,
1042 zoneroot_ds
, sizeof (zoneroot_ds
)) != 0) {
1043 be_print_err(gettext("be_promote_zone_ds: "
1044 "Zone does not have an active root "
1045 "dataset, skipping this zone.\n"));
1049 if ((z_zhp
= zfs_open(g_zfs
, zoneroot_ds
,
1050 ZFS_TYPE_FILESYSTEM
)) == NULL
) {
1051 be_print_err(gettext("be_promote_zone_ds: "
1052 "Failed to open dataset "
1053 "(%s): %s\n"), zoneroot_ds
,
1054 libzfs_error_description(g_zfs
));
1055 err
= zfs_err_to_be_err(g_zfs
);
1059 if (zfs_prop_get(z_zhp
, ZFS_PROP_ORIGIN
, origin
,
1060 sizeof (origin
), NULL
, NULL
, 0, B_FALSE
) != 0) {
1066 * We don't need to close the zfs handle at this
1067 * point because the callback funtion
1068 * be_promote_ds_callback() will close it for us.
1070 if (be_promote_ds_callback(z_zhp
, NULL
) != 0) {
1071 be_print_err(gettext("be_promote_zone_ds: "
1072 "failed to activate the "
1073 "datasets for %s: %s\n"),
1075 libzfs_error_description(g_zfs
));
1076 err
= BE_ERR_PROMOTE
;
1085 (void) _be_unmount(be_name
, 0);
1092 * Function: be_promote_ds_callback
1093 * Description: This function is used to promote the datasets for the BE
1094 * being activated as well as the datasets for the zones BE
1098 * zhp - the zfs handle for zone BE being activated.
1102 * be_errno_t - Failure
1109 be_promote_ds_callback(zfs_handle_t
*zhp
, void *data
)
1111 char origin
[MAXPATHLEN
];
1112 char *sub_dataset
= NULL
;
1116 sub_dataset
= strdup(zfs_get_name(zhp
));
1117 if (sub_dataset
== NULL
) {
1122 be_print_err(gettext("be_promote_ds_callback: "
1123 "Invalid zfs handle passed into function\n"));
1129 * This loop makes sure that we promote the dataset to the
1130 * top of the tree so that it is no longer a decendent of any
1131 * dataset. The ZFS close and then open is used to make sure that
1132 * the promotion is updated before we move on.
1134 while (zfs_prop_get(zhp
, ZFS_PROP_ORIGIN
, origin
,
1135 sizeof (origin
), NULL
, NULL
, 0, B_FALSE
) == 0) {
1136 if (zfs_promote(zhp
) != 0) {
1137 if (libzfs_errno(g_zfs
) != EZFS_EXISTS
) {
1138 be_print_err(gettext("be_promote_ds_callback: "
1139 "promote of %s failed: %s\n"),
1141 libzfs_error_description(g_zfs
));
1142 ret
= zfs_err_to_be_err(g_zfs
);
1146 * If the call to zfs_promote returns the
1147 * error EZFS_EXISTS we've hit a snapshot name
1148 * collision. This means we're probably
1149 * attemping to promote a zone dataset above a
1150 * parent dataset that belongs to another zone
1151 * which this zone was cloned from.
1153 * TODO: If this is a zone dataset at some
1154 * point we should skip this if the zone
1155 * paths for the dataset and the snapshot
1158 be_print_err(gettext("be_promote_ds_callback: "
1159 "promote of %s failed due to snapshot "
1160 "name collision: %s\n"), zfs_get_name(zhp
),
1161 libzfs_error_description(g_zfs
));
1162 ret
= zfs_err_to_be_err(g_zfs
);
1167 if ((zhp
= zfs_open(g_zfs
, sub_dataset
,
1168 ZFS_TYPE_FILESYSTEM
)) == NULL
) {
1169 be_print_err(gettext("be_promote_ds_callback: "
1170 "Failed to open dataset (%s): %s\n"), sub_dataset
,
1171 libzfs_error_description(g_zfs
));
1172 ret
= zfs_err_to_be_err(g_zfs
);
1177 /* Iterate down this dataset's children and promote them */
1178 ret
= zfs_iter_filesystems(zhp
, be_promote_ds_callback
, NULL
);