Path: blob/main/sys/contrib/openzfs/lib/libefi/rdwr_efi.c
48378 views
// SPDX-License-Identifier: CDDL-1.01/*2* CDDL HEADER START3*4* The contents of this file are subject to the terms of the5* Common Development and Distribution License (the "License").6* You may not use this file except in compliance with the License.7*8* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE9* or https://opensource.org/licenses/CDDL-1.0.10* See the License for the specific language governing permissions11* and limitations under the License.12*13* When distributing Covered Code, include this CDDL HEADER in each14* file and include the License file at usr/src/OPENSOLARIS.LICENSE.15* If applicable, add the following below this CDDL HEADER, with the16* fields enclosed by brackets "[]" replaced with your own identifying17* information: Portions Copyright [yyyy] [name of copyright owner]18*19* CDDL HEADER END20*/2122/*23* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.24* Copyright 2012 Nexenta Systems, Inc. All rights reserved.25* Copyright (c) 2018 by Delphix. All rights reserved.26*/2728#include <stdio.h>29#include <stdlib.h>30#include <errno.h>31#include <string.h>32#include <unistd.h>33#include <uuid/uuid.h>34#include <zlib.h>35#include <libintl.h>36#include <sys/types.h>37#include <sys/dkio.h>38#include <sys/mhd.h>39#include <sys/param.h>40#include <sys/dktp/fdisk.h>41#include <sys/efi_partition.h>42#include <sys/byteorder.h>43#include <sys/vdev_disk.h>44#include <linux/fs.h>45#include <linux/blkpg.h>4647static struct uuid_to_ptag {48struct uuid uuid;49} conversion_array[] = {50{ EFI_UNUSED },51{ EFI_BOOT },52{ EFI_ROOT },53{ EFI_SWAP },54{ EFI_USR },55{ EFI_BACKUP },56{ EFI_UNUSED }, /* STAND is never used */57{ EFI_VAR },58{ EFI_HOME },59{ EFI_ALTSCTR },60{ EFI_UNUSED }, /* CACHE (cachefs) is never used */61{ EFI_RESERVED },62{ EFI_SYSTEM },63{ EFI_LEGACY_MBR },64{ EFI_SYMC_PUB },65{ EFI_SYMC_CDS },66{ EFI_MSFT_RESV },67{ EFI_DELL_BASIC },68{ EFI_DELL_RAID },69{ EFI_DELL_SWAP },70{ EFI_DELL_LVM },71{ EFI_DELL_RESV },72{ EFI_AAPL_HFS },73{ EFI_AAPL_UFS },74{ EFI_FREEBSD_BOOT },75{ EFI_FREEBSD_SWAP },76{ EFI_FREEBSD_UFS },77{ EFI_FREEBSD_VINUM },78{ EFI_FREEBSD_ZFS },79{ EFI_BIOS_BOOT },80{ EFI_INTC_RS },81{ EFI_SNE_BOOT },82{ EFI_LENOVO_BOOT },83{ EFI_MSFT_LDMM },84{ EFI_MSFT_LDMD },85{ EFI_MSFT_RE },86{ EFI_IBM_GPFS },87{ EFI_MSFT_STORAGESPACES },88{ EFI_HPQ_DATA },89{ EFI_HPQ_SVC },90{ EFI_RHT_DATA },91{ EFI_RHT_HOME },92{ EFI_RHT_SRV },93{ EFI_RHT_DMCRYPT },94{ EFI_RHT_LUKS },95{ EFI_FREEBSD_DISKLABEL },96{ EFI_AAPL_RAID },97{ EFI_AAPL_RAIDOFFLINE },98{ EFI_AAPL_BOOT },99{ EFI_AAPL_LABEL },100{ EFI_AAPL_TVRECOVERY },101{ EFI_AAPL_CORESTORAGE },102{ EFI_NETBSD_SWAP },103{ EFI_NETBSD_FFS },104{ EFI_NETBSD_LFS },105{ EFI_NETBSD_RAID },106{ EFI_NETBSD_CAT },107{ EFI_NETBSD_CRYPT },108{ EFI_GOOG_KERN },109{ EFI_GOOG_ROOT },110{ EFI_GOOG_RESV },111{ EFI_HAIKU_BFS },112{ EFI_MIDNIGHTBSD_BOOT },113{ EFI_MIDNIGHTBSD_DATA },114{ EFI_MIDNIGHTBSD_SWAP },115{ EFI_MIDNIGHTBSD_UFS },116{ EFI_MIDNIGHTBSD_VINUM },117{ EFI_MIDNIGHTBSD_ZFS },118{ EFI_CEPH_JOURNAL },119{ EFI_CEPH_DMCRYPTJOURNAL },120{ EFI_CEPH_OSD },121{ EFI_CEPH_DMCRYPTOSD },122{ EFI_CEPH_CREATE },123{ EFI_CEPH_DMCRYPTCREATE },124{ EFI_OPENBSD_DISKLABEL },125{ EFI_BBRY_QNX },126{ EFI_BELL_PLAN9 },127{ EFI_VMW_KCORE },128{ EFI_VMW_VMFS },129{ EFI_VMW_RESV },130{ EFI_RHT_ROOTX86 },131{ EFI_RHT_ROOTAMD64 },132{ EFI_RHT_ROOTARM },133{ EFI_RHT_ROOTARM64 },134{ EFI_ACRONIS_SECUREZONE },135{ EFI_ONIE_BOOT },136{ EFI_ONIE_CONFIG },137{ EFI_IBM_PPRPBOOT },138{ EFI_FREEDESKTOP_BOOT }139};140141int efi_debug = 0;142143static int efi_read(int, struct dk_gpt *);144145/*146* Return a 32-bit CRC of the contents of the buffer. Pre-and-post147* one's conditioning will be handled by crc32() internally.148*/149static uint32_t150efi_crc32(const unsigned char *buf, unsigned int size)151{152uint32_t crc = crc32(0, Z_NULL, 0);153154crc = crc32(crc, buf, size);155156return (crc);157}158159static int160read_disk_info(int fd, diskaddr_t *capacity, uint_t *lbsize)161{162int sector_size;163unsigned long long capacity_size;164165if (ioctl(fd, BLKSSZGET, §or_size) < 0)166return (-1);167168if (ioctl(fd, BLKGETSIZE64, &capacity_size) < 0)169return (-1);170171*lbsize = (uint_t)sector_size;172*capacity = (diskaddr_t)(capacity_size / sector_size);173174return (0);175}176177/*178* Return back the device name associated with the file descriptor. The179* caller is responsible for freeing the memory associated with the180* returned string.181*/182static char *183efi_get_devname(int fd)184{185char path[32];186187/*188* The libefi API only provides the open fd and not the file path.189* To handle this realpath(3) is used to resolve the block device190* name from /proc/self/fd/<fd>.191*/192(void) snprintf(path, sizeof (path), "/proc/self/fd/%d", fd);193return (realpath(path, NULL));194}195196static int197efi_get_info(int fd, struct dk_cinfo *dki_info)198{199char *dev_path;200int rval = 0;201202memset(dki_info, 0, sizeof (*dki_info));203204/*205* The simplest way to get the partition number under linux is206* to parse it out of the /dev/<disk><partition> block device name.207* The kernel creates this using the partition number when it208* populates /dev/ so it may be trusted. The tricky bit here is209* that the naming convention is based on the block device type.210* So we need to take this in to account when parsing out the211* partition information. Aside from the partition number we collect212* some additional device info.213*/214dev_path = efi_get_devname(fd);215if (dev_path == NULL)216goto error;217218if ((strncmp(dev_path, "/dev/sd", 7) == 0)) {219strcpy(dki_info->dki_cname, "sd");220dki_info->dki_ctype = DKC_SCSI_CCS;221rval = sscanf(dev_path, "/dev/%[a-zA-Z]%hu",222dki_info->dki_dname,223&dki_info->dki_partition);224} else if ((strncmp(dev_path, "/dev/hd", 7) == 0)) {225strcpy(dki_info->dki_cname, "hd");226dki_info->dki_ctype = DKC_DIRECT;227rval = sscanf(dev_path, "/dev/%[a-zA-Z]%hu",228dki_info->dki_dname,229&dki_info->dki_partition);230} else if ((strncmp(dev_path, "/dev/md", 7) == 0)) {231strcpy(dki_info->dki_cname, "pseudo");232dki_info->dki_ctype = DKC_MD;233strcpy(dki_info->dki_dname, "md");234rval = sscanf(dev_path, "/dev/md%[0-9]p%hu",235dki_info->dki_dname + 2,236&dki_info->dki_partition);237} else if ((strncmp(dev_path, "/dev/vd", 7) == 0)) {238strcpy(dki_info->dki_cname, "vd");239dki_info->dki_ctype = DKC_MD;240rval = sscanf(dev_path, "/dev/%[a-zA-Z]%hu",241dki_info->dki_dname,242&dki_info->dki_partition);243} else if ((strncmp(dev_path, "/dev/xvd", 8) == 0)) {244strcpy(dki_info->dki_cname, "xvd");245dki_info->dki_ctype = DKC_MD;246rval = sscanf(dev_path, "/dev/%[a-zA-Z]%hu",247dki_info->dki_dname,248&dki_info->dki_partition);249} else if ((strncmp(dev_path, "/dev/zd", 7) == 0)) {250strcpy(dki_info->dki_cname, "zd");251dki_info->dki_ctype = DKC_MD;252strcpy(dki_info->dki_dname, "zd");253rval = sscanf(dev_path, "/dev/zd%[0-9]p%hu",254dki_info->dki_dname + 2,255&dki_info->dki_partition);256} else if ((strncmp(dev_path, "/dev/dm-", 8) == 0)) {257strcpy(dki_info->dki_cname, "pseudo");258dki_info->dki_ctype = DKC_VBD;259strcpy(dki_info->dki_dname, "dm-");260rval = sscanf(dev_path, "/dev/dm-%[0-9]p%hu",261dki_info->dki_dname + 3,262&dki_info->dki_partition);263} else if ((strncmp(dev_path, "/dev/ram", 8) == 0)) {264strcpy(dki_info->dki_cname, "pseudo");265dki_info->dki_ctype = DKC_PCMCIA_MEM;266strcpy(dki_info->dki_dname, "ram");267rval = sscanf(dev_path, "/dev/ram%[0-9]p%hu",268dki_info->dki_dname + 3,269&dki_info->dki_partition);270} else if ((strncmp(dev_path, "/dev/loop", 9) == 0)) {271strcpy(dki_info->dki_cname, "pseudo");272dki_info->dki_ctype = DKC_VBD;273strcpy(dki_info->dki_dname, "loop");274rval = sscanf(dev_path, "/dev/loop%[0-9]p%hu",275dki_info->dki_dname + 4,276&dki_info->dki_partition);277} else if ((strncmp(dev_path, "/dev/nvme", 9) == 0)) {278strcpy(dki_info->dki_cname, "nvme");279dki_info->dki_ctype = DKC_SCSI_CCS;280strcpy(dki_info->dki_dname, "nvme");281(void) sscanf(dev_path, "/dev/nvme%[0-9]",282dki_info->dki_dname + 4);283size_t controller_length = strlen(284dki_info->dki_dname);285strcpy(dki_info->dki_dname + controller_length,286"n");287rval = sscanf(dev_path,288"/dev/nvme%*[0-9]n%[0-9]p%hu",289dki_info->dki_dname + controller_length + 1,290&dki_info->dki_partition);291} else {292strcpy(dki_info->dki_dname, "unknown");293strcpy(dki_info->dki_cname, "unknown");294dki_info->dki_ctype = DKC_UNKNOWN;295}296297switch (rval) {298case 0:299errno = EINVAL;300goto error;301case 1:302dki_info->dki_partition = 0;303}304305free(dev_path);306307return (0);308error:309if (efi_debug)310(void) fprintf(stderr, "DKIOCINFO errno 0x%x\n", errno);311312switch (errno) {313case EIO:314return (VT_EIO);315case EINVAL:316return (VT_EINVAL);317default:318return (VT_ERROR);319}320}321322/*323* the number of blocks the EFI label takes up (round up to nearest324* block)325*/326#define NBLOCKS(p, l) (1 + ((((p) * (int)sizeof (efi_gpe_t)) + \327((l) - 1)) / (l)))328/* number of partitions -- limited by what we can malloc */329#define MAX_PARTS ((4294967295UL - sizeof (struct dk_gpt)) / \330sizeof (struct dk_part))331332int333efi_alloc_and_init(int fd, uint32_t nparts, struct dk_gpt **vtoc)334{335diskaddr_t capacity = 0;336uint_t lbsize = 0;337uint_t nblocks;338size_t length;339struct dk_gpt *vptr;340struct uuid uuid;341struct dk_cinfo dki_info;342343if (read_disk_info(fd, &capacity, &lbsize) != 0)344return (-1);345346if (efi_get_info(fd, &dki_info) != 0)347return (-1);348349if (dki_info.dki_partition != 0)350return (-1);351352if ((dki_info.dki_ctype == DKC_PCMCIA_MEM) ||353(dki_info.dki_ctype == DKC_VBD) ||354(dki_info.dki_ctype == DKC_UNKNOWN))355return (-1);356357nblocks = NBLOCKS(nparts, lbsize);358if ((nblocks * lbsize) < EFI_MIN_ARRAY_SIZE + lbsize) {359/* 16K plus one block for the GPT */360nblocks = EFI_MIN_ARRAY_SIZE / lbsize + 1;361}362363if (nparts > MAX_PARTS) {364if (efi_debug) {365(void) fprintf(stderr,366"the maximum number of partitions supported is %lu\n",367MAX_PARTS);368}369return (-1);370}371372length = sizeof (struct dk_gpt) +373sizeof (struct dk_part) * (nparts - 1);374375vptr = calloc(1, length);376if (vptr == NULL)377return (-1);378379*vtoc = vptr;380381vptr->efi_version = EFI_VERSION_CURRENT;382vptr->efi_lbasize = lbsize;383vptr->efi_nparts = nparts;384/*385* add one block here for the PMBR; on disks with a 512 byte386* block size and 128 or fewer partitions, efi_first_u_lba387* should work out to "34"388*/389vptr->efi_first_u_lba = nblocks + 1;390vptr->efi_last_lba = capacity - 1;391vptr->efi_altern_lba = capacity -1;392vptr->efi_last_u_lba = vptr->efi_last_lba - nblocks;393394(void) uuid_generate((uchar_t *)&uuid);395UUID_LE_CONVERT(vptr->efi_disk_uguid, uuid);396return (0);397}398399/*400* Read EFI - return partition number upon success.401*/402int403efi_alloc_and_read(int fd, struct dk_gpt **vtoc)404{405int rval;406uint32_t nparts;407int length;408struct dk_gpt *vptr;409410/* figure out the number of entries that would fit into 16K */411nparts = EFI_MIN_ARRAY_SIZE / sizeof (efi_gpe_t);412length = (int) sizeof (struct dk_gpt) +413(int) sizeof (struct dk_part) * (nparts - 1);414vptr = calloc(1, length);415416if (vptr == NULL)417return (VT_ERROR);418419vptr->efi_nparts = nparts;420rval = efi_read(fd, vptr);421422if ((rval == VT_EINVAL) && vptr->efi_nparts > nparts) {423void *tmp;424length = (int) sizeof (struct dk_gpt) +425(int) sizeof (struct dk_part) * (vptr->efi_nparts - 1);426if ((tmp = realloc(vptr, length)) == NULL) {427/* cppcheck-suppress doubleFree */428free(vptr);429*vtoc = NULL;430return (VT_ERROR);431} else {432vptr = tmp;433rval = efi_read(fd, vptr);434}435}436437if (rval < 0) {438if (efi_debug) {439(void) fprintf(stderr,440"read of EFI table failed, rval=%d\n", rval);441}442free(vptr);443*vtoc = NULL;444} else {445*vtoc = vptr;446}447448return (rval);449}450451static int452efi_ioctl(int fd, int cmd, dk_efi_t *dk_ioc)453{454void *data = dk_ioc->dki_data;455int error;456diskaddr_t capacity;457uint_t lbsize;458459/*460* When the IO is not being performed in kernel as an ioctl we need461* to know the sector size so we can seek to the proper byte offset.462*/463if (read_disk_info(fd, &capacity, &lbsize) == -1) {464if (efi_debug)465fprintf(stderr, "unable to read disk info: %d", errno);466467errno = EIO;468return (-1);469}470471switch (cmd) {472case DKIOCGETEFI:473if (lbsize == 0) {474if (efi_debug)475(void) fprintf(stderr, "DKIOCGETEFI assuming "476"LBA %d bytes\n", DEV_BSIZE);477478lbsize = DEV_BSIZE;479}480481error = lseek(fd, dk_ioc->dki_lba * lbsize, SEEK_SET);482if (error == -1) {483if (efi_debug)484(void) fprintf(stderr, "DKIOCGETEFI lseek "485"error: %d\n", errno);486return (error);487}488489error = read(fd, data, dk_ioc->dki_length);490if (error == -1) {491if (efi_debug)492(void) fprintf(stderr, "DKIOCGETEFI read "493"error: %d\n", errno);494return (error);495}496497if (error != dk_ioc->dki_length) {498if (efi_debug)499(void) fprintf(stderr, "DKIOCGETEFI short "500"read of %d bytes\n", error);501errno = EIO;502return (-1);503}504error = 0;505break;506507case DKIOCSETEFI:508if (lbsize == 0) {509if (efi_debug)510(void) fprintf(stderr, "DKIOCSETEFI unknown "511"LBA size\n");512errno = EIO;513return (-1);514}515516error = lseek(fd, dk_ioc->dki_lba * lbsize, SEEK_SET);517if (error == -1) {518if (efi_debug)519(void) fprintf(stderr, "DKIOCSETEFI lseek "520"error: %d\n", errno);521return (error);522}523524error = write(fd, data, dk_ioc->dki_length);525if (error == -1) {526if (efi_debug)527(void) fprintf(stderr, "DKIOCSETEFI write "528"error: %d\n", errno);529return (error);530}531532if (error != dk_ioc->dki_length) {533if (efi_debug)534(void) fprintf(stderr, "DKIOCSETEFI short "535"write of %d bytes\n", error);536errno = EIO;537return (-1);538}539540/* Sync the new EFI table to disk */541error = fsync(fd);542if (error == -1)543return (error);544545/* Ensure any local disk cache is also flushed */546if (ioctl(fd, BLKFLSBUF, 0) == -1)547return (error);548549error = 0;550break;551552default:553if (efi_debug)554(void) fprintf(stderr, "unsupported ioctl()\n");555556errno = EIO;557return (-1);558}559560return (error);561}562563int564efi_rescan(int fd)565{566int retry = 10;567568/* Notify the kernel a devices partition table has been updated */569while (ioctl(fd, BLKRRPART) != 0) {570if ((--retry == 0) || (errno != EBUSY)) {571(void) fprintf(stderr, "the kernel failed to rescan "572"the partition table: %d\n", errno);573return (-1);574}575usleep(50000);576}577578return (0);579}580581static int582check_label(int fd, dk_efi_t *dk_ioc)583{584efi_gpt_t *efi;585uint_t crc;586587if (efi_ioctl(fd, DKIOCGETEFI, dk_ioc) == -1) {588switch (errno) {589case EIO:590return (VT_EIO);591default:592return (VT_ERROR);593}594}595efi = dk_ioc->dki_data;596if (efi->efi_gpt_Signature != LE_64(EFI_SIGNATURE)) {597if (efi_debug)598(void) fprintf(stderr,599"Bad EFI signature: 0x%llx != 0x%llx\n",600(long long)efi->efi_gpt_Signature,601(long long)LE_64(EFI_SIGNATURE));602return (VT_EINVAL);603}604605/*606* check CRC of the header; the size of the header should607* never be larger than one block608*/609crc = efi->efi_gpt_HeaderCRC32;610efi->efi_gpt_HeaderCRC32 = 0;611len_t headerSize = (len_t)LE_32(efi->efi_gpt_HeaderSize);612613if (headerSize < EFI_MIN_LABEL_SIZE || headerSize > EFI_LABEL_SIZE) {614if (efi_debug)615(void) fprintf(stderr,616"Invalid EFI HeaderSize %llu. Assuming %d.\n",617headerSize, EFI_MIN_LABEL_SIZE);618}619620if ((headerSize > dk_ioc->dki_length) ||621crc != LE_32(efi_crc32((unsigned char *)efi, headerSize))) {622if (efi_debug)623(void) fprintf(stderr,624"Bad EFI CRC: 0x%x != 0x%x\n",625crc, LE_32(efi_crc32((unsigned char *)efi,626headerSize)));627return (VT_EINVAL);628}629630return (0);631}632633static int634efi_read(int fd, struct dk_gpt *vtoc)635{636int i, j;637int label_len;638int rval = 0;639int md_flag = 0;640int vdc_flag = 0;641diskaddr_t capacity = 0;642uint_t lbsize = 0;643struct dk_minfo disk_info;644dk_efi_t dk_ioc;645efi_gpt_t *efi;646efi_gpe_t *efi_parts;647struct dk_cinfo dki_info;648uint32_t user_length;649boolean_t legacy_label = B_FALSE;650651/*652* get the partition number for this file descriptor.653*/654if ((rval = efi_get_info(fd, &dki_info)) != 0)655return (rval);656657if ((strncmp(dki_info.dki_cname, "pseudo", 7) == 0) &&658(strncmp(dki_info.dki_dname, "md", 3) == 0)) {659md_flag++;660} else if ((strncmp(dki_info.dki_cname, "vdc", 4) == 0) &&661(strncmp(dki_info.dki_dname, "vdc", 4) == 0)) {662/*663* The controller and drive name "vdc" (virtual disk client)664* indicates a LDoms virtual disk.665*/666vdc_flag++;667}668669/* get the LBA size */670if (read_disk_info(fd, &capacity, &lbsize) == -1) {671if (efi_debug) {672(void) fprintf(stderr,673"unable to read disk info: %d",674errno);675}676return (VT_EINVAL);677}678679disk_info.dki_lbsize = lbsize;680disk_info.dki_capacity = capacity;681682if (disk_info.dki_lbsize == 0) {683if (efi_debug) {684(void) fprintf(stderr,685"efi_read: assuming LBA 512 bytes\n");686}687disk_info.dki_lbsize = DEV_BSIZE;688}689/*690* Read the EFI GPT to figure out how many partitions we need691* to deal with.692*/693dk_ioc.dki_lba = 1;694if (NBLOCKS(vtoc->efi_nparts, disk_info.dki_lbsize) < 34) {695label_len = EFI_MIN_ARRAY_SIZE + disk_info.dki_lbsize;696} else {697label_len = vtoc->efi_nparts * (int) sizeof (efi_gpe_t) +698disk_info.dki_lbsize;699if (label_len % disk_info.dki_lbsize) {700/* pad to physical sector size */701label_len += disk_info.dki_lbsize;702label_len &= ~(disk_info.dki_lbsize - 1);703}704}705706if (posix_memalign((void **)&dk_ioc.dki_data,707disk_info.dki_lbsize, label_len))708return (VT_ERROR);709710memset(dk_ioc.dki_data, 0, label_len);711dk_ioc.dki_length = disk_info.dki_lbsize;712user_length = vtoc->efi_nparts;713efi = dk_ioc.dki_data;714if (md_flag) {715dk_ioc.dki_length = label_len;716if (efi_ioctl(fd, DKIOCGETEFI, &dk_ioc) == -1) {717switch (errno) {718case EIO:719return (VT_EIO);720default:721return (VT_ERROR);722}723}724} else if ((rval = check_label(fd, &dk_ioc)) == VT_EINVAL) {725/*726* No valid label here; try the alternate. Note that here727* we just read GPT header and save it into dk_ioc.data,728* Later, we will read GUID partition entry array if we729* can get valid GPT header.730*/731732/*733* This is a workaround for legacy systems. In the past, the734* last sector of SCSI disk was invisible on x86 platform. At735* that time, backup label was saved on the next to the last736* sector. It is possible for users to move a disk from previous737* solaris system to present system. Here, we attempt to search738* legacy backup EFI label first.739*/740dk_ioc.dki_lba = disk_info.dki_capacity - 2;741dk_ioc.dki_length = disk_info.dki_lbsize;742rval = check_label(fd, &dk_ioc);743if (rval == VT_EINVAL) {744/*745* we didn't find legacy backup EFI label, try to746* search backup EFI label in the last block.747*/748dk_ioc.dki_lba = disk_info.dki_capacity - 1;749dk_ioc.dki_length = disk_info.dki_lbsize;750rval = check_label(fd, &dk_ioc);751if (rval == 0) {752legacy_label = B_TRUE;753if (efi_debug)754(void) fprintf(stderr,755"efi_read: primary label corrupt; "756"using EFI backup label located on"757" the last block\n");758}759} else {760if ((efi_debug) && (rval == 0))761(void) fprintf(stderr, "efi_read: primary label"762" corrupt; using legacy EFI backup label "763" located on the next to last block\n");764}765766if (rval == 0) {767dk_ioc.dki_lba = LE_64(efi->efi_gpt_PartitionEntryLBA);768vtoc->efi_flags |= EFI_GPT_PRIMARY_CORRUPT;769vtoc->efi_nparts =770LE_32(efi->efi_gpt_NumberOfPartitionEntries);771/*772* Partition tables are between backup GPT header773* table and ParitionEntryLBA (the starting LBA of774* the GUID partition entries array). Now that we775* already got valid GPT header and saved it in776* dk_ioc.dki_data, we try to get GUID partition777* entry array here.778*/779/* LINTED */780dk_ioc.dki_data = (efi_gpt_t *)((char *)dk_ioc.dki_data781+ disk_info.dki_lbsize);782if (legacy_label)783dk_ioc.dki_length = disk_info.dki_capacity - 1 -784dk_ioc.dki_lba;785else786dk_ioc.dki_length = disk_info.dki_capacity - 2 -787dk_ioc.dki_lba;788dk_ioc.dki_length *= disk_info.dki_lbsize;789if (dk_ioc.dki_length >790((len_t)label_len - sizeof (*dk_ioc.dki_data))) {791rval = VT_EINVAL;792} else {793/*794* read GUID partition entry array795*/796rval = efi_ioctl(fd, DKIOCGETEFI, &dk_ioc);797}798}799800} else if (rval == 0) {801802dk_ioc.dki_lba = LE_64(efi->efi_gpt_PartitionEntryLBA);803/* LINTED */804dk_ioc.dki_data = (efi_gpt_t *)((char *)dk_ioc.dki_data805+ disk_info.dki_lbsize);806dk_ioc.dki_length = label_len - disk_info.dki_lbsize;807rval = efi_ioctl(fd, DKIOCGETEFI, &dk_ioc);808809} else if (vdc_flag && rval == VT_ERROR && errno == EINVAL) {810/*811* When the device is a LDoms virtual disk, the DKIOCGETEFI812* ioctl can fail with EINVAL if the virtual disk backend813* is a ZFS volume serviced by a domain running an old version814* of Solaris. This is because the DKIOCGETEFI ioctl was815* initially incorrectly implemented for a ZFS volume and it816* expected the GPT and GPE to be retrieved with a single ioctl.817* So we try to read the GPT and the GPE using that old style818* ioctl.819*/820dk_ioc.dki_lba = 1;821dk_ioc.dki_length = label_len;822rval = check_label(fd, &dk_ioc);823}824825if (rval < 0) {826free(efi);827return (rval);828}829830/* LINTED -- always longlong aligned */831efi_parts = (efi_gpe_t *)(((char *)efi) + disk_info.dki_lbsize);832833/*834* Assemble this into a "dk_gpt" struct for easier835* digestibility by applications.836*/837vtoc->efi_version = LE_32(efi->efi_gpt_Revision);838vtoc->efi_nparts = LE_32(efi->efi_gpt_NumberOfPartitionEntries);839vtoc->efi_part_size = LE_32(efi->efi_gpt_SizeOfPartitionEntry);840vtoc->efi_lbasize = disk_info.dki_lbsize;841vtoc->efi_last_lba = disk_info.dki_capacity - 1;842vtoc->efi_first_u_lba = LE_64(efi->efi_gpt_FirstUsableLBA);843vtoc->efi_last_u_lba = LE_64(efi->efi_gpt_LastUsableLBA);844vtoc->efi_altern_lba = LE_64(efi->efi_gpt_AlternateLBA);845UUID_LE_CONVERT(vtoc->efi_disk_uguid, efi->efi_gpt_DiskGUID);846847/*848* If the array the user passed in is too small, set the length849* to what it needs to be and return850*/851if (user_length < vtoc->efi_nparts) {852return (VT_EINVAL);853}854855for (i = 0; i < vtoc->efi_nparts; i++) {856UUID_LE_CONVERT(vtoc->efi_parts[i].p_guid,857efi_parts[i].efi_gpe_PartitionTypeGUID);858859for (j = 0;860j < sizeof (conversion_array)861/ sizeof (struct uuid_to_ptag); j++) {862863if (memcmp(&vtoc->efi_parts[i].p_guid,864&conversion_array[j].uuid,865sizeof (struct uuid)) == 0) {866vtoc->efi_parts[i].p_tag = j;867break;868}869}870if (vtoc->efi_parts[i].p_tag == V_UNASSIGNED)871continue;872vtoc->efi_parts[i].p_flag =873LE_16(efi_parts[i].efi_gpe_Attributes.PartitionAttrs);874vtoc->efi_parts[i].p_start =875LE_64(efi_parts[i].efi_gpe_StartingLBA);876vtoc->efi_parts[i].p_size =877LE_64(efi_parts[i].efi_gpe_EndingLBA) -878vtoc->efi_parts[i].p_start + 1;879for (j = 0; j < EFI_PART_NAME_LEN; j++) {880vtoc->efi_parts[i].p_name[j] =881(uchar_t)LE_16(882efi_parts[i].efi_gpe_PartitionName[j]);883}884885UUID_LE_CONVERT(vtoc->efi_parts[i].p_uguid,886efi_parts[i].efi_gpe_UniquePartitionGUID);887}888free(efi);889890return (dki_info.dki_partition);891}892893/* writes a "protective" MBR */894static int895write_pmbr(int fd, struct dk_gpt *vtoc)896{897dk_efi_t dk_ioc;898struct mboot mb;899uchar_t *cp;900diskaddr_t size_in_lba;901uchar_t *buf;902int len;903904len = (vtoc->efi_lbasize == 0) ? sizeof (mb) : vtoc->efi_lbasize;905if (posix_memalign((void **)&buf, len, len))906return (VT_ERROR);907908/*909* Preserve any boot code and disk signature if the first block is910* already an MBR.911*/912memset(buf, 0, len);913dk_ioc.dki_lba = 0;914dk_ioc.dki_length = len;915/* LINTED -- always longlong aligned */916dk_ioc.dki_data = (efi_gpt_t *)buf;917if (efi_ioctl(fd, DKIOCGETEFI, &dk_ioc) == -1) {918memset(&mb, 0, sizeof (mb));919mb.signature = LE_16(MBB_MAGIC);920} else {921(void) memcpy(&mb, buf, sizeof (mb));922if (mb.signature != LE_16(MBB_MAGIC)) {923memset(&mb, 0, sizeof (mb));924mb.signature = LE_16(MBB_MAGIC);925}926}927928memset(&mb.parts, 0, sizeof (mb.parts));929cp = (uchar_t *)&mb.parts[0];930/* bootable or not */931*cp++ = 0;932/* beginning CHS; 0xffffff if not representable */933*cp++ = 0xff;934*cp++ = 0xff;935*cp++ = 0xff;936/* OS type */937*cp++ = EFI_PMBR;938/* ending CHS; 0xffffff if not representable */939*cp++ = 0xff;940*cp++ = 0xff;941*cp++ = 0xff;942/* starting LBA: 1 (little endian format) by EFI definition */943*cp++ = 0x01;944*cp++ = 0x00;945*cp++ = 0x00;946*cp++ = 0x00;947/* ending LBA: last block on the disk (little endian format) */948size_in_lba = vtoc->efi_last_lba;949if (size_in_lba < 0xffffffff) {950*cp++ = (size_in_lba & 0x000000ff);951*cp++ = (size_in_lba & 0x0000ff00) >> 8;952*cp++ = (size_in_lba & 0x00ff0000) >> 16;953*cp++ = (size_in_lba & 0xff000000) >> 24;954} else {955*cp++ = 0xff;956*cp++ = 0xff;957*cp++ = 0xff;958*cp++ = 0xff;959}960961(void) memcpy(buf, &mb, sizeof (mb));962/* LINTED -- always longlong aligned */963dk_ioc.dki_data = (efi_gpt_t *)buf;964dk_ioc.dki_lba = 0;965dk_ioc.dki_length = len;966if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) {967free(buf);968switch (errno) {969case EIO:970return (VT_EIO);971case EINVAL:972return (VT_EINVAL);973default:974return (VT_ERROR);975}976}977free(buf);978return (0);979}980981/* make sure the user specified something reasonable */982static int983check_input(struct dk_gpt *vtoc)984{985int resv_part = -1;986int i, j;987diskaddr_t istart, jstart, isize, jsize, endsect;988989/*990* Sanity-check the input (make sure no partitions overlap)991*/992for (i = 0; i < vtoc->efi_nparts; i++) {993/* It can't be unassigned and have an actual size */994if ((vtoc->efi_parts[i].p_tag == V_UNASSIGNED) &&995(vtoc->efi_parts[i].p_size != 0)) {996if (efi_debug) {997(void) fprintf(stderr, "partition %d is "998"\"unassigned\" but has a size of %llu",999i, vtoc->efi_parts[i].p_size);1000}1001return (VT_EINVAL);1002}1003if (vtoc->efi_parts[i].p_tag == V_UNASSIGNED) {1004if (uuid_is_null((uchar_t *)&vtoc->efi_parts[i].p_guid))1005continue;1006/* we have encountered an unknown uuid */1007vtoc->efi_parts[i].p_tag = 0xff;1008}1009if (vtoc->efi_parts[i].p_tag == V_RESERVED) {1010if (resv_part != -1) {1011if (efi_debug) {1012(void) fprintf(stderr, "found "1013"duplicate reserved partition "1014"at %d\n", i);1015}1016return (VT_EINVAL);1017}1018resv_part = i;1019}1020if ((vtoc->efi_parts[i].p_start < vtoc->efi_first_u_lba) ||1021(vtoc->efi_parts[i].p_start > vtoc->efi_last_u_lba)) {1022if (efi_debug) {1023(void) fprintf(stderr,1024"Partition %d starts at %llu. ",1025i,1026vtoc->efi_parts[i].p_start);1027(void) fprintf(stderr,1028"It must be between %llu and %llu.\n",1029vtoc->efi_first_u_lba,1030vtoc->efi_last_u_lba);1031}1032return (VT_EINVAL);1033}1034if ((vtoc->efi_parts[i].p_start +1035vtoc->efi_parts[i].p_size <1036vtoc->efi_first_u_lba) ||1037(vtoc->efi_parts[i].p_start +1038vtoc->efi_parts[i].p_size >1039vtoc->efi_last_u_lba + 1)) {1040if (efi_debug) {1041(void) fprintf(stderr,1042"Partition %d ends at %llu. ",1043i,1044vtoc->efi_parts[i].p_start +1045vtoc->efi_parts[i].p_size);1046(void) fprintf(stderr,1047"It must be between %llu and %llu.\n",1048vtoc->efi_first_u_lba,1049vtoc->efi_last_u_lba);1050}1051return (VT_EINVAL);1052}10531054for (j = 0; j < vtoc->efi_nparts; j++) {1055isize = vtoc->efi_parts[i].p_size;1056jsize = vtoc->efi_parts[j].p_size;1057istart = vtoc->efi_parts[i].p_start;1058jstart = vtoc->efi_parts[j].p_start;1059if ((i != j) && (isize != 0) && (jsize != 0)) {1060endsect = jstart + jsize -1;1061if ((jstart <= istart) &&1062(istart <= endsect)) {1063if (efi_debug) {1064(void) fprintf(stderr,1065"Partition %d overlaps "1066"partition %d.", i, j);1067}1068return (VT_EINVAL);1069}1070}1071}1072}1073/* just a warning for now */1074if ((resv_part == -1) && efi_debug) {1075(void) fprintf(stderr,1076"no reserved partition found\n");1077}1078return (0);1079}10801081static int1082call_blkpg_ioctl(int fd, int command, diskaddr_t start,1083diskaddr_t size, uint_t pno)1084{1085struct blkpg_ioctl_arg ioctl_arg;1086struct blkpg_partition linux_part;1087memset(&linux_part, 0, sizeof (linux_part));10881089char *path = efi_get_devname(fd);1090if (path == NULL) {1091(void) fprintf(stderr, "failed to retrieve device name\n");1092return (VT_EINVAL);1093}10941095linux_part.start = start;1096linux_part.length = size;1097linux_part.pno = pno;1098snprintf(linux_part.devname, BLKPG_DEVNAMELTH - 1, "%s%u", path, pno);1099linux_part.devname[BLKPG_DEVNAMELTH - 1] = '\0';1100free(path);11011102ioctl_arg.op = command;1103ioctl_arg.flags = 0;1104ioctl_arg.datalen = sizeof (struct blkpg_partition);1105ioctl_arg.data = &linux_part;11061107return (ioctl(fd, BLKPG, &ioctl_arg));1108}11091110/*1111* add all the unallocated space to the current label1112*/1113int1114efi_use_whole_disk(int fd)1115{1116struct dk_gpt *efi_label = NULL;1117int rval;1118int i;1119uint_t resv_index = 0, data_index = 0;1120diskaddr_t resv_start = 0, data_start = 0;1121diskaddr_t data_size, limit, difference;1122boolean_t sync_needed = B_FALSE;1123uint_t nblocks;11241125rval = efi_alloc_and_read(fd, &efi_label);1126if (rval < 0) {1127if (efi_label != NULL)1128efi_free(efi_label);1129return (rval);1130}11311132/*1133* Find the last physically non-zero partition.1134* This should be the reserved partition.1135*/1136for (i = 0; i < efi_label->efi_nparts; i ++) {1137if (resv_start < efi_label->efi_parts[i].p_start) {1138resv_start = efi_label->efi_parts[i].p_start;1139resv_index = i;1140}1141}11421143/*1144* Find the last physically non-zero partition before that.1145* This is the data partition.1146*/1147for (i = 0; i < resv_index; i ++) {1148if (data_start < efi_label->efi_parts[i].p_start) {1149data_start = efi_label->efi_parts[i].p_start;1150data_index = i;1151}1152}1153data_size = efi_label->efi_parts[data_index].p_size;11541155/*1156* See the "efi_alloc_and_init" function for more information1157* about where this "nblocks" value comes from.1158*/1159nblocks = efi_label->efi_first_u_lba - 1;11601161/*1162* Determine if the EFI label is out of sync. We check that:1163*1164* 1. the data partition ends at the limit we set, and1165* 2. the reserved partition starts at the limit we set.1166*1167* If either of these conditions is not met, then we need to1168* resync the EFI label.1169*1170* The limit is the last usable LBA, determined by the last LBA1171* and the first usable LBA fields on the EFI label of the disk1172* (see the lines directly above). Additionally, we factor in1173* EFI_MIN_RESV_SIZE (per its use in "zpool_label_disk") and1174* P2ALIGN it to ensure the partition boundaries are aligned1175* (for performance reasons). The alignment should match the1176* alignment used by the "zpool_label_disk" function.1177*/1178limit = P2ALIGN_TYPED(efi_label->efi_last_lba - nblocks -1179EFI_MIN_RESV_SIZE, PARTITION_END_ALIGNMENT, diskaddr_t);1180if (data_start + data_size != limit || resv_start != limit)1181sync_needed = B_TRUE;11821183if (efi_debug && sync_needed)1184(void) fprintf(stderr, "efi_use_whole_disk: sync needed\n");11851186/*1187* If alter_lba is 1, we are using the backup label.1188* Since we can locate the backup label by disk capacity,1189* there must be no unallocated space.1190*/1191if ((efi_label->efi_altern_lba == 1) || (efi_label->efi_altern_lba1192>= efi_label->efi_last_lba && !sync_needed)) {1193if (efi_debug) {1194(void) fprintf(stderr,1195"efi_use_whole_disk: requested space not found\n");1196}1197efi_free(efi_label);1198return (VT_ENOSPC);1199}12001201/*1202* Verify that we've found the reserved partition by checking1203* that it looks the way it did when we created it in zpool_label_disk.1204* If we've found the incorrect partition, then we know that this1205* device was reformatted and no longer is solely used by ZFS.1206*/1207if ((efi_label->efi_parts[resv_index].p_size != EFI_MIN_RESV_SIZE) ||1208(efi_label->efi_parts[resv_index].p_tag != V_RESERVED) ||1209(resv_index != 8)) {1210if (efi_debug) {1211(void) fprintf(stderr,1212"efi_use_whole_disk: wholedisk not available\n");1213}1214efi_free(efi_label);1215return (VT_ENOSPC);1216}12171218if (data_start + data_size != resv_start) {1219if (efi_debug) {1220(void) fprintf(stderr,1221"efi_use_whole_disk: "1222"data_start (%lli) + "1223"data_size (%lli) != "1224"resv_start (%lli)\n",1225data_start, data_size, resv_start);1226}12271228return (VT_EINVAL);1229}12301231if (limit < resv_start) {1232if (efi_debug) {1233(void) fprintf(stderr,1234"efi_use_whole_disk: "1235"limit (%lli) < resv_start (%lli)\n",1236limit, resv_start);1237}12381239return (VT_EINVAL);1240}12411242difference = limit - resv_start;12431244if (efi_debug)1245(void) fprintf(stderr,1246"efi_use_whole_disk: difference is %lli\n", difference);12471248/*1249* Move the reserved partition. There is currently no data in1250* here except fabricated devids (which get generated via1251* efi_write()). So there is no need to copy data.1252*/1253efi_label->efi_parts[data_index].p_size += difference;1254efi_label->efi_parts[resv_index].p_start += difference;1255efi_label->efi_last_u_lba = efi_label->efi_last_lba - nblocks;12561257/*1258* Rescanning the partition table in the kernel can result1259* in the device links to be removed (see comment in vdev_disk_open).1260* If BLKPG_RESIZE_PARTITION is available, then we can resize1261* the partition table online and avoid having to remove the device1262* links used by the pool. This provides a very deterministic1263* approach to resizing devices and does not require any1264* loops waiting for devices to reappear.1265*/1266#ifdef BLKPG_RESIZE_PARTITION1267/*1268* Delete the reserved partition since we're about to expand1269* the data partition and it would overlap with the reserved1270* partition.1271* NOTE: The starting index for the ioctl is 1 while for the1272* EFI partitions it's 0. For that reason we have to add one1273* whenever we make an ioctl call.1274*/1275rval = call_blkpg_ioctl(fd, BLKPG_DEL_PARTITION, 0, 0, resv_index + 1);1276if (rval != 0)1277goto out;12781279/*1280* Expand the data partition1281*/1282rval = call_blkpg_ioctl(fd, BLKPG_RESIZE_PARTITION,1283efi_label->efi_parts[data_index].p_start * efi_label->efi_lbasize,1284efi_label->efi_parts[data_index].p_size * efi_label->efi_lbasize,1285data_index + 1);1286if (rval != 0) {1287(void) fprintf(stderr, "Unable to resize data "1288"partition: %d\n", rval);1289/*1290* Since we failed to resize, we need to reset the start1291* of the reserve partition and re-create it.1292*/1293efi_label->efi_parts[resv_index].p_start -= difference;1294}12951296/*1297* Re-add the reserved partition. If we've expanded the data partition1298* then we'll move the reserve partition to the end of the data1299* partition. Otherwise, we'll recreate the partition in its original1300* location. Note that we do this as best-effort and ignore any1301* errors that may arise here. This will ensure that we finish writing1302* the EFI label.1303*/1304(void) call_blkpg_ioctl(fd, BLKPG_ADD_PARTITION,1305efi_label->efi_parts[resv_index].p_start * efi_label->efi_lbasize,1306efi_label->efi_parts[resv_index].p_size * efi_label->efi_lbasize,1307resv_index + 1);1308#endif13091310/*1311* We're now ready to write the EFI label.1312*/1313if (rval == 0) {1314rval = efi_write(fd, efi_label);1315if (rval < 0 && efi_debug) {1316(void) fprintf(stderr, "efi_use_whole_disk:fail "1317"to write label, rval=%d\n", rval);1318}1319}13201321out:1322efi_free(efi_label);1323return (rval);1324}13251326/*1327* write EFI label and backup label1328*/1329int1330efi_write(int fd, struct dk_gpt *vtoc)1331{1332dk_efi_t dk_ioc;1333efi_gpt_t *efi;1334efi_gpe_t *efi_parts;1335int i, j;1336struct dk_cinfo dki_info;1337int rval;1338int md_flag = 0;1339int nblocks;1340diskaddr_t lba_backup_gpt_hdr;13411342if ((rval = efi_get_info(fd, &dki_info)) != 0)1343return (rval);13441345/* check if we are dealing with a metadevice */1346if ((strncmp(dki_info.dki_cname, "pseudo", 7) == 0) &&1347(strncmp(dki_info.dki_dname, "md", 3) == 0)) {1348md_flag = 1;1349}13501351if (check_input(vtoc)) {1352/*1353* not valid; if it's a metadevice just pass it down1354* because SVM will do its own checking1355*/1356if (md_flag == 0) {1357return (VT_EINVAL);1358}1359}13601361dk_ioc.dki_lba = 1;1362if (NBLOCKS(vtoc->efi_nparts, vtoc->efi_lbasize) < 34) {1363dk_ioc.dki_length = EFI_MIN_ARRAY_SIZE + vtoc->efi_lbasize;1364} else {1365dk_ioc.dki_length = (len_t)NBLOCKS(vtoc->efi_nparts,1366vtoc->efi_lbasize) *1367vtoc->efi_lbasize;1368}13691370/*1371* the number of blocks occupied by GUID partition entry array1372*/1373nblocks = dk_ioc.dki_length / vtoc->efi_lbasize - 1;13741375/*1376* Backup GPT header is located on the block after GUID1377* partition entry array. Here, we calculate the address1378* for backup GPT header.1379*/1380lba_backup_gpt_hdr = vtoc->efi_last_u_lba + 1 + nblocks;1381if (posix_memalign((void **)&dk_ioc.dki_data,1382vtoc->efi_lbasize, dk_ioc.dki_length))1383return (VT_ERROR);13841385memset(dk_ioc.dki_data, 0, dk_ioc.dki_length);1386efi = dk_ioc.dki_data;13871388/* stuff user's input into EFI struct */1389efi->efi_gpt_Signature = LE_64(EFI_SIGNATURE);1390efi->efi_gpt_Revision = LE_32(vtoc->efi_version); /* 0x02000100 */1391efi->efi_gpt_HeaderSize = LE_32(sizeof (struct efi_gpt) - LEN_EFI_PAD);1392efi->efi_gpt_Reserved1 = 0;1393efi->efi_gpt_MyLBA = LE_64(1ULL);1394efi->efi_gpt_AlternateLBA = LE_64(lba_backup_gpt_hdr);1395efi->efi_gpt_FirstUsableLBA = LE_64(vtoc->efi_first_u_lba);1396efi->efi_gpt_LastUsableLBA = LE_64(vtoc->efi_last_u_lba);1397efi->efi_gpt_PartitionEntryLBA = LE_64(2ULL);1398efi->efi_gpt_NumberOfPartitionEntries = LE_32(vtoc->efi_nparts);1399efi->efi_gpt_SizeOfPartitionEntry = LE_32(sizeof (struct efi_gpe));1400UUID_LE_CONVERT(efi->efi_gpt_DiskGUID, vtoc->efi_disk_uguid);14011402/* LINTED -- always longlong aligned */1403efi_parts = (efi_gpe_t *)((char *)dk_ioc.dki_data + vtoc->efi_lbasize);14041405for (i = 0; i < vtoc->efi_nparts; i++) {1406for (j = 0;1407j < sizeof (conversion_array) /1408sizeof (struct uuid_to_ptag); j++) {14091410if (vtoc->efi_parts[i].p_tag == j) {1411UUID_LE_CONVERT(1412efi_parts[i].efi_gpe_PartitionTypeGUID,1413conversion_array[j].uuid);1414break;1415}1416}14171418if (j == sizeof (conversion_array) /1419sizeof (struct uuid_to_ptag)) {1420/*1421* If we didn't have a matching uuid match, bail here.1422* Don't write a label with unknown uuid.1423*/1424if (efi_debug) {1425(void) fprintf(stderr,1426"Unknown uuid for p_tag %d\n",1427vtoc->efi_parts[i].p_tag);1428}1429return (VT_EINVAL);1430}14311432/* Zero's should be written for empty partitions */1433if (vtoc->efi_parts[i].p_tag == V_UNASSIGNED)1434continue;14351436efi_parts[i].efi_gpe_StartingLBA =1437LE_64(vtoc->efi_parts[i].p_start);1438efi_parts[i].efi_gpe_EndingLBA =1439LE_64(vtoc->efi_parts[i].p_start +1440vtoc->efi_parts[i].p_size - 1);1441efi_parts[i].efi_gpe_Attributes.PartitionAttrs =1442LE_16(vtoc->efi_parts[i].p_flag);1443for (j = 0; j < EFI_PART_NAME_LEN; j++) {1444efi_parts[i].efi_gpe_PartitionName[j] =1445LE_16((ushort_t)vtoc->efi_parts[i].p_name[j]);1446}1447if ((vtoc->efi_parts[i].p_tag != V_UNASSIGNED) &&1448uuid_is_null((uchar_t *)&vtoc->efi_parts[i].p_uguid)) {1449(void) uuid_generate((uchar_t *)1450&vtoc->efi_parts[i].p_uguid);1451}1452memcpy(&efi_parts[i].efi_gpe_UniquePartitionGUID,1453&vtoc->efi_parts[i].p_uguid,1454sizeof (uuid_t));1455}1456efi->efi_gpt_PartitionEntryArrayCRC32 =1457LE_32(efi_crc32((unsigned char *)efi_parts,1458vtoc->efi_nparts * (int)sizeof (struct efi_gpe)));1459efi->efi_gpt_HeaderCRC32 =1460LE_32(efi_crc32((unsigned char *)efi,1461LE_32(efi->efi_gpt_HeaderSize)));14621463if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) {1464free(dk_ioc.dki_data);1465switch (errno) {1466case EIO:1467return (VT_EIO);1468case EINVAL:1469return (VT_EINVAL);1470default:1471return (VT_ERROR);1472}1473}1474/* if it's a metadevice we're done */1475if (md_flag) {1476free(dk_ioc.dki_data);1477return (0);1478}14791480/* write backup partition array */1481dk_ioc.dki_lba = vtoc->efi_last_u_lba + 1;1482dk_ioc.dki_length -= vtoc->efi_lbasize;1483/* LINTED */1484dk_ioc.dki_data = (efi_gpt_t *)((char *)dk_ioc.dki_data +1485vtoc->efi_lbasize);14861487if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) {1488/*1489* we wrote the primary label okay, so don't fail1490*/1491if (efi_debug) {1492(void) fprintf(stderr,1493"write of backup partitions to block %llu "1494"failed, errno %d\n",1495vtoc->efi_last_u_lba + 1,1496errno);1497}1498}1499/*1500* now swap MyLBA and AlternateLBA fields and write backup1501* partition table header1502*/1503dk_ioc.dki_lba = lba_backup_gpt_hdr;1504dk_ioc.dki_length = vtoc->efi_lbasize;1505/* LINTED */1506dk_ioc.dki_data = (efi_gpt_t *)((char *)dk_ioc.dki_data -1507vtoc->efi_lbasize);1508efi->efi_gpt_AlternateLBA = LE_64(1ULL);1509efi->efi_gpt_MyLBA = LE_64(lba_backup_gpt_hdr);1510efi->efi_gpt_PartitionEntryLBA = LE_64(vtoc->efi_last_u_lba + 1);1511efi->efi_gpt_HeaderCRC32 = 0;1512efi->efi_gpt_HeaderCRC32 =1513LE_32(efi_crc32((unsigned char *)dk_ioc.dki_data,1514LE_32(efi->efi_gpt_HeaderSize)));15151516if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) {1517if (efi_debug) {1518(void) fprintf(stderr,1519"write of backup header to block %llu failed, "1520"errno %d\n",1521lba_backup_gpt_hdr,1522errno);1523}1524}1525/* write the PMBR */1526(void) write_pmbr(fd, vtoc);1527free(dk_ioc.dki_data);15281529return (0);1530}15311532void1533efi_free(struct dk_gpt *ptr)1534{1535free(ptr);1536}15371538void1539efi_err_check(struct dk_gpt *vtoc)1540{1541int resv_part = -1;1542int i, j;1543diskaddr_t istart, jstart, isize, jsize, endsect;1544int overlap = 0;15451546/*1547* make sure no partitions overlap1548*/1549for (i = 0; i < vtoc->efi_nparts; i++) {1550/* It can't be unassigned and have an actual size */1551if ((vtoc->efi_parts[i].p_tag == V_UNASSIGNED) &&1552(vtoc->efi_parts[i].p_size != 0)) {1553(void) fprintf(stderr,1554"partition %d is \"unassigned\" but has a size "1555"of %llu\n", i, vtoc->efi_parts[i].p_size);1556}1557if (vtoc->efi_parts[i].p_tag == V_UNASSIGNED) {1558continue;1559}1560if (vtoc->efi_parts[i].p_tag == V_RESERVED) {1561if (resv_part != -1) {1562(void) fprintf(stderr,1563"found duplicate reserved partition at "1564"%d\n", i);1565}1566resv_part = i;1567if (vtoc->efi_parts[i].p_size != EFI_MIN_RESV_SIZE)1568(void) fprintf(stderr,1569"Warning: reserved partition size must "1570"be %d sectors\n", EFI_MIN_RESV_SIZE);1571}1572if ((vtoc->efi_parts[i].p_start < vtoc->efi_first_u_lba) ||1573(vtoc->efi_parts[i].p_start > vtoc->efi_last_u_lba)) {1574(void) fprintf(stderr,1575"Partition %d starts at %llu\n",1576i,1577vtoc->efi_parts[i].p_start);1578(void) fprintf(stderr,1579"It must be between %llu and %llu.\n",1580vtoc->efi_first_u_lba,1581vtoc->efi_last_u_lba);1582}1583if ((vtoc->efi_parts[i].p_start +1584vtoc->efi_parts[i].p_size <1585vtoc->efi_first_u_lba) ||1586(vtoc->efi_parts[i].p_start +1587vtoc->efi_parts[i].p_size >1588vtoc->efi_last_u_lba + 1)) {1589(void) fprintf(stderr,1590"Partition %d ends at %llu\n",1591i,1592vtoc->efi_parts[i].p_start +1593vtoc->efi_parts[i].p_size);1594(void) fprintf(stderr,1595"It must be between %llu and %llu.\n",1596vtoc->efi_first_u_lba,1597vtoc->efi_last_u_lba);1598}15991600for (j = 0; j < vtoc->efi_nparts; j++) {1601isize = vtoc->efi_parts[i].p_size;1602jsize = vtoc->efi_parts[j].p_size;1603istart = vtoc->efi_parts[i].p_start;1604jstart = vtoc->efi_parts[j].p_start;1605if ((i != j) && (isize != 0) && (jsize != 0)) {1606endsect = jstart + jsize -1;1607if ((jstart <= istart) &&1608(istart <= endsect)) {1609if (!overlap) {1610(void) fprintf(stderr,1611"label error: EFI Labels do not "1612"support overlapping partitions\n");1613}1614(void) fprintf(stderr,1615"Partition %d overlaps partition "1616"%d.\n", i, j);1617overlap = 1;1618}1619}1620}1621}1622/* make sure there is a reserved partition */1623if (resv_part == -1) {1624(void) fprintf(stderr,1625"no reserved partition found\n");1626}1627}162816291630