summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulius Werner <jwerner@chromium.org>2016-04-19 13:20:52 -0700
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2016-06-21 23:51:19 +0000
commitac638a4f258b332073be2e46dbeb78ab4f35d29e (patch)
treee69cfcb2c67a7ff46c1fb48f38f78a4cdf5f0142
parent723b3c09debfa350f7a17e7927116c3535ac081b (diff)
downloadvboot-ac638a4f258b332073be2e46dbeb78ab4f35d29e.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/354565 Reviewed-by: Bernie Thompson <bhthompson@chromium.org> Commit-Queue: Bernie Thompson <bhthompson@chromium.org> Tested-by: Bernie Thompson <bhthompson@chromium.org>
-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));
+ }
}
}