X-Git-Url: https://git.camperquake.de/gitweb.cgi?a=blobdiff_plain;f=lib%2Flibefi%2Frdwr_efi.c;h=f4cf41712a69a456da23eb2b00659a7eeb6695dd;hb=5853fe790d1df58c5dd85ea52c5e165b6d43013c;hp=da71e3486c2270886a3621403cd9ddb17b4ba29b;hpb=d603ed6c278f9c25b17ba8e75e9bce6e5d715ac0;p=zfs.git diff --git a/lib/libefi/rdwr_efi.c b/lib/libefi/rdwr_efi.c index da71e34..f4cf417 100644 --- a/lib/libefi/rdwr_efi.c +++ b/lib/libefi/rdwr_efi.c @@ -87,7 +87,7 @@ struct dk_map2 default_vtoc_map[NDKMAP] = { #if defined(_SUNOS_VTOC_16) -#if defined(i386) || defined(__amd64) +#if defined(i386) || defined(__amd64) || defined(__arm) || defined(__powerpc) { V_BOOT, V_UNMNT }, /* i - 8 */ { V_ALTSCTR, 0 }, /* j - 9 */ @@ -196,6 +196,12 @@ efi_get_info(int fd, struct dk_cinfo *dki_info) rval = sscanf(dev_path, "/dev/%[a-zA-Z0-9]p%hu", dki_info->dki_dname, &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); } else if ((strncmp(dev_path, "/dev/dm-", 8) == 0)) { strcpy(dki_info->dki_cname, "pseudo"); dki_info->dki_ctype = DKC_VBD; @@ -269,19 +275,12 @@ efi_alloc_and_init(int fd, uint32_t nparts, struct dk_gpt **vtoc) struct uuid uuid; struct dk_cinfo dki_info; - if (read_disk_info(fd, &capacity, &lbsize) != 0) { - if (efi_debug) - (void) fprintf(stderr, - "couldn't read disk information\n"); + if (read_disk_info(fd, &capacity, &lbsize) != 0) return (-1); - } + #if defined(__linux__) - if (efi_get_info(fd, &dki_info) != 0) { - if (efi_debug) - (void) fprintf(stderr, - "couldn't read disk information\n"); + if (efi_get_info(fd, &dki_info) != 0) return (-1); - } if (dki_info.dki_partition != 0) return (-1); @@ -498,10 +497,9 @@ efi_ioctl(int fd, int cmd, dk_efi_t *dk_ioc) return (error); } -#if defined(__linux__) -static int -efi_rescan(int fd) +int efi_rescan(int fd) { +#if defined(__linux__) int retry = 5; int error; @@ -513,10 +511,10 @@ efi_rescan(int fd) return (-1); } } +#endif return (0); } -#endif static int check_label(int fd, dk_efi_t *dk_ioc) @@ -548,16 +546,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(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 (((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 > 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); } @@ -1023,24 +1027,15 @@ efi_use_whole_disk(int fd) struct dk_gpt *efi_label; 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) { 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, @@ -1056,16 +1051,28 @@ efi_use_whole_disk(int fd) return (VT_ENOSPC); } + difference = efi_label->efi_last_lba - efi_label->efi_altern_lba; + /* - * 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. + * This is the reserved 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 < 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; + } + } + + /* + * Find the last physically non-zero partition before that. + * This is the data partition. + */ + 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; + } } /* @@ -1073,10 +1080,9 @@ efi_use_whole_disk(int fd) * 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) { @@ -1159,7 +1165,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); @@ -1228,7 +1234,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); @@ -1281,7 +1288,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) { @@ -1296,12 +1303,6 @@ efi_write(int fd, struct dk_gpt *vtoc) (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); }