summaryrefslogtreecommitdiff
path: root/usr/src/lib
diff options
context:
space:
mode:
authorHans Rosenfeld <hans.rosenfeld@nexenta.com>2015-01-10 21:16:37 +0100
committerGordon Ross <gwr@nexenta.com>2015-02-20 18:00:32 -0500
commit1a902ef8628b0dffd6df5442354ab59bb8530962 (patch)
treea8f20055af62687834f7818a81d4ebbdf6eb881d /usr/src/lib
parent44bc9120699af80bb18366ca474cb2c618608ca9 (diff)
downloadillumos-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.com4
-rw-r--r--usr/src/lib/libbe/common/be_activate.c195
-rw-r--r--usr/src/lib/libgrubmgmt/common/libgrub_cmd.c5
-rw-r--r--usr/src/lib/libzfs/common/libzfs_pool.c79
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);