Skip to content

Commit

Permalink
5561 support root pools on EFI/GPT partitioned disks
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Hans Rosenfeld authored and gwr committed Feb 20, 2015
1 parent 44bc912 commit 1a902ef
Show file tree
Hide file tree
Showing 11 changed files with 263 additions and 193 deletions.
34 changes: 26 additions & 8 deletions usr/src/cmd/boot/bootadm/bootadm.c
Expand Up @@ -24,7 +24,7 @@
*/

/*
* Copyright 2014 Nexenta Systems, Inc. All rights reserved.
* Copyright 2015 Nexenta Systems, Inc. All rights reserved.
*/

/*
Expand Down Expand Up @@ -116,6 +116,9 @@ typedef struct {
#define ENTRY_INIT -1 /* entryNum initial value */
#define ALL_ENTRIES -2 /* selects all boot entries */

#define PARTNO_NOTFOUND -1 /* Solaris partition not found */
#define PARTNO_EFI -2 /* EFI partition table found */

#define GRUB_DIR "/boot/grub"
#define GRUB_STAGE2 GRUB_DIR "/stage2"
#define GRUB_MENU "/boot/grub/menu.lst"
Expand Down Expand Up @@ -4916,14 +4919,14 @@ create_diskmap(char *osroot)
static int
get_partition(char *device)
{
int i, fd, is_pcfs, partno = -1;
int i, fd, is_pcfs, partno = PARTNO_NOTFOUND;
struct mboot *mboot;
char boot_sect[SECTOR_SIZE];
char *wholedisk, *slice;
#ifdef i386
ext_part_t *epp;
uint32_t secnum, numsec;
int rval, pno, ext_partno = -1;
int rval, pno, ext_partno = PARTNO_NOTFOUND;
#endif

/* form whole disk (p0) */
Expand Down Expand Up @@ -4979,6 +4982,11 @@ get_partition(char *device)
break;
}
} else { /* look for solaris partition, old and new */
if (part->systid == EFI_PMBR) {
partno = PARTNO_EFI;
break;
}

#ifdef i386
if ((part->systid == SUNIXOS &&
(fdisk_is_linux_swap(epp, part->relsect,
Expand All @@ -4999,7 +5007,7 @@ get_partition(char *device)
}
#ifdef i386
/* If no primary solaris partition, check extended partition */
if ((partno == -1) && (ext_partno != -1)) {
if ((partno == PARTNO_NOTFOUND) && (ext_partno != PARTNO_NOTFOUND)) {
rval = fdisk_get_solaris_part(epp, &pno, &secnum, &numsec);
if (rval == FDISK_SUCCESS) {
partno = pno - 1;
Expand Down Expand Up @@ -5072,13 +5080,18 @@ get_grubroot(char *osroot, char *osdev, char *menu_root)
}

fdiskpart = get_partition(osdev);
INJECT_ERROR1("GRUBROOT_FDISK_FAIL", fdiskpart = -1);
if (fdiskpart == -1) {
INJECT_ERROR1("GRUBROOT_FDISK_FAIL", fdiskpart = PARTNO_NOTFOUND);
if (fdiskpart == PARTNO_NOTFOUND) {
bam_error(FDISKPART_FAIL, osdev);
return (NULL);
}

grubroot = s_calloc(1, 10);
if (fdiskpart == PARTNO_EFI) {
fdiskpart = atoi(&slice[1]);
slice = NULL;
}

if (slice) {
(void) snprintf(grubroot, 10, "(hd%s,%d,%c)",
grubhd, fdiskpart, slice[1] + 'a' - '0');
Expand Down Expand Up @@ -7103,15 +7116,20 @@ get_grubsign(char *osroot, char *osdev)
bam_print(GRUBSIGN_FOUND_OR_CREATED, sign, osdev);

fdiskpart = get_partition(osdev);
INJECT_ERROR1("GET_GRUBSIGN_FDISK", fdiskpart = -1);
if (fdiskpart == -1) {
INJECT_ERROR1("GET_GRUBSIGN_FDISK", fdiskpart = PARTNO_NOTFOUND);
if (fdiskpart == PARTNO_NOTFOUND) {
bam_error(FDISKPART_FAIL, osdev);
free(sign);
return (NULL);
}

slice = strrchr(osdev, 's');

if (fdiskpart == PARTNO_EFI) {
fdiskpart = atoi(&slice[1]);
slice = NULL;
}

grubsign = s_calloc(1, MAXNAMELEN + 10);
if (slice) {
(void) snprintf(grubsign, MAXNAMELEN + 10, "(%s,%d,%c)",
Expand Down
3 changes: 2 additions & 1 deletion usr/src/cmd/boot/installgrub/Makefile
Expand Up @@ -19,6 +19,7 @@
# CDDL HEADER END
#
# Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
# Copyright 2015, Nexenta Systems, Inc.
#

PROG= installgrub
Expand All @@ -45,7 +46,7 @@ LDLIBS += -lmd5
i386_CFLAGS += -D_LARGEFILE64_SOURCE
i386_CFLAGS += -D_FILE_OFFSET_BITS=64

LDLIBS += -lfdisk
LDLIBS += -lfdisk -lefi -lfstyp

LINTFLAGS += \
-erroff=E_BAD_PTR_CAST_ALIGN \
Expand Down
74 changes: 60 additions & 14 deletions usr/src/cmd/boot/installgrub/installgrub.c
Expand Up @@ -21,7 +21,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2012 Milan Jurik. All rights reserved.
* Copyright 2012 Nexenta Systems, Inc. All rights reserved.
* Copyright 2015 Nexenta Systems, Inc. All rights reserved.
*/

#include <stdio.h>
Expand All @@ -48,6 +48,10 @@
#include <sys/stat.h>
#include <sys/multiboot.h>
#include <sys/sysmacros.h>
#include <sys/efi_partition.h>

#include <libnvpair.h>
#include <libfstyp.h>

#include "message.h"
#include "installgrub.h"
Expand Down Expand Up @@ -107,7 +111,7 @@ static void usage(char *);
static int read_stage1_from_file(char *, ig_data_t *);
static int read_stage2_from_file(char *, ig_data_t *);
static int read_stage1_from_disk(int, char *);
static int read_stage2_from_disk(int, ig_stage2_t *);
static int read_stage2_from_disk(int, ig_stage2_t *, int);
static int prepare_stage1(ig_data_t *);
static int prepare_stage2(ig_data_t *, char *);
static void prepare_fake_multiboot(ig_stage2_t *);
Expand Down Expand Up @@ -389,7 +393,7 @@ handle_getinfo(char *progname, char **argv)
goto out_dev;
}

ret = read_stage2_from_disk(device->part_fd, stage2);
ret = read_stage2_from_disk(device->part_fd, stage2, device->type);
if (ret == BC_ERROR) {
(void) fprintf(stderr, gettext("Error reading stage2 from "
"%s\n"), device_path);
Expand Down Expand Up @@ -487,7 +491,8 @@ handle_mirror(char *progname, char **argv)
goto out_devs;
}

ret = read_stage2_from_disk(curr_device->part_fd, stage2_curr);
ret = read_stage2_from_disk(curr_device->part_fd, stage2_curr,
curr_device->type);
if (ret == BC_ERROR) {
BOOT_DEBUG("Error reading first stage2 blocks from %s\n",
curr_device->path);
Expand Down Expand Up @@ -623,6 +628,10 @@ propagate_bootblock(ig_data_t *source, ig_data_t *target, char *updt_str)
static int
init_device(ig_device_t *device, char *path)
{
struct dk_gpt *vtoc;
fstyp_handle_t fhdl;
const char *fident;

bzero(device, sizeof (*device));
device->part_fd = -1;
device->disk_fd = -1;
Expand Down Expand Up @@ -655,9 +664,25 @@ init_device(ig_device_t *device, char *path)
return (BC_ERROR);
}

if (efi_alloc_and_read(device->disk_fd, &vtoc) > 0) {
device->type = IG_DEV_EFI;
efi_free(vtoc);
}

if (get_raw_partition_fd(device) != BC_SUCCESS)
return (BC_ERROR);

if (fstyp_init(device->part_fd, 0, NULL, &fhdl) != 0)
return (BC_ERROR);

if (fstyp_ident(fhdl, "zfs", &fident) != 0) {
fstyp_fini(fhdl);
(void) fprintf(stderr, gettext("Booting of EFI labeled disks "
"is only supported with ZFS\n"));
return (BC_ERROR);
}
fstyp_fini(fhdl);

if (get_start_sector(device) != BC_SUCCESS)
return (BC_ERROR);

Expand Down Expand Up @@ -701,6 +726,21 @@ get_start_sector(ig_device_t *device)
struct part_info dkpi;
struct extpart_info edkpi;

if (is_efi(device->type)) {
struct dk_gpt *vtoc;

if (efi_alloc_and_read(device->disk_fd, &vtoc) <= 0)
return (BC_ERROR);

device->start_sector = vtoc->efi_parts[device->slice].p_start;
/* GPT doesn't use traditional slice letters */
device->slice = 0xff;
device->partition = 0;

efi_free(vtoc);
goto found_part;
}

mboot = (struct mboot *)device->boot_sector;

if (is_bootpar(device->type)) {
Expand Down Expand Up @@ -959,7 +999,8 @@ write_stage2(ig_data_t *install)
* Note that we use stage2->buf rather than stage2->file, because we
* may have extended information after the latter.
*/
offset = STAGE2_BLKOFF * SECTOR_SIZE;
offset = STAGE2_BLKOFF(device->type) * SECTOR_SIZE;

if (write_out(device->part_fd, stage2->buf, stage2->buf_size,
offset) != BC_SUCCESS) {
perror("write");
Expand All @@ -968,7 +1009,7 @@ write_stage2(ig_data_t *install)

/* Simulate the "old" installgrub output. */
(void) fprintf(stdout, WRITE_STAGE2_DISK, device->partition,
(stage2->buf_size / SECTOR_SIZE) + 1, STAGE2_BLKOFF,
(stage2->buf_size / SECTOR_SIZE) + 1, STAGE2_BLKOFF(device->type),
stage2->first_sector);

return (BC_SUCCESS);
Expand Down Expand Up @@ -1162,7 +1203,7 @@ read_stage1_from_disk(int dev_fd, char *stage1_buf)
}

static int
read_stage2_from_disk(int dev_fd, ig_stage2_t *stage2)
read_stage2_from_disk(int dev_fd, ig_stage2_t *stage2, int type)
{
uint32_t size;
uint32_t buf_size;
Expand All @@ -1173,7 +1214,7 @@ read_stage2_from_disk(int dev_fd, ig_stage2_t *stage2)
assert(dev_fd != -1);

if (read_in(dev_fd, mboot_scan, sizeof (mboot_scan),
STAGE2_BLKOFF * SECTOR_SIZE) != BC_SUCCESS) {
STAGE2_BLKOFF(type) * SECTOR_SIZE) != BC_SUCCESS) {
perror(gettext("Error reading stage2 sectors"));
return (BC_ERROR);
}
Expand Down Expand Up @@ -1209,7 +1250,7 @@ read_stage2_from_disk(int dev_fd, ig_stage2_t *stage2)
}
stage2->buf_size = buf_size;

if (read_in(dev_fd, stage2->buf, buf_size, STAGE2_BLKOFF *
if (read_in(dev_fd, stage2->buf, buf_size, STAGE2_BLKOFF(type) *
SECTOR_SIZE) != BC_SUCCESS) {
perror("read");
free(stage2->buf);
Expand Down Expand Up @@ -1243,7 +1284,8 @@ is_update_necessary(ig_data_t *data, char *updt_str)
bzero(&stage2_disk, sizeof (ig_stage2_t));

/* Gather stage2 (if present) from the target device. */
if (read_stage2_from_disk(dev_fd, &stage2_disk) != BC_SUCCESS) {
if (read_stage2_from_disk(dev_fd, &stage2_disk, device->type)
!= BC_SUCCESS) {
BOOT_DEBUG("Unable to read stage2 from %s\n", device->path);
BOOT_DEBUG("No multiboot wrapped stage2 on %s\n", device->path);
return (B_TRUE);
Expand Down Expand Up @@ -1367,7 +1409,8 @@ prepare_stage2(ig_data_t *install, char *updt_str)
}
} else {
/* Solaris VTOC */
stage2->first_sector = device->start_sector + STAGE2_BLKOFF;
stage2->first_sector = device->start_sector +
STAGE2_BLKOFF(device->type);
BOOT_DEBUG("stage2 first sector: %d\n", stage2->first_sector);
/*
* In a solaris partition, stage2 is written to contiguous
Expand Down Expand Up @@ -1441,15 +1484,18 @@ get_raw_partition_path(ig_device_t *device)
}

len = strlen(raw);
if (raw[len - 2] != 's' || raw[len - 1] == '2') {
if (!is_efi(device->type) &&
(raw[len - 2] != 's' || raw[len - 1] == '2')) {
(void) fprintf(stderr, NOT_ROOT_SLICE);
free(raw);
return (NULL);
}
device->slice = atoi(&raw[len - 1]);

raw[len - 2] = 's';
raw[len - 1] = '2';
if (!is_efi(device->type)) {
raw[len - 2] = 's';
raw[len - 1] = '2';
}

return (raw);
}
Expand Down
9 changes: 6 additions & 3 deletions usr/src/cmd/boot/installgrub/installgrub.h
Expand Up @@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2012 Nexenta Systems, Inc. All rights reserved.
* Copyright 2015 Nexenta Systems, Inc. All rights reserved.
*/

#ifndef _INSTALLGRUB_H
Expand Down Expand Up @@ -68,10 +68,12 @@ typedef struct _ig_data {

enum ig_devtype_t {
IG_DEV_X86BOOTPAR = 1,
IG_DEV_SOLVTOC
IG_DEV_SOLVTOC,
IG_DEV_EFI
};

#define is_bootpar(type) (type == IG_DEV_X86BOOTPAR)
#define is_efi(type) (type == IG_DEV_EFI)

#define STAGE2_MEMADDR (0x8000) /* loading addr of stage2 */

Expand All @@ -86,7 +88,8 @@ enum ig_devtype_t {
#define STAGE2_BLOCKLIST (SECTOR_SIZE - 0x8)
#define STAGE2_INSTALLPART (SECTOR_SIZE + 0x8)
#define STAGE2_FORCE_LBA (SECTOR_SIZE + 0x11)
#define STAGE2_BLKOFF (50) /* offset from start of fdisk part */
#define STAGE2_BLKOFF(type) \
(is_efi(type) ? 1024 : 50) /* offset from start of part */

#ifdef __cplusplus
}
Expand Down
4 changes: 2 additions & 2 deletions usr/src/lib/libbe/Makefile.com
Expand Up @@ -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.
#


Expand All @@ -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
Expand Down

0 comments on commit 1a902ef

Please sign in to comment.