summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulius Werner <jwerner@chromium.org>2016-04-19 13:20:52 -0700
committerChromeOS bot <3su6n15k.default@developer.gserviceaccount.com>2016-04-27 22:19:03 +0000
commit0bbbe41102bb5257e8170ebc29d05b71e3da328e (patch)
tree90474b452f12efa7ee51424f7434f178fcd04bc1
parent1a505fc6c4003f493028a6813537f375abd24f9e (diff)
downloadvboot-0bbbe41102bb5257e8170ebc29d05b71e3da328e.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> (cherry picked from commit 5de0000ece70bf419130db9bdbaf444ffc98bf30) Reviewed-on: https://chromium-review.googlesource.com/340784
-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 ffaa3090..813f65fa 100644
--- a/cgpt/cgpt_common.c
+++ b/cgpt/cgpt_common.c
@@ -211,15 +211,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,
@@ -230,14 +221,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));
+ }
}
}