[parted-devel] [PATCH] Bug fixes needed to parse EFI GPT labels written by OpenSolaris ZFS

Matthew S. Harris mharris312 at gmail.com
Thu Apr 26 06:55:31 UTC 2007


I finally got Parted to correctly read EFI GPT labels written by
OpenSolaris ZFS!  Patch attached.  I sent off the email to
assign at gnu.org tonight.  Naturally I'd like to see this go into a
stable release as soon as reasonable so that other ZFS users can
comfortably use Parted, but I understand this may take a while if
copyright assignment doesn't happen before the next release.

My only remaining issue is that OpenSolaris sees my disks as 5040
blocks smaller than Linux does, but that's not Parted's fault.


Matthew
-------------- next part --------------
From ceddb9b171b2e1c7cb45d1971aea2304827bd5f9 Mon Sep 17 00:00:00 2001
From: Matthew Harris <mharris at coruscant.(none)>
Date: Wed, 25 Apr 2007 23:43:23 -0700
Subject: [PATCH] Bug fixes needed to parse EFI GPT labels written by OpenSolaris ZFS

- Use the HeaderSize field value when determining how many bytes to
compute the CRC over.

- Don't abort if the HeaderSize field value is bigger than our struct,
since more fields may be defined in the future.

- When the backup GPT table isn't at the end of the disk, allow (and
default to) ignoring the problem.  If another OS sees the disk as
smaller, we don't want to break them by moving things around.

- If the primary GPT table appears corrupt, the default behavior (when
the user presses Ctrl-C, for example) should be to cancel rather than
to overwrite the primary GPT table.

- Use the SizeOfPartitionEntry field value when reading the partition
entries rather than assuming that the entries are the same size as our
struct.

- When reading the partition entries, round up, not down, the number
of blocks to read.
---
 libparted/labels/gpt.c |   56 +++++++++++++++++++++++++----------------------
 1 files changed, 30 insertions(+), 26 deletions(-)

diff --git a/libparted/labels/gpt.c b/libparted/labels/gpt.c
index 86c31c7..dc6c210 100644
--- a/libparted/labels/gpt.c
+++ b/libparted/labels/gpt.c
@@ -390,7 +390,7 @@ pth_crc32(const PedDevice* dev, const GuidPartitionTableHeader_t* pth)
         PED_ASSERT (dev != NULL, return 0);
         PED_ASSERT (pth != NULL, return 0);
        
-        crc32 = efi_crc32 (pth_raw, pth_get_size_static (dev));
+        crc32 = efi_crc32 (pth_raw, PED_LE32_TO_CPU (pth->HeaderSize));
 
         ped_free (pth_raw);
       
@@ -590,8 +590,13 @@ _header_is_valid (const PedDevice* dev, GuidPartitionTableHeader_t* gpt)
 
 	if (PED_LE64_TO_CPU (gpt->Signature) != GPT_HEADER_SIGNATURE)
 		return 0;
-	if (PED_LE32_TO_CPU (gpt->HeaderSize)
-			> pth_get_size_static (dev))
+	/*
+	 * "While the GUID Partition Table Header's size may increase
+	 * in the future it cannot span more than one block on the
+	 * device."  EFI Specification, version 1.10, 11.2.2.1
+	 */
+	if (PED_LE32_TO_CPU (gpt->HeaderSize) < pth_get_size_static (dev)
+	    || PED_LE32_TO_CPU (gpt->HeaderSize) > dev->sector_size)
 		return 0;
 
 	origcrc = gpt->HeaderCRC32;
