diff options
author | Hans Rosenfeld <hans.rosenfeld@nexenta.com> | 2015-01-10 21:16:37 +0100 |
---|---|---|
committer | Gordon Ross <gwr@nexenta.com> | 2015-02-20 18:00:32 -0500 |
commit | 1a902ef8628b0dffd6df5442354ab59bb8530962 (patch) | |
tree | a8f20055af62687834f7818a81d4ebbdf6eb881d /usr/src/lib | |
parent | 44bc9120699af80bb18366ca474cb2c618608ca9 (diff) | |
download | illumos-joyent-1a902ef8628b0dffd6df5442354ab59bb8530962.tar.gz |
5561 support root pools on EFI/GPT partitioned disks
5125 update zpool/libzfs to manage bootable whole disk pools (EFI/GPT labeled disks)
Reviewed by: Jean McCormack <jean.mccormack@nexenta.com>
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
Approved by: Dan McDonald <danmcd@omniti.com>
Diffstat (limited to 'usr/src/lib')
-rw-r--r-- | usr/src/lib/libbe/Makefile.com | 4 | ||||
-rw-r--r-- | usr/src/lib/libbe/common/be_activate.c | 195 | ||||
-rw-r--r-- | usr/src/lib/libgrubmgmt/common/libgrub_cmd.c | 5 | ||||
-rw-r--r-- | usr/src/lib/libzfs/common/libzfs_pool.c | 79 |
4 files changed, 154 insertions, 129 deletions
diff --git a/usr/src/lib/libbe/Makefile.com b/usr/src/lib/libbe/Makefile.com index b71a0f85b5..bc04dd8a47 100644 --- a/usr/src/lib/libbe/Makefile.com +++ b/usr/src/lib/libbe/Makefile.com @@ -22,8 +22,8 @@ # # Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. # -# Copyright 2011 Nexenta Systems, Inc. All rights reserved. # Copyright 2012 OmniTI Computer Consulting, Inc. All rights reserved. +# Copyright 2015 Nexenta Systems, Inc. All rights reserved. # @@ -50,7 +50,7 @@ INCS += -I$(SRCDIR) C99MODE= $(C99_ENABLE) -LDLIBS += -lzfs -linstzones -luuid -lnvpair -lc -lgen -ldevinfo +LDLIBS += -lzfs -linstzones -luuid -lnvpair -lc -lgen -ldevinfo -lefi CPPFLAGS += $(INCS) CERRWARN += -_gcc=-Wno-unused-label CERRWARN += -_gcc=-Wno-uninitialized diff --git a/usr/src/lib/libbe/common/be_activate.c b/usr/src/lib/libbe/common/be_activate.c index 5b4555d924..da6ed3fb18 100644 --- a/usr/src/lib/libbe/common/be_activate.c +++ b/usr/src/lib/libbe/common/be_activate.c @@ -24,7 +24,7 @@ */ /* - * Copyright 2013 Nexenta Systems, Inc. All rights reserved. + * Copyright 2015 Nexenta Systems, Inc. All rights reserved. */ #include <assert.h> @@ -34,11 +34,14 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <strings.h> #include <errno.h> #include <sys/mnttab.h> #include <sys/types.h> #include <sys/stat.h> +#include <fcntl.h> #include <unistd.h> +#include <sys/efi_partition.h> #include <libbe.h> #include <libbe_priv.h> @@ -50,6 +53,9 @@ char *mnttab = MNTTAB; */ static int set_bootfs(char *boot_rpool, char *be_root_ds); static int set_canmount(be_node_list_t *, char *); +static boolean_t be_do_installgrub_mbr(char *, nvlist_t *); +static int be_do_installgrub_helper(zpool_handle_t *, nvlist_t *, char *, + char *); static int be_do_installgrub(be_transaction_data_t *); static int be_get_grub_vers(be_transaction_data_t *, char **, char **); static int get_ver_from_capfile(char *, char **); @@ -750,6 +756,136 @@ get_ver_from_capfile(char *file, char **vers) } /* + * To be able to boot EFI labeled disks, GRUB stage1 needs to be written + * into the MBR. We do not do this if we're on disks with a traditional + * fdisk partition table only, or if any foreign EFI partitions exist. + * In the trivial case of a whole-disk vdev we always write stage1 into + * the MBR. + */ +static boolean_t +be_do_installgrub_mbr(char *diskname, nvlist_t *child) +{ + struct uuid allowed_uuids[] = { + EFI_UNUSED, + EFI_RESV1, + EFI_BOOT, + EFI_ROOT, + EFI_SWAP, + EFI_USR, + EFI_BACKUP, + EFI_RESV2, + EFI_VAR, + EFI_HOME, + EFI_ALTSCTR, + EFI_RESERVED, + EFI_SYSTEM, + EFI_BIOS_BOOT, + EFI_SYMC_PUB, + EFI_SYMC_CDS + }; + + uint64_t whole; + struct dk_gpt *gpt; + struct uuid *u; + int fd, npart, i, j; + + (void) nvlist_lookup_uint64(child, ZPOOL_CONFIG_WHOLE_DISK, + &whole); + + if (whole) + return (B_TRUE); + + if ((fd = open(diskname, O_RDONLY|O_NDELAY)) < 0) + return (B_FALSE); + + if ((npart = efi_alloc_and_read(fd, &gpt)) <= 0) + return (B_FALSE); + + for (i = 0; i != npart; i++) { + int match = 0; + + u = &gpt->efi_parts[i].p_guid; + + for (j = 0; + j != sizeof (allowed_uuids) / sizeof (struct uuid); + j++) + if (bcmp(u, &allowed_uuids[j], + sizeof (struct uuid)) == 0) + match++; + + if (match == 0) + return (B_FALSE); + } + + return (B_TRUE); +} + +static int +be_do_installgrub_helper(zpool_handle_t *zphp, nvlist_t *child, char *stage1, + char *stage2) +{ + char installgrub_cmd[MAXPATHLEN]; + char be_run_cmd_errbuf[BUFSIZ]; + char diskname[MAXPATHLEN]; + char *vname; + char *path, *dsk_ptr; + char *m_flag = ""; + + if (nvlist_lookup_string(child, ZPOOL_CONFIG_PATH, &path) != 0) { + be_print_err(gettext("be_do_installgrub: " + "failed to get device path\n")); + return (BE_ERR_NODEV); + } + + /* + * Modify the vdev path to point to the raw disk. + */ + path = strdup(path); + if (path == NULL) + return (BE_ERR_NOMEM); + + dsk_ptr = strstr(path, "/dsk/"); + if (dsk_ptr != NULL) { + *dsk_ptr = '\0'; + dsk_ptr++; + } else { + dsk_ptr = ""; + } + + (void) snprintf(diskname, sizeof (diskname), "%s/r%s", path, dsk_ptr); + free(path); + + if (be_do_installgrub_mbr(diskname, child)) + m_flag = "-m -f"; + + vname = zpool_vdev_name(g_zfs, zphp, child, B_FALSE); + if (vname == NULL) { + be_print_err(gettext("be_do_installgrub: " + "failed to get device name: %s\n"), + libzfs_error_description(g_zfs)); + return (zfs_err_to_be_err(g_zfs)); + } + + (void) snprintf(installgrub_cmd, sizeof (installgrub_cmd), + "%s %s %s %s %s", BE_INSTALL_GRUB, m_flag, stage1, stage2, + diskname); + if (be_run_cmd(installgrub_cmd, be_run_cmd_errbuf, BUFSIZ, NULL, 0) + != BE_SUCCESS) { + be_print_err(gettext("be_do_installgrub: installgrub " + "failed for device %s.\n"), vname); + /* Assume localized cmd err output. */ + be_print_err(gettext(" Command: \"%s\"\n"), + installgrub_cmd); + be_print_err("%s", be_run_cmd_errbuf); + free(vname); + return (BE_ERR_BOOTFILE_INST); + } + free(vname); + + return (BE_SUCCESS); +} + +/* * Function: be_do_installgrub * Description: This function runs installgrub using the grub loader files * from the BE we're activating and installing them on the @@ -782,9 +918,7 @@ be_do_installgrub(be_transaction_data_t *bt) char zpool_cap_file[MAXPATHLEN]; char stage1[MAXPATHLEN]; char stage2[MAXPATHLEN]; - char installgrub_cmd[MAXPATHLEN]; char *vname; - char be_run_cmd_errbuf[BUFSIZ]; int ret = BE_SUCCESS; int err = 0; boolean_t be_mounted = B_FALSE; @@ -868,6 +1002,7 @@ be_do_installgrub(be_transaction_data_t *bt) goto done; } if (strcmp(vname, "mirror") == 0 || vname[0] != 'c') { + free(vname); if (nvlist_lookup_nvlist_array(child[c], ZPOOL_CONFIG_CHILDREN, &nvchild, &nchildren) != 0) { @@ -879,56 +1014,18 @@ be_do_installgrub(be_transaction_data_t *bt) } for (i = 0; i < nchildren; i++) { - vname = zpool_vdev_name(g_zfs, zphp, - nvchild[i], B_FALSE); - if (vname == NULL) { - be_print_err(gettext( - "be_do_installgrub: " - "failed to get device name: %s\n"), - libzfs_error_description(g_zfs)); - ret = zfs_err_to_be_err(g_zfs); + ret = be_do_installgrub_helper(zphp, nvchild[i], + stage1, stage2); + if (ret != BE_SUCCESS) goto done; - } - - (void) snprintf(installgrub_cmd, - sizeof (installgrub_cmd), - "%s %s %s /dev/rdsk/%s", - BE_INSTALL_GRUB, stage1, stage2, vname); - if (be_run_cmd(installgrub_cmd, - be_run_cmd_errbuf, BUFSIZ, NULL, 0) != - BE_SUCCESS) { - be_print_err(gettext( - "be_do_installgrub: installgrub " - "failed for device %s.\n"), vname); - /* Assume localized cmd err output. */ - be_print_err(gettext( - " Command: \"%s\"\n"), - installgrub_cmd); - be_print_err("%s", be_run_cmd_errbuf); - free(vname); - ret = BE_ERR_BOOTFILE_INST; - goto done; - } - free(vname); } } else { - (void) snprintf(installgrub_cmd, - sizeof (installgrub_cmd), "%s %s %s /dev/rdsk/%s", - BE_INSTALL_GRUB, stage1, stage2, vname); - if (be_run_cmd(installgrub_cmd, be_run_cmd_errbuf, - BUFSIZ, NULL, 0) != BE_SUCCESS) { - be_print_err(gettext( - "be_do_installgrub: installgrub " - "failed for device %s.\n"), vname); - /* Assume localized cmd err output. */ - be_print_err(gettext(" Command: \"%s\"\n"), - installgrub_cmd); - be_print_err("%s", be_run_cmd_errbuf); - free(vname); - ret = BE_ERR_BOOTFILE_INST; - goto done; - } free(vname); + + ret = be_do_installgrub_helper(zphp, child[c], stage1, + stage2); + if (ret != BE_SUCCESS) + goto done; } } diff --git a/usr/src/lib/libgrubmgmt/common/libgrub_cmd.c b/usr/src/lib/libgrubmgmt/common/libgrub_cmd.c index 85304d45e7..5dc12247b1 100644 --- a/usr/src/lib/libgrubmgmt/common/libgrub_cmd.c +++ b/usr/src/lib/libgrubmgmt/common/libgrub_cmd.c @@ -22,6 +22,9 @@ * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ +/* + * Copyright 2015 Nexenta Systems, Inc. + */ /* * This file contains all the functions that implement the following @@ -399,7 +402,7 @@ findroot(const grub_line_t *lp, grub_barg_t *barg) return (EG_FINDROOTFMT); ++pos; - if (pos[0] != ',' || + if ((pos[0] != ',' && pos[0] != ')') || !IS_SLCNUM_VALID(barg->gb_slcnum = pos[1]) || pos[2] != ')') return (EG_FINDROOTFMT); diff --git a/usr/src/lib/libzfs/common/libzfs_pool.c b/usr/src/lib/libzfs/common/libzfs_pool.c index 4f8d0b6148..0418091025 100644 --- a/usr/src/lib/libzfs/common/libzfs_pool.c +++ b/usr/src/lib/libzfs/common/libzfs_pool.c @@ -373,27 +373,6 @@ bootfs_name_valid(const char *pool, char *bootfs) return (B_FALSE); } -/* - * Inspect the configuration to determine if any of the devices contain - * an EFI label. - */ -static boolean_t -pool_uses_efi(nvlist_t *config) -{ - nvlist_t **child; - uint_t c, children; - - if (nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_CHILDREN, - &child, &children) != 0) - return (read_efi_label(config, NULL) >= 0); - - for (c = 0; c < children; c++) { - if (pool_uses_efi(child[c])) - return (B_TRUE); - } - return (B_FALSE); -} - boolean_t zpool_is_bootable(zpool_handle_t *zhp) { @@ -422,7 +401,6 @@ zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname, char *slash, *check; struct stat64 statbuf; zpool_handle_t *zhp; - nvlist_t *nvroot; if (nvlist_alloc(&retprops, NV_UNIQUE_NAME, 0) != 0) { (void) no_memory(hdl); @@ -541,21 +519,6 @@ zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname, (void) zfs_error(hdl, EZFS_OPENFAILED, errbuf); goto error; } - verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL), - ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); - - /* - * bootfs property cannot be set on a disk which has - * been EFI labeled. - */ - if (pool_uses_efi(nvroot)) { - zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, - "property '%s' not supported on " - "EFI labeled devices"), propname); - (void) zfs_error(hdl, EZFS_POOL_NOTSUP, errbuf); - zpool_close(zhp); - goto error; - } zpool_close(zhp); break; @@ -1278,25 +1241,6 @@ zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot) return (zfs_error(hdl, EZFS_BADVERSION, msg)); } - if (zpool_is_bootable(zhp) && nvlist_lookup_nvlist_array(nvroot, - ZPOOL_CONFIG_SPARES, &spares, &nspares) == 0) { - uint64_t s; - - for (s = 0; s < nspares; s++) { - char *path; - - if (nvlist_lookup_string(spares[s], ZPOOL_CONFIG_PATH, - &path) == 0 && pool_uses_efi(spares[s])) { - zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, - "device '%s' contains an EFI label and " - "cannot be used on root pools."), - zpool_vdev_name(hdl, NULL, spares[s], - B_FALSE)); - return (zfs_error(hdl, EZFS_POOL_NOTSUP, msg)); - } - } - } - if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) < SPA_VERSION_L2CACHE && nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE, @@ -2311,11 +2255,9 @@ zpool_get_config_physpath(nvlist_t *config, char *physpath, size_t phypath_size) return (EZFS_INVALCONFIG); /* - * root pool can not have EFI labeled disks and can only have - * a single top-level vdev. + * root pool can only have a single top-level vdev. */ - if (strcmp(type, VDEV_TYPE_ROOT) != 0 || count != 1 || - pool_uses_efi(vdev_root)) + if (strcmp(type, VDEV_TYPE_ROOT) != 0 || count != 1) return (EZFS_POOL_INVALARG); (void) vdev_get_physpaths(child[0], physpath, phypath_size, &rsz, @@ -2617,16 +2559,6 @@ zpool_vdev_attach(zpool_handle_t *zhp, (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, "cannot attach %s to %s"), new_disk, old_disk); - /* - * If this is a root pool, make sure that we're not attaching an - * EFI labeled device. - */ - if (rootpool && pool_uses_efi(nvroot)) { - zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, - "EFI labeled devices are not supported on root pools.")); - return (zfs_error(hdl, EZFS_POOL_NOTSUP, msg)); - } - (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name)); if ((tgt = zpool_find_vdev(zhp, old_disk, &avail_spare, &l2cache, &islog)) == 0) @@ -3902,13 +3834,6 @@ zpool_label_disk(libzfs_handle_t *hdl, zpool_handle_t *zhp, char *name) if (zhp) { nvlist_t *nvroot; - if (zpool_is_bootable(zhp)) { - zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, - "EFI labeled devices are not supported on root " - "pools.")); - return (zfs_error(hdl, EZFS_POOL_NOTSUP, errbuf)); - } - verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); |