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/cmd | |
parent | 44bc9120699af80bb18366ca474cb2c618608ca9 (diff) | |
download | illumos-gate-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/cmd')
-rw-r--r-- | usr/src/cmd/boot/bootadm/bootadm.c | 34 | ||||
-rw-r--r-- | usr/src/cmd/boot/installgrub/Makefile | 3 | ||||
-rw-r--r-- | usr/src/cmd/boot/installgrub/installgrub.c | 74 | ||||
-rw-r--r-- | usr/src/cmd/boot/installgrub/installgrub.h | 9 |
4 files changed, 94 insertions, 26 deletions
diff --git a/usr/src/cmd/boot/bootadm/bootadm.c b/usr/src/cmd/boot/bootadm/bootadm.c index c9466725f5..454b266d45 100644 --- a/usr/src/cmd/boot/bootadm/bootadm.c +++ b/usr/src/cmd/boot/bootadm/bootadm.c @@ -24,7 +24,7 @@ */ /* - * Copyright 2014 Nexenta Systems, Inc. All rights reserved. + * Copyright 2015 Nexenta Systems, Inc. All rights reserved. */ /* @@ -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" @@ -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) */ @@ -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, @@ -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; @@ -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'); @@ -7103,8 +7116,8 @@ 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); @@ -7112,6 +7125,11 @@ get_grubsign(char *osroot, char *osdev) 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)", diff --git a/usr/src/cmd/boot/installgrub/Makefile b/usr/src/cmd/boot/installgrub/Makefile index 4cc69eccd5..aecf0f7096 100644 --- a/usr/src/cmd/boot/installgrub/Makefile +++ b/usr/src/cmd/boot/installgrub/Makefile @@ -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 @@ -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 \ diff --git a/usr/src/cmd/boot/installgrub/installgrub.c b/usr/src/cmd/boot/installgrub/installgrub.c index c27dca802b..4d29d0236e 100644 --- a/usr/src/cmd/boot/installgrub/installgrub.c +++ b/usr/src/cmd/boot/installgrub/installgrub.c @@ -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> @@ -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" @@ -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 *); @@ -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); @@ -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); @@ -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; @@ -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); @@ -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)) { @@ -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"); @@ -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); @@ -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; @@ -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); } @@ -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); @@ -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); @@ -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 @@ -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); } diff --git a/usr/src/cmd/boot/installgrub/installgrub.h b/usr/src/cmd/boot/installgrub/installgrub.h index af6e60b973..037ffad4ce 100644 --- a/usr/src/cmd/boot/installgrub/installgrub.h +++ b/usr/src/cmd/boot/installgrub/installgrub.h @@ -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 @@ -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 */ @@ -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 } |