@@ -639,9 +644,7 @@ _parse_header (PedDisk* disk, GuidPartitionTableHeader_t* gpt,
 	PED_ASSERT (_header_is_valid (disk->dev, gpt), return 0);
 
 #ifndef DISCOVER_ONLY
-	if (PED_LE32_TO_CPU (gpt->Revision) > GPT_HEADER_REVISION_V1_02
-	    || PED_LE32_TO_CPU (gpt->HeaderSize) != pth_get_size_static (
-                                                        disk->dev)) {
+	if (PED_LE32_TO_CPU (gpt->Revision) > GPT_HEADER_REVISION_V1_02) {
 		if (ped_exception_throw (
 			PED_EXCEPTION_WARNING,
 			PED_EXCEPTION_IGNORE_CANCEL,
@@ -797,8 +800,8 @@ gpt_read (PedDisk * disk)
 {
 	GPTDiskData *gpt_disk_data = disk->disk_specific;
 	GuidPartitionTableHeader_t* gpt;
-	GuidPartitionEntry_t* ptes;
-	int ptes_size;
+	void* ptes;
+	int ptes_sectors;
 	int i;
 #ifndef DISCOVER_ONLY
 	int write_back = 0;
@@ -822,20 +825,19 @@ gpt_read (PedDisk * disk)
 
 #ifndef DISCOVER_ONLY
 			if (ped_exception_throw (
-				PED_EXCEPTION_ERROR,
-				PED_EXCEPTION_FIX | PED_EXCEPTION_CANCEL,
+				PED_EXCEPTION_WARNING,
+				PED_EXCEPTION_FIX | PED_EXCEPTION_IGNORE,
 		_("The backup GPT table is not at the end of the disk, as it "
 		  "should be.  This might mean that another operating system "
 		  "believes the disk is smaller.  Fix, by moving the backup "
 		  "to the end (and removing the old backup)?"))
-					== PED_EXCEPTION_CANCEL)
-				goto error_free_gpt;
-
-			write_back = 1;
-			memset (zeros, 0, disk->dev->sector_size);
-			ped_device_write (disk->dev, zeros,
-					  PED_LE64_TO_CPU (gpt->AlternateLBA),
-					  1);
+					== PED_EXCEPTION_FIX) {
+				write_back = 1;
+				memset (zeros, 0, disk->dev->sector_size);
+				ped_device_write (disk->dev, zeros,
+						  PED_LE64_TO_CPU (gpt->AlternateLBA),
+						  1);
+			}
 #endif /* !DISCOVER_ONLY */
 		}
 	} else { /* primary GPT *not* ok */
@@ -858,10 +860,10 @@ gpt_read (PedDisk * disk)
 		if (alternate_ok) {
 			if (ped_exception_throw (
 				PED_EXCEPTION_ERROR,
-				PED_EXCEPTION_OK_CANCEL,
+				PED_EXCEPTION_FIX | PED_EXCEPTION_CANCEL,
 				_("The primary GPT table is corrupt, but the "
 				  "backup appears OK, so that will be used."))
-				    == PED_EXCEPTION_CANCEL)
+				    != PED_EXCEPTION_FIX)
 				goto error_free_gpt;
 		} else {
 			ped_exception_throw (
@@ -878,22 +880,24 @@ gpt_read (PedDisk * disk)
 	if (!_parse_header (disk, gpt, &write_back))
 		goto error_free_gpt;
 
-
-	ptes_size = sizeof (GuidPartitionEntry_t) * gpt_disk_data->entry_count;
-	ptes = (GuidPartitionEntry_t*) ped_malloc (ptes_size);
+	ptes_sectors = ped_div_round_up(gpt->SizeOfPartitionEntry *
+		gpt_disk_data->entry_count, disk->dev->sector_size);
+	ptes = ped_malloc (ptes_sectors * disk->dev->sector_size);
 	if (!ped_device_read (disk->dev, ptes,
 			      PED_LE64_TO_CPU(gpt->PartitionEntryLBA),
-			      ptes_size / disk->dev->sector_size))
+			      ptes_sectors))
 		goto error_free_ptes;
 
 	for (i = 0; i < gpt_disk_data->entry_count; i++) {
+		GuidPartitionEntry_t* pte = (GuidPartitionEntry_t*) (ptes +
+			i * gpt->SizeOfPartitionEntry);
 		PedPartition* part;
 		PedConstraint* constraint_exact;
 
-		if (!guid_cmp (ptes[i].PartitionTypeGuid, UNUSED_ENTRY_GUID))
+		if (!guid_cmp (pte->PartitionTypeGuid, UNUSED_ENTRY_GUID))
 			continue;
 
-		part = _parse_part_entry (disk, &ptes[i]);
+		part = _parse_part_entry (disk, pte);
 		if (!part)
 			goto error_delete_all;
 
-- 
1.4.4.2


More information about the parted-devel mailing list