]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libfdisk: (gpt) recover from corrupted primary/backup PT
authorKarel Zak <kzak@redhat.com>
Wed, 23 Oct 2013 08:27:39 +0000 (10:27 +0200)
committerKarel Zak <kzak@redhat.com>
Wed, 23 Oct 2013 08:46:10 +0000 (10:46 +0200)
We already have all code to support this feature, unfortunately
it was not used in gpt_probe_label()...

References: https://bugzilla.redhat.com/show_bug.cgi?id=1022217
Signed-off-by: Karel Zak <kzak@redhat.com>
libfdisk/src/gpt.c

index 6e7b74d9fe12f0b41461f6fc1eec131ba3a54fdf..3a256e6dc033454ce2e53687e135ecf9e1b5f42a 100644 (file)
@@ -1094,6 +1094,8 @@ static int gpt_probe_label(struct fdisk_context *cxt)
 
        gpt = self_label(cxt);
 
+       /* TODO: it would be nice to support scenario when GPT headers are OK,
+        *       but PMBR is corrupt */
        mbr_type = valid_pmbr(cxt);
        if (!mbr_type)
                goto failed;
@@ -1104,21 +1106,39 @@ static int gpt_probe_label(struct fdisk_context *cxt)
        /* primary header */
        gpt->pheader = gpt_read_header(cxt, GPT_PRIMARY_PARTITION_TABLE_LBA,
                                       &gpt->ents);
+       /* backup header */
+       gpt->bheader = gpt_read_header(cxt, last_lba(cxt),
+                                       gpt->pheader ? NULL : &gpt->ents);
 
-       /*
-        * TODO: If the primary GPT is corrupt, we must check the last LBA of the
-        * device to see if it has a valid GPT Header and point to a valid GPT
-        * Partition Entry Array.
-        * If it points to a valid GPT Partition Entry Array, then software should
-        * restore the primary GPT if allowed by platform policy settings.
-        *
-        * For now we just abort GPT probing!
-        */
-       if (!gpt->pheader || !gpt->ents)
+       if (!gpt->pheader && !gpt->bheader)
                goto failed;
 
-       /* OK, probing passed, now initialize backup header and fdisk variables. */
-       gpt->bheader = gpt_read_header(cxt, last_lba(cxt), NULL);
+       /* primary OK, backup corrupted -- recovery */
+       if (gpt->pheader && !gpt->bheader) {
+               fdisk_warnx(cxt, _("The backup GPT table is corrupt, but the "
+                                 "primary appears OK, so that will be used."));
+               gpt->bheader = calloc(1, sizeof(*gpt->bheader));
+               if (!gpt->bheader) {
+                       fdisk_warn(cxt, _("failed to allocate GPT header"));
+                       goto failed;
+               }
+               gpt_mknew_header_from_bkp(cxt, gpt->bheader,
+                               last_lba(cxt), gpt->pheader);
+               gpt_recompute_crc(gpt->bheader, gpt->ents);
+
+       /* primary corrupted, backup OK -- recovery */
+       } else if (!gpt->pheader && gpt->bheader) {
+               fdisk_warnx(cxt, _("The primary GPT table is corrupt, but the "
+                                 "backup appears OK, so that will be used."));
+               gpt->pheader = calloc(1, sizeof(*gpt->bheader));
+               if (!gpt->pheader) {
+                       fdisk_warn(cxt, _("failed to allocate GPT header"));
+                       goto failed;
+               }
+               gpt_mknew_header_from_bkp(cxt, gpt->pheader,
+                               GPT_PRIMARY_PARTITION_TABLE_LBA, gpt->bheader);
+               gpt_recompute_crc(gpt->pheader, gpt->ents);
+       }
 
        cxt->label->nparts_max = le32_to_cpu(gpt->pheader->npartition_entries);
        cxt->label->nparts_cur = partitions_in_use(gpt->pheader, gpt->ents);