summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulius Werner <jwerner@chromium.org>2016-04-19 13:20:52 -0700
committerPhilip Chen <philipchen@chromium.org>2016-11-15 18:32:40 +0000
commit5d3e4d772a7ab61daa8e6b83a4cb7ec8df73a512 (patch)
tree20dc6a74705bf7bb770debbd4bddf04187275574
parent5d652cdffa70dc772e80548a760e1f0d67de273f (diff)
downloadvboot-5d3e4d772a7ab61daa8e6b83a4cb7ec8df73a512.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/411475 Reviewed-by: Philip Chen <philipchen@chromium.org> Commit-Queue: Philip Chen <philipchen@chromium.org> Tested-by: Philip Chen <philipchen@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 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));
+ }
}
}