diff options
author | Karel Zak | 2013-10-23 12:06:47 +0200 |
---|---|---|
committer | Karel Zak | 2013-10-23 12:06:47 +0200 |
commit | 45ddb828ed7eef92db34841c9d583047b6a6c65e (patch) | |
tree | bcbd3224b5df67fa77ea3c93527e76cc9a9173bf /libfdisk | |
parent | tests: test corruted GPT headers (diff) | |
download | kernel-qcow2-util-linux-45ddb828ed7eef92db34841c9d583047b6a6c65e.tar.gz kernel-qcow2-util-linux-45ddb828ed7eef92db34841c9d583047b6a6c65e.tar.xz kernel-qcow2-util-linux-45ddb828ed7eef92db34841c9d583047b6a6c65e.zip |
libfdisk: (gpt) improve and cleanup recovery code
* use AlternativeLBA rather than hardcoded offset to backup GPT
* create gpt_copy_header()
Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'libfdisk')
-rw-r--r-- | libfdisk/src/gpt.c | 71 |
1 files changed, 56 insertions, 15 deletions
diff --git a/libfdisk/src/gpt.c b/libfdisk/src/gpt.c index 3a256e6dc..68eddeb80 100644 --- a/libfdisk/src/gpt.c +++ b/libfdisk/src/gpt.c @@ -413,6 +413,46 @@ static int gpt_mknew_header_from_bkp(struct fdisk_context *cxt, return 0; } +static struct gpt_header *gpt_copy_header(struct fdisk_context *cxt, + struct gpt_header *src) +{ + struct gpt_header *res; + + if (!cxt || !src) + return NULL; + + res = calloc(1, sizeof(*res)); + if (!res) { + fdisk_warn(cxt, _("failed to allocate GPT header")); + return NULL; + } + + res->my_lba = src->alternative_lba; + res->alternative_lba = src->my_lba; + + res->signature = src->signature; + res->revision = src->revision; + res->size = src->size; + res->npartition_entries = src->npartition_entries; + res->sizeof_partition_entry = src->sizeof_partition_entry; + res->first_usable_lba = src->first_usable_lba; + res->last_usable_lba = src->last_usable_lba; + + memcpy(&res->disk_guid, &src->disk_guid, sizeof(src->disk_guid)); + + + if (res->my_lba == GPT_PRIMARY_PARTITION_TABLE_LBA) + res->partition_entry_lba = cpu_to_le64(2); + else { + uint64_t esz = le32_to_cpu(src->npartition_entries) * sizeof(struct gpt_entry); + uint64_t esects = (esz + cxt->sector_size - 1) / cxt->sector_size; + + res->partition_entry_lba = cpu_to_le64(cxt->total_sectors - 1 - esects); + } + + return res; +} + /* * Builds a clean new GPT header (currently under revision 1.0). * @@ -779,10 +819,13 @@ static struct gpt_header *gpt_read_header(struct fdisk_context *cxt, else free(ents); + DBG(LABEL, dbgprint("found valid GPT Header on LBA %ju", lba)); return header; invalid: free(header); free(ents); + + DBG(LABEL, dbgprint("read GPT Header on LBA %ju failed", lba)); return NULL; } @@ -1106,9 +1149,15 @@ 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); + + if (gpt->pheader) + /* primary OK, try backup from alternative LBA */ + gpt->bheader = gpt_read_header(cxt, + le64_to_cpu(gpt->pheader->alternative_lba), + NULL); + else + /* primary corrupted -- try last LBA */ + gpt->bheader = gpt_read_header(cxt, last_lba(cxt), &gpt->ents); if (!gpt->pheader && !gpt->bheader) goto failed; @@ -1117,26 +1166,18 @@ static int gpt_probe_label(struct fdisk_context *cxt) 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")); + gpt->bheader = gpt_copy_header(cxt, gpt->pheader); + if (!gpt->bheader) 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")); + gpt->pheader = gpt_copy_header(cxt, gpt->bheader); + if (!gpt->pheader) goto failed; - } - gpt_mknew_header_from_bkp(cxt, gpt->pheader, - GPT_PRIMARY_PARTITION_TABLE_LBA, gpt->bheader); gpt_recompute_crc(gpt->pheader, gpt->ents); } |