/*
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
*/
#include <stdio.h>
{ EFI_DELL_LVM },
{ EFI_DELL_RESV },
{ EFI_AAPL_HFS },
- { EFI_AAPL_UFS }
+ { EFI_AAPL_UFS },
+ { EFI_FREEBSD_BOOT },
+ { EFI_FREEBSD_SWAP },
+ { EFI_FREEBSD_UFS },
+ { EFI_FREEBSD_VINUM },
+ { EFI_FREEBSD_ZFS },
+ { EFI_BIOS_BOOT },
+ { EFI_INTC_RS },
+ { EFI_SNE_BOOT },
+ { EFI_LENOVO_BOOT },
+ { EFI_MSFT_LDMM },
+ { EFI_MSFT_LDMD },
+ { EFI_MSFT_RE },
+ { EFI_IBM_GPFS },
+ { EFI_MSFT_STORAGESPACES },
+ { EFI_HPQ_DATA },
+ { EFI_HPQ_SVC },
+ { EFI_RHT_DATA },
+ { EFI_RHT_HOME },
+ { EFI_RHT_SRV },
+ { EFI_RHT_DMCRYPT },
+ { EFI_RHT_LUKS },
+ { EFI_FREEBSD_DISKLABEL },
+ { EFI_AAPL_RAID },
+ { EFI_AAPL_RAIDOFFLINE },
+ { EFI_AAPL_BOOT },
+ { EFI_AAPL_LABEL },
+ { EFI_AAPL_TVRECOVERY },
+ { EFI_AAPL_CORESTORAGE },
+ { EFI_NETBSD_SWAP },
+ { EFI_NETBSD_FFS },
+ { EFI_NETBSD_LFS },
+ { EFI_NETBSD_RAID },
+ { EFI_NETBSD_CAT },
+ { EFI_NETBSD_CRYPT },
+ { EFI_GOOG_KERN },
+ { EFI_GOOG_ROOT },
+ { EFI_GOOG_RESV },
+ { EFI_HAIKU_BFS },
+ { EFI_MIDNIGHTBSD_BOOT },
+ { EFI_MIDNIGHTBSD_DATA },
+ { EFI_MIDNIGHTBSD_SWAP },
+ { EFI_MIDNIGHTBSD_UFS },
+ { EFI_MIDNIGHTBSD_VINUM },
+ { EFI_MIDNIGHTBSD_ZFS },
+ { EFI_CEPH_JOURNAL },
+ { EFI_CEPH_DMCRYPTJOURNAL },
+ { EFI_CEPH_OSD },
+ { EFI_CEPH_DMCRYPTOSD },
+ { EFI_CEPH_CREATE },
+ { EFI_CEPH_DMCRYPTCREATE },
+ { EFI_OPENBSD_DISKLABEL },
+ { EFI_BBRY_QNX },
+ { EFI_BELL_PLAN9 },
+ { EFI_VMW_KCORE },
+ { EFI_VMW_VMFS },
+ { EFI_VMW_RESV },
+ { EFI_RHT_ROOTX86 },
+ { EFI_RHT_ROOTAMD64 },
+ { EFI_RHT_ROOTARM },
+ { EFI_RHT_ROOTARM64 },
+ { EFI_ACRONIS_SECUREZONE },
+ { EFI_ONIE_BOOT },
+ { EFI_ONIE_CONFIG },
+ { EFI_IBM_PPRPBOOT },
+ { EFI_FREEDESKTOP_BOOT }
};
/*
#if defined(_SUNOS_VTOC_16)
-#if defined(i386) || defined(__amd64) || defined(__arm)
+#if defined(i386) || defined(__amd64) || defined(__arm) || \
+ defined(__powerpc) || defined(__sparc) || defined(__s390__) || \
+ defined(__mips__)
{ V_BOOT, V_UNMNT }, /* i - 8 */
{ V_ALTSCTR, 0 }, /* j - 9 */
#endif /* defined(_SUNOS_VTOC_16) */
};
-#ifdef DEBUG
-int efi_debug = 1;
-#else
int efi_debug = 0;
-#endif
static int efi_read(int, struct dk_gpt *);
int sector_size;
unsigned long long capacity_size;
- if (ioctl(fd, BLKSSZGET, §or_size) < 0)
- return (-1);
+ if (ioctl(fd, BLKSSZGET, §or_size) < 0)
+ return (-1);
if (ioctl(fd, BLKGETSIZE64, &capacity_size) < 0)
return (-1);
char *dev_path;
int rval = 0;
- memset(dki_info, 0, sizeof(*dki_info));
+ memset(dki_info, 0, sizeof (*dki_info));
path = calloc(PATH_MAX, 1);
if (path == NULL)
strcpy(dki_info->dki_cname, "sd");
dki_info->dki_ctype = DKC_SCSI_CCS;
rval = sscanf(dev_path, "/dev/%[a-zA-Z]%hu",
- dki_info->dki_dname,
- &dki_info->dki_partition);
+ dki_info->dki_dname,
+ &dki_info->dki_partition);
} else if ((strncmp(dev_path, "/dev/hd", 7) == 0)) {
strcpy(dki_info->dki_cname, "hd");
dki_info->dki_ctype = DKC_DIRECT;
rval = sscanf(dev_path, "/dev/%[a-zA-Z]%hu",
- dki_info->dki_dname,
- &dki_info->dki_partition);
+ dki_info->dki_dname,
+ &dki_info->dki_partition);
} else if ((strncmp(dev_path, "/dev/md", 7) == 0)) {
strcpy(dki_info->dki_cname, "pseudo");
dki_info->dki_ctype = DKC_MD;
- rval = sscanf(dev_path, "/dev/%[a-zA-Z0-9]p%hu",
- dki_info->dki_dname,
- &dki_info->dki_partition);
+ strcpy(dki_info->dki_dname, "md");
+ rval = sscanf(dev_path, "/dev/md%[0-9]p%hu",
+ dki_info->dki_dname + 2,
+ &dki_info->dki_partition);
} else if ((strncmp(dev_path, "/dev/vd", 7) == 0)) {
strcpy(dki_info->dki_cname, "vd");
dki_info->dki_ctype = DKC_MD;
rval = sscanf(dev_path, "/dev/%[a-zA-Z]%hu",
- dki_info->dki_dname,
- &dki_info->dki_partition);
+ dki_info->dki_dname,
+ &dki_info->dki_partition);
+ } else if ((strncmp(dev_path, "/dev/xvd", 8) == 0)) {
+ strcpy(dki_info->dki_cname, "xvd");
+ dki_info->dki_ctype = DKC_MD;
+ rval = sscanf(dev_path, "/dev/%[a-zA-Z]%hu",
+ dki_info->dki_dname,
+ &dki_info->dki_partition);
+ } else if ((strncmp(dev_path, "/dev/zd", 7) == 0)) {
+ strcpy(dki_info->dki_cname, "zd");
+ dki_info->dki_ctype = DKC_MD;
+ rval = sscanf(dev_path, "/dev/%[a-zA-Z]%hu",
+ dki_info->dki_dname,
+ &dki_info->dki_partition);
} else if ((strncmp(dev_path, "/dev/dm-", 8) == 0)) {
strcpy(dki_info->dki_cname, "pseudo");
dki_info->dki_ctype = DKC_VBD;
- rval = sscanf(dev_path, "/dev/%[a-zA-Z0-9-]p%hu",
- dki_info->dki_dname,
- &dki_info->dki_partition);
+ strcpy(dki_info->dki_dname, "dm-");
+ rval = sscanf(dev_path, "/dev/dm-%[0-9]p%hu",
+ dki_info->dki_dname + 3,
+ &dki_info->dki_partition);
} else if ((strncmp(dev_path, "/dev/ram", 8) == 0)) {
strcpy(dki_info->dki_cname, "pseudo");
dki_info->dki_ctype = DKC_PCMCIA_MEM;
- rval = sscanf(dev_path, "/dev/%[a-zA-Z0-9]p%hu",
- dki_info->dki_dname,
- &dki_info->dki_partition);
+ strcpy(dki_info->dki_dname, "ram");
+ rval = sscanf(dev_path, "/dev/ram%[0-9]p%hu",
+ dki_info->dki_dname + 3,
+ &dki_info->dki_partition);
} else if ((strncmp(dev_path, "/dev/loop", 9) == 0)) {
strcpy(dki_info->dki_cname, "pseudo");
dki_info->dki_ctype = DKC_VBD;
- rval = sscanf(dev_path, "/dev/%[a-zA-Z0-9]p%hu",
- dki_info->dki_dname,
- &dki_info->dki_partition);
+ strcpy(dki_info->dki_dname, "loop");
+ rval = sscanf(dev_path, "/dev/loop%[0-9]p%hu",
+ dki_info->dki_dname + 4,
+ &dki_info->dki_partition);
+ } else if ((strncmp(dev_path, "/dev/nvme", 9) == 0)) {
+ strcpy(dki_info->dki_cname, "nvme");
+ dki_info->dki_ctype = DKC_SCSI_CCS;
+ strcpy(dki_info->dki_dname, "nvme");
+ (void) sscanf(dev_path, "/dev/nvme%[0-9]",
+ dki_info->dki_dname + 4);
+ size_t controller_length = strlen(
+ dki_info->dki_dname);
+ strcpy(dki_info->dki_dname + controller_length,
+ "n");
+ rval = sscanf(dev_path,
+ "/dev/nvme%*[0-9]n%[0-9]p%hu",
+ dki_info->dki_dname + controller_length + 1,
+ &dki_info->dki_partition);
} else {
strcpy(dki_info->dki_dname, "unknown");
strcpy(dki_info->dki_cname, "unknown");
*/
if (read_disk_info(fd, &capacity, &lbsize) == -1) {
if (efi_debug)
- fprintf(stderr,"unable to read disk info: %d",errno);
+ fprintf(stderr, "unable to read disk info: %d", errno);
errno = EIO;
- return -1;
+ return (-1);
}
switch (cmd) {
if (lbsize == 0) {
if (efi_debug)
(void) fprintf(stderr, "DKIOCGETEFI assuming "
- "LBA %d bytes\n", DEV_BSIZE);
+ "LBA %d bytes\n", DEV_BSIZE);
lbsize = DEV_BSIZE;
}
if (error == -1) {
if (efi_debug)
(void) fprintf(stderr, "DKIOCGETEFI lseek "
- "error: %d\n", errno);
- return error;
+ "error: %d\n", errno);
+ return (error);
}
error = read(fd, data, dk_ioc->dki_length);
if (error == -1) {
if (efi_debug)
(void) fprintf(stderr, "DKIOCGETEFI read "
- "error: %d\n", errno);
- return error;
+ "error: %d\n", errno);
+ return (error);
}
if (error != dk_ioc->dki_length) {
if (efi_debug)
(void) fprintf(stderr, "DKIOCGETEFI short "
- "read of %d bytes\n", error);
+ "read of %d bytes\n", error);
errno = EIO;
- return -1;
+ return (-1);
}
error = 0;
break;
if (lbsize == 0) {
if (efi_debug)
(void) fprintf(stderr, "DKIOCSETEFI unknown "
- "LBA size\n");
+ "LBA size\n");
errno = EIO;
- return -1;
+ return (-1);
}
error = lseek(fd, dk_ioc->dki_lba * lbsize, SEEK_SET);
if (error == -1) {
if (efi_debug)
(void) fprintf(stderr, "DKIOCSETEFI lseek "
- "error: %d\n", errno);
- return error;
+ "error: %d\n", errno);
+ return (error);
}
error = write(fd, data, dk_ioc->dki_length);
if (error == -1) {
if (efi_debug)
(void) fprintf(stderr, "DKIOCSETEFI write "
- "error: %d\n", errno);
- return error;
+ "error: %d\n", errno);
+ return (error);
}
if (error != dk_ioc->dki_length) {
if (efi_debug)
(void) fprintf(stderr, "DKIOCSETEFI short "
- "write of %d bytes\n", error);
+ "write of %d bytes\n", error);
errno = EIO;
- return -1;
+ return (-1);
}
/* Sync the new EFI table to disk */
error = fsync(fd);
if (error == -1)
- return error;
+ return (error);
/* Ensure any local disk cache is also flushed */
if (ioctl(fd, BLKFLSBUF, 0) == -1)
- return error;
+ return (error);
error = 0;
break;
(void) fprintf(stderr, "unsupported ioctl()\n");
errno = EIO;
- return -1;
+ return (-1);
}
#else
dk_ioc->dki_data_64 = (uint64_t)(uintptr_t)data;
return (error);
}
-#if defined(__linux__)
-static int
+int
efi_rescan(int fd)
{
- int retry = 5;
+#if defined(__linux__)
+ int retry = 10;
int error;
/* Notify the kernel a devices partition table has been updated */
while ((error = ioctl(fd, BLKRRPART)) != 0) {
- if (--retry == 0) {
+ if ((--retry == 0) || (errno != EBUSY)) {
(void) fprintf(stderr, "the kernel failed to rescan "
- "the partition table: %d\n", errno);
+ "the partition table: %d\n", errno);
return (-1);
}
+ usleep(50000);
}
+#endif
return (0);
}
-#endif
static int
check_label(int fd, dk_efi_t *dk_ioc)
efi->efi_gpt_HeaderCRC32 = 0;
len_t headerSize = (len_t)LE_32(efi->efi_gpt_HeaderSize);
- if(headerSize < EFI_MIN_LABEL_SIZE || headerSize > EFI_LABEL_SIZE) {
+ if (headerSize < EFI_MIN_LABEL_SIZE || headerSize > EFI_LABEL_SIZE) {
if (efi_debug)
(void) fprintf(stderr,
- "Invalid EFI HeaderSize %llu. Assuming %d.\n",
- headerSize, EFI_MIN_LABEL_SIZE);
+ "Invalid EFI HeaderSize %llu. Assuming %d.\n",
+ headerSize, EFI_MIN_LABEL_SIZE);
}
if ((headerSize > dk_ioc->dki_length) ||
* get the partition number for this file descriptor.
*/
if ((rval = efi_get_info(fd, &dki_info)) != 0)
- return rval;
+ return (rval);
if ((strncmp(dki_info.dki_cname, "pseudo", 7) == 0) &&
(strncmp(dki_info.dki_dname, "md", 3) == 0)) {
if (read_disk_info(fd, &capacity, &lbsize) == -1) {
if (efi_debug) {
(void) fprintf(stderr,
- "unable to read disk info: %d",
- errno);
+ "unable to read disk info: %d",
+ errno);
}
return (VT_EINVAL);
}
}
if (posix_memalign((void **)&dk_ioc.dki_data,
- disk_info.dki_lbsize, label_len))
+ disk_info.dki_lbsize, label_len))
return (VT_ERROR);
memset(dk_ioc.dki_data, 0, label_len);
/* LINTED -- always longlong aligned */
dk_ioc.dki_data = (efi_gpt_t *)buf;
if (efi_ioctl(fd, DKIOCGETEFI, &dk_ioc) == -1) {
- (void *) memcpy(&mb, buf, sizeof (mb));
+ (void) memcpy(&mb, buf, sizeof (mb));
bzero(&mb, sizeof (mb));
mb.signature = LE_16(MBB_MAGIC);
} else {
- (void *) memcpy(&mb, buf, sizeof (mb));
+ (void) memcpy(&mb, buf, sizeof (mb));
if (mb.signature != LE_16(MBB_MAGIC)) {
bzero(&mb, sizeof (mb));
mb.signature = LE_16(MBB_MAGIC);
*cp++ = 0xff;
}
- (void *) memcpy(buf, &mb, sizeof (mb));
+ (void) memcpy(buf, &mb, sizeof (mb));
/* LINTED -- always longlong aligned */
dk_ioc.dki_data = (efi_gpt_t *)buf;
dk_ioc.dki_lba = 0;
int
efi_use_whole_disk(int fd)
{
- struct dk_gpt *efi_label;
+ struct dk_gpt *efi_label = NULL;
int rval;
int i;
- uint_t phy_last_slice = 0;
- diskaddr_t pl_start = 0;
- diskaddr_t pl_size;
+ uint_t resv_index = 0, data_index = 0;
+ diskaddr_t resv_start = 0, data_start = 0;
+ diskaddr_t difference;
rval = efi_alloc_and_read(fd, &efi_label);
if (rval < 0) {
+ if (efi_label != NULL)
+ efi_free(efi_label);
return (rval);
}
- /* find the last physically non-zero partition */
- for (i = 0; i < efi_label->efi_nparts - 2; i ++) {
- if (pl_start < efi_label->efi_parts[i].p_start) {
- pl_start = efi_label->efi_parts[i].p_start;
- phy_last_slice = i;
- }
- }
- pl_size = efi_label->efi_parts[phy_last_slice].p_size;
-
/*
* If alter_lba is 1, we are using the backup label.
* Since we can locate the backup label by disk capacity,
return (VT_ENOSPC);
}
+ difference = efi_label->efi_last_lba - efi_label->efi_altern_lba;
+
+ /*
+ * Find the last physically non-zero partition.
+ * This is the reserved partition.
+ */
+ for (i = 0; i < efi_label->efi_nparts; i ++) {
+ if (resv_start < efi_label->efi_parts[i].p_start) {
+ resv_start = efi_label->efi_parts[i].p_start;
+ resv_index = i;
+ }
+ }
+
/*
- * If there is space between the last physically non-zero partition
- * and the reserved partition, just add the unallocated space to this
- * area. Otherwise, the unallocated space is added to the last
- * physically non-zero partition.
+ * Find the last physically non-zero partition before that.
+ * This is the data partition.
*/
- if (pl_start + pl_size - 1 == efi_label->efi_last_u_lba -
- EFI_MIN_RESV_SIZE) {
- efi_label->efi_parts[phy_last_slice].p_size +=
- efi_label->efi_last_lba - efi_label->efi_altern_lba;
+ for (i = 0; i < resv_index; i ++) {
+ if (data_start < efi_label->efi_parts[i].p_start) {
+ data_start = efi_label->efi_parts[i].p_start;
+ data_index = i;
+ }
}
/*
* here except fabricated devids (which get generated via
* efi_write()). So there is no need to copy data.
*/
- efi_label->efi_parts[efi_label->efi_nparts - 1].p_start +=
- efi_label->efi_last_lba - efi_label->efi_altern_lba;
- efi_label->efi_last_u_lba += efi_label->efi_last_lba
- - efi_label->efi_altern_lba;
+ efi_label->efi_parts[data_index].p_size += difference;
+ efi_label->efi_parts[resv_index].p_start += difference;
+ efi_label->efi_last_u_lba += difference;
rval = efi_write(fd, efi_label);
if (rval < 0) {
diskaddr_t lba_backup_gpt_hdr;
if ((rval = efi_get_info(fd, &dki_info)) != 0)
- return rval;
+ return (rval);
/* check if we are dealing wih a metadevice */
if ((strncmp(dki_info.dki_cname, "pseudo", 7) == 0) &&
*/
lba_backup_gpt_hdr = vtoc->efi_last_u_lba + 1 + nblocks;
if (posix_memalign((void **)&dk_ioc.dki_data,
- vtoc->efi_lbasize, dk_ioc.dki_length))
+ vtoc->efi_lbasize, dk_ioc.dki_length))
return (VT_ERROR);
memset(dk_ioc.dki_data, 0, dk_ioc.dki_length);
(void) write_pmbr(fd, vtoc);
free(dk_ioc.dki_data);
-#if defined(__linux__)
- rval = efi_rescan(fd);
- if (rval)
- return (VT_ERROR);
-#endif
-
return (0);
}