summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulius Werner <jwerner@chromium.org>2016-04-19 13:20:52 -0700
committerchrome-bot <chrome-bot@chromium.org>2016-04-25 15:15:32 -0700
commit5de0000ece70bf419130db9bdbaf444ffc98bf30 (patch)
tree8deb87e570769bfd20775bbef5859a30ea377ce1
parentff9c2b2e8b49a948ecc6ca640a0400450fd16f4f (diff)
downloadvboot-5de0000ece70bf419130db9bdbaf444ffc98bf30.tar.gz
cgpt: Fully write out primary GPT before starting to write secondary
The point of having two GPTs is to always have a known good one if one of them gets corrupted. One of the most obvious ways that could happen is if the write stopped half-way through (e.g. due to a crash or random power loss). Unfortunately, the way we currently save modified GPTs can leave both copies invalid if we stop writing at just the wrong time. Since a GPT header contains a checksum over the GPT entries, we need to write both the header and entries for one GPT (and make sure they're synced to disk) before we start writing the other. BRANCH=None BUG=chrome-os-partner:52595 TEST=None Change-Id: I2d4b56bcfba9a94395af5896f274ebade9e39081 Signed-off-by: Julius Werner <jwerner@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/340071 Reviewed-by: Nam Nguyen <namnguyen@google.com>
-rw-r--r--cgpt/cgpt_common.c42
1 files changed, 26 insertions, 16 deletions
diff --git a/cgpt/cgpt_common.c b/cgpt/cgpt_common.c
index 5bb44f7a..2c21cdc2 100644
--- a/cgpt/cgpt_common.c
+++ b/cgpt/cgpt_common.c
@@ -213,15 +213,6 @@ static int GptSave(struct drive *drive) {
Error("Cannot write primary header: %s\n", strerror(errno));
}
}
-
- if (drive->gpt.modified & GPT_MODIFIED_HEADER2) {
- if(CGPT_OK != Save(drive, drive->gpt.secondary_header,
- drive->gpt.gpt_drive_sectors - GPT_PMBR_SECTORS,
- drive->gpt.sector_bytes, GPT_HEADER_SECTORS)) {
- errors++;
- Error("Cannot write secondary header: %s\n", strerror(errno));
- }
- }
GptHeader* primary_header = (GptHeader*)drive->gpt.primary_header;
if (drive->gpt.modified & GPT_MODIFIED_ENTRIES1) {
if (CGPT_OK != Save(drive, drive->gpt.primary_entries,
@@ -232,14 +223,33 @@ static int GptSave(struct drive *drive) {
Error("Cannot write primary entries: %s\n", strerror(errno));
}
}
- GptHeader* secondary_header = (GptHeader*)drive->gpt.secondary_header;
- if (drive->gpt.modified & GPT_MODIFIED_ENTRIES2) {
- if (CGPT_OK != Save(drive, drive->gpt.secondary_entries,
- secondary_header->entries_lba,
- drive->gpt.sector_bytes,
- CalculateEntriesSectors(secondary_header))) {
+
+ // Sync primary GPT before touching secondary so one is always valid.
+ if (drive->gpt.modified & (GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1))
+ if (fsync(drive->fd) < 0 && errno == EIO) {
errors++;
- Error("Cannot write secondary entries: %s\n", strerror(errno));
+ Error("I/O error when trying to write primary GPT\n");
+ }
+
+ // Only start writing secondary GPT if primary was written correctly.
+ if (!errors) {
+ if (drive->gpt.modified & GPT_MODIFIED_HEADER2) {
+ if(CGPT_OK != Save(drive, drive->gpt.secondary_header,
+ drive->gpt.gpt_drive_sectors - GPT_PMBR_SECTORS,
+ drive->gpt.sector_bytes, GPT_HEADER_SECTORS)) {
+ errors++;
+ Error("Cannot write secondary header: %s\n", strerror(errno));
+ }
+ }
+ GptHeader* secondary_header = (GptHeader*)drive->gpt.secondary_header;
+ if (drive->gpt.modified & GPT_MODIFIED_ENTRIES2) {
+ if (CGPT_OK != Save(drive, drive->gpt.secondary_entries,
+ secondary_header->entries_lba,
+ drive->gpt.sector_bytes,
+ CalculateEntriesSectors(secondary_header))) {
+ errors++;
+ Error("Cannot write secondary entries: %s\n", strerror(errno));
+ }
}
}