OSDN Git Service

partitions/efi: account for pmbr size in lba
[uclinux-h8/linux.git] / block / partitions / efi.c
index e3cb4f1..b028af6 100644 (file)
@@ -166,6 +166,7 @@ invalid:
 /**
  * is_pmbr_valid(): test Protective MBR for validity
  * @mbr: pointer to a legacy mbr structure
+ * @total_sectors: amount of sectors in the device
  *
  * Description: Checks for a valid protective or hybrid
  * master boot record (MBR). The validity of a pMBR depends
@@ -180,9 +181,9 @@ invalid:
  * Returns 0 upon invalid MBR, or GPT_MBR_PROTECTIVE or
  * GPT_MBR_HYBRID depending on the device layout.
  */
-static int is_pmbr_valid(legacy_mbr *mbr)
+static int is_pmbr_valid(legacy_mbr *mbr, sector_t total_sectors)
 {
-       int i, ret = 0; /* invalid by default */
+       int i, part = 0, ret = 0; /* invalid by default */
 
        if (!mbr || le16_to_cpu(mbr->signature) != MSDOS_MBR_SIGNATURE)
                goto done;
@@ -190,6 +191,7 @@ static int is_pmbr_valid(legacy_mbr *mbr)
        for (i = 0; i < 4; i++) {
                ret = pmbr_part_valid(&mbr->partition_record[i]);
                if (ret == GPT_MBR_PROTECTIVE) {
+                       part = i;
                        /*
                         * Ok, we at least know that there's a protective MBR,
                         * now check if there are other partition types for
@@ -207,6 +209,18 @@ check_hybrid:
                        EFI_PMBR_OSTYPE_EFI_GPT) &&
                    (mbr->partition_record[i].os_type != 0x00))
                        ret = GPT_MBR_HYBRID;
+
+       /*
+        * Protective MBRs take up the lesser of the whole disk
+        * or 2 TiB (32bit LBA), ignoring the rest of the disk.
+        *
+        * Hybrid MBRs do not necessarily comply with this.
+        */
+       if (ret == GPT_MBR_PROTECTIVE) {
+               if (le32_to_cpu(mbr->partition_record[part].size_in_lba) !=
+                   min((uint32_t) total_sectors - 1, 0xFFFFFFFF))
+                       ret = 0;
+       }
 done:
        return ret;
 }
@@ -568,6 +582,7 @@ static int find_valid_gpt(struct parsed_partitions *state, gpt_header **gpt,
        gpt_header *pgpt = NULL, *agpt = NULL;
        gpt_entry *pptes = NULL, *aptes = NULL;
        legacy_mbr *legacymbr;
+       sector_t total_sectors = i_size_read(state->bdev->bd_inode) >> 9;
        u64 lastlba;
 
        if (!ptes)
@@ -581,7 +596,7 @@ static int find_valid_gpt(struct parsed_partitions *state, gpt_header **gpt,
                        goto fail;
 
                read_lba(state, 0, (u8 *)legacymbr, sizeof(*legacymbr));
-               good_pmbr = is_pmbr_valid(legacymbr);
+               good_pmbr = is_pmbr_valid(legacymbr, total_sectors);
                kfree(legacymbr);
 
                if (!good_pmbr)