Skip to content

Commit 5c783b5

Browse files
Philippe Reynestrini
Philippe Reynes
authored andcommitted
disk: part_efi: add support to repair gpt table
If a gpt table is corrupted (after a power cut for example), then the gpt table should repaired. The function gpt_repair_headers check if at least one gpt table is valid, and then only write the corrupted gpt table. Signed-off-by: Philippe Reynes <[email protected]>
1 parent 145921b commit 5c783b5

File tree

2 files changed

+96
-0
lines changed

2 files changed

+96
-0
lines changed

disk/part_efi.c

+86
Original file line numberDiff line numberDiff line change
@@ -705,6 +705,92 @@ int gpt_verify_headers(struct blk_desc *dev_desc, gpt_header *gpt_head,
705705
return 0;
706706
}
707707

708+
static void restore_primary_gpt_header(gpt_header *gpt_h, struct blk_desc *dev_desc)
709+
{
710+
u32 calc_crc32;
711+
u64 val;
712+
713+
/* recalculate the values for the Primary GPT Header */
714+
val = le64_to_cpu(gpt_h->my_lba);
715+
gpt_h->my_lba = gpt_h->alternate_lba;
716+
gpt_h->alternate_lba = cpu_to_le64(val);
717+
gpt_h->partition_entry_lba = cpu_to_le64(partition_entries_offset(dev_desc));
718+
719+
gpt_h->header_crc32 = 0;
720+
721+
calc_crc32 = efi_crc32((const unsigned char *)gpt_h,
722+
le32_to_cpu(gpt_h->header_size));
723+
gpt_h->header_crc32 = cpu_to_le32(calc_crc32);
724+
}
725+
726+
static int write_one_gpt_table(struct blk_desc *dev_desc,
727+
gpt_header *gpt_h, gpt_entry *gpt_e)
728+
{
729+
const int pte_blk_cnt = BLOCK_CNT((gpt_h->num_partition_entries
730+
* sizeof(gpt_entry)), dev_desc);
731+
lbaint_t start;
732+
int ret = 0;
733+
734+
start = le64_to_cpu(gpt_h->my_lba);
735+
if (blk_dwrite(dev_desc, start, 1, gpt_h) != 1) {
736+
ret = -1;
737+
goto out;
738+
}
739+
740+
start = le64_to_cpu(gpt_h->partition_entry_lba);
741+
if (blk_dwrite(dev_desc, start, pte_blk_cnt, gpt_e) != pte_blk_cnt) {
742+
ret = -1;
743+
goto out;
744+
}
745+
746+
out:
747+
return ret;
748+
}
749+
750+
int gpt_repair_headers(struct blk_desc *dev_desc)
751+
{
752+
ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_h1, 1, dev_desc->blksz);
753+
ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_h2, 1, dev_desc->blksz);
754+
gpt_entry *gpt_e1 = NULL, *gpt_e2 = NULL;
755+
int is_gpt1_valid, is_gpt2_valid;
756+
int ret = -1;
757+
758+
is_gpt1_valid = is_gpt_valid(dev_desc, GPT_PRIMARY_PARTITION_TABLE_LBA,
759+
gpt_h1, &gpt_e1);
760+
is_gpt2_valid = is_gpt_valid(dev_desc, dev_desc->lba - 1,
761+
gpt_h2, &gpt_e2);
762+
763+
if (is_gpt1_valid && is_gpt2_valid) {
764+
ret = 0;
765+
goto out;
766+
}
767+
768+
if (is_gpt1_valid && !is_gpt2_valid) {
769+
prepare_backup_gpt_header(gpt_h1);
770+
ret = write_one_gpt_table(dev_desc, gpt_h1, gpt_e1);
771+
goto out;
772+
}
773+
774+
if (!is_gpt1_valid && is_gpt2_valid) {
775+
restore_primary_gpt_header(gpt_h2, dev_desc);
776+
ret = write_one_gpt_table(dev_desc, gpt_h2, gpt_e2);
777+
goto out;
778+
}
779+
780+
if (!is_gpt1_valid && !is_gpt2_valid) {
781+
ret = -1;
782+
goto out;
783+
}
784+
785+
out:
786+
if (is_gpt1_valid)
787+
free(gpt_e1);
788+
if (is_gpt2_valid)
789+
free(gpt_e2);
790+
791+
return ret;
792+
}
793+
708794
int gpt_verify_partitions(struct blk_desc *dev_desc,
709795
struct disk_partition *partitions, int parts,
710796
gpt_header *gpt_head, gpt_entry **gpt_pte)

include/part.h

+10
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,16 @@ int write_mbr_and_gpt_partitions(struct blk_desc *dev_desc, void *buf);
466466
int gpt_verify_headers(struct blk_desc *dev_desc, gpt_header *gpt_head,
467467
gpt_entry **gpt_pte);
468468

469+
/**
470+
* gpt_repair_headers() - Function to repair the GPT's header
471+
* and partition table entries (PTE)
472+
*
473+
* @param dev_desc - block device descriptor
474+
*
475+
* Return: - '0' on success, otherwise error
476+
*/
477+
int gpt_repair_headers(struct blk_desc *dev_desc);
478+
469479
/**
470480
* gpt_verify_partitions() - Function to check if partitions' name, start and
471481
* size correspond to '$partitions' env variable

0 commit comments

Comments
 (0)