summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorZachary Bedell <[email protected]>2011-09-18 21:35:42 -0400
committerBrian Behlendorf <[email protected]>2011-09-26 09:44:43 -0700
commit7a0232735d7527b08e02196762727994aa6065f9 (patch)
tree068d6005443c0cd3ca82735d34586c87b0523d86 /lib
parentc39b2786ac98ab87d6dda00aa83b399ed175055a (diff)
Make libefi-created GPT compatible with gptfdisk
GPT's created by libefi set the HeaderSize attribute in the GPT header to 512 -- size of the GPT header INCLUDING the 420 padding bytes at the end. Most other tools set the size to 92 -- size of the actual header itself excluding the padding. Most tools check the recorded HeaderSize when verifying CRC, but gptfdisk hardcodes 92 and thus reports CRC verification problems for full-disk vdevs created IE with `zpool create pool sdc`. This commit changes libefi's behavior for GPT creation and also fixes several edge cases where libefi's behavior was similar (though in an incompatible manner) to gptfdisk. Libefi assumed HeaderSize was always 512 even if the GPT recorded a different value. Sanity checks of the GPT headersize read from disk were added before applying checksum calculation -- this will prevent segfault in cases of bogus on-disk values. Zpools created with the resuling libefi are verified as correct both by parted and gptfdisk. Also pool have been tested to import correctly on ZFS on Linux as well as Solaris Express 11 livecd. Signed-off-by: Zachary Bedell <[email protected]> Signed-off-by: Brian Behlendorf <[email protected]> Closes #344
Diffstat (limited to 'lib')
-rw-r--r--lib/libefi/rdwr_efi.c25
1 files changed, 16 insertions, 9 deletions
diff --git a/lib/libefi/rdwr_efi.c b/lib/libefi/rdwr_efi.c
index 2af0c4e2e..43a5310a3 100644
--- a/lib/libefi/rdwr_efi.c
+++ b/lib/libefi/rdwr_efi.c
@@ -541,16 +541,22 @@ check_label(int fd, dk_efi_t *dk_ioc)
*/
crc = efi->efi_gpt_HeaderCRC32;
efi->efi_gpt_HeaderCRC32 = 0;
+ len_t headerSize = (len_t)LE_32(efi->efi_gpt_HeaderSize);
- if (((len_t)LE_32(efi->efi_gpt_HeaderSize) > dk_ioc->dki_length) ||
- crc != LE_32(efi_crc32((unsigned char *)efi,
- LE_32(efi->efi_gpt_HeaderSize)))) {
+ 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);
+ }
+
+ if ((headerSize > dk_ioc->dki_length) ||
+ crc != LE_32(efi_crc32((unsigned char *)efi, headerSize))) {
if (efi_debug)
(void) fprintf(stderr,
"Bad EFI CRC: 0x%x != 0x%x\n",
- crc,
- LE_32(efi_crc32((unsigned char *)efi,
- sizeof (struct efi_gpt))));
+ crc, LE_32(efi_crc32((unsigned char *)efi,
+ headerSize)));
return (VT_EINVAL);
}
@@ -1152,7 +1158,7 @@ efi_write(int fd, struct dk_gpt *vtoc)
/* stuff user's input into EFI struct */
efi->efi_gpt_Signature = LE_64(EFI_SIGNATURE);
efi->efi_gpt_Revision = LE_32(vtoc->efi_version); /* 0x02000100 */
- efi->efi_gpt_HeaderSize = LE_32(sizeof (struct efi_gpt));
+ efi->efi_gpt_HeaderSize = LE_32(sizeof (struct efi_gpt) - LEN_EFI_PAD);
efi->efi_gpt_Reserved1 = 0;
efi->efi_gpt_MyLBA = LE_64(1ULL);
efi->efi_gpt_AlternateLBA = LE_64(lba_backup_gpt_hdr);
@@ -1221,7 +1227,8 @@ efi_write(int fd, struct dk_gpt *vtoc)
LE_32(efi_crc32((unsigned char *)efi_parts,
vtoc->efi_nparts * (int)sizeof (struct efi_gpe)));
efi->efi_gpt_HeaderCRC32 =
- LE_32(efi_crc32((unsigned char *)efi, sizeof (struct efi_gpt)));
+ LE_32(efi_crc32((unsigned char *)efi,
+ LE_32(efi->efi_gpt_HeaderSize)));
if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) {
free(dk_ioc.dki_data);
@@ -1274,7 +1281,7 @@ efi_write(int fd, struct dk_gpt *vtoc)
efi->efi_gpt_HeaderCRC32 = 0;
efi->efi_gpt_HeaderCRC32 =
LE_32(efi_crc32((unsigned char *)dk_ioc.dki_data,
- sizeof (struct efi_gpt)));
+ LE_32(efi->efi_gpt_HeaderSize)));
if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) {
if (efi_debug) {