Skip to content

Commit

Permalink
signpost: Avoid updating into nothing
Browse files Browse the repository at this point in the history
Add two new commands to signpost:
- mark-inactive-valid, used to mark the inactive partition as having a
potentially valid image but not for boot.
- cancel-upgrade, which reverts the changes of upgrade-to-inactive.

In addition upgrade-to-inactive makes two initial checks; whether the
inactive partition has been marked valid with mark-inactive-valid, and
whether the inactive partition has already been marked for boot. The
first is to avoid accidentally booting into a blank partition, while the
second is a warning that makes it more clear that invoking
upgrade-to-inactive twice does not revert the change.

Signed-off-by: Samuel Mendoza-Jonas <[email protected]>
  • Loading branch information
sam-aws committed Nov 13, 2019
1 parent 32bd262 commit c137992
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 7 deletions.
6 changes: 6 additions & 0 deletions workspaces/updater/signpost/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ pub enum Error {
#[snafu(display("Failed to write GPT onto device {}: {}", device.display(), source))]
GPTWrite { device: PathBuf, source: GPTError },

#[snafu(display("Inactive partition {} is already marked for upgrade", inactive.display()))]
InactiveAlreadyMarked { inactive: PathBuf },

#[snafu(display("Inactive partition {} has not been marked valid for upgrade", inactive.display()))]
InactiveNotValid { inactive: PathBuf },

#[snafu(display(
"Inactive partition is not valid to roll back to (priority={} tries_left={} successful={})",
priority,
Expand Down
16 changes: 14 additions & 2 deletions workspaces/updater/signpost/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ use signpost::State;
enum Command {
Status,
MarkSuccessfulBoot,
MarkInactiveValid,
ClearInactive,
UpgradeToInactive,
CancelUpgrade,
RollbackToInactive,
RewriteTable,
}
Expand All @@ -24,7 +26,9 @@ SUBCOMMANDS:
status Show partition sets and priority status
mark-successful-boot Mark the active partitions as successfully booted
clear-inactive Clears inactive priority information to prepare writing images to disk
upgrade-to-inactive Sets the inactive partitions as new upgrade partitions
mark-inactive-valid Marks the inactive partition as having a valid image
upgrade-to-inactive Sets the inactive partitions as new upgrade partitions if marked valid
cancel-upgrade Reverse upgrade-to-inactive
rollback-to-inactive Deprioritizes the inactive partitions
rewrite-table Rewrite the partition table with no changes to disk (used for testing this code)");
std::process::exit(1)
Expand All @@ -45,8 +49,16 @@ fn main() {
state.mark_successful_boot();
state.write()?;
}
Command::MarkInactiveValid => {
state.mark_inactive_valid();
state.write()?;
}
Command::UpgradeToInactive => {
state.upgrade_to_inactive();
state.upgrade_to_inactive()?;
state.write()?;
}
Command::CancelUpgrade => {
state.cancel_upgrade();
state.write()?;
}
Command::RollbackToInactive => {
Expand Down
42 changes: 39 additions & 3 deletions workspaces/updater/signpost/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::set::{PartitionSet, SetSelect};
use block_party::BlockDevice;
use gptman::GPT;
use hex_literal::hex;
use snafu::{OptionExt, ResultExt};
use snafu::{ensure, OptionExt, ResultExt};
use std::fmt;
use std::fs::{File, OpenOptions};
use std::path::{Path, PathBuf};
Expand Down Expand Up @@ -200,21 +200,57 @@ impl State {
self.set_gptprio(self.inactive(), inactive_flags);
}

/// Sets 'tries left' to 1 on the inactive partition to represent a
/// potentially valid image, but does not change the priority.
/// **does not write to the disk**.
pub fn mark_inactive_valid(&mut self) {
let mut inactive_flags = self.gptprio(self.inactive());
inactive_flags.set_tries_left(1);
self.set_gptprio(self.inactive(), inactive_flags);
}

/// Sets the inactive partition as a new upgrade partition, but **does not write to the disk**.
///
/// * Sets the inactive partition's priority to 2 and the active partition's priority to 1.
/// * Sets the inactive partition's tries left to 1.
/// * Sets the inactive partition as not successfully booted.
pub fn upgrade_to_inactive(&mut self) {
/// * Returns an error if the partition has not been marked as potentially
/// valid or if it has already been marked for upgrade.
pub fn upgrade_to_inactive(&mut self) -> Result<(), Error> {
let mut inactive_flags = self.gptprio(self.inactive());
ensure!(
inactive_flags.priority() == 0 && !inactive_flags.successful(),
error::InactiveAlreadyMarked {
inactive: &self.os_disk
}
);
ensure!(
inactive_flags.tries_left() > 0,
error::InactiveNotValid {
inactive: &self.os_disk
}
);

inactive_flags.set_priority(2);
inactive_flags.set_tries_left(1);
inactive_flags.set_successful(false);
self.set_gptprio(self.inactive(), inactive_flags);

let mut active_flags = self.gptprio(self.active());
active_flags.set_priority(1);
self.set_gptprio(self.active(), active_flags);
Ok(())
}

/// Reverts upgrade_to_inactive(), but **does not write to the disk**.
///
/// * Clears all bits of the inactive partition.
/// * Restores the active partition's priority to 2
pub fn cancel_upgrade(&mut self) {
self.clear_inactive();

let mut active_flags = self.gptprio(self.active());
active_flags.set_priority(2);
self.set_gptprio(self.active(), active_flags);
}

/// Prioritizes the inactive partition, but **does not write to the disk**.
Expand Down
3 changes: 3 additions & 0 deletions workspaces/updater/updog/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ pub(crate) enum Error {
#[snafu(display("Duplicate version key: {}", key))]
DuplicateVersionKey { backtrace: Backtrace, key: String },

#[snafu(display("Could not mark inactive partition for boot: {}", source))]
InactivePartitionUpgrade { source: signpost::Error },

#[snafu(display("Failed to attach image to loop device"))]
LoopAttachFailed {
backtrace: Backtrace,
Expand Down
8 changes: 6 additions & 2 deletions workspaces/updater/updog/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -378,12 +378,17 @@ fn update_image(update: &Update, repository: &Repository<'_>) -> Result<()> {
write_target_to_disk(repository, &update.images.root, &inactive.root)?;
write_target_to_disk(repository, &update.images.boot, &inactive.boot)?;
write_target_to_disk(repository, &update.images.hash, &inactive.hash)?;

gpt_state.mark_inactive_valid();
gpt_state.write().context(error::PartitionTableWrite)?;
Ok(())
}

fn update_flags() -> Result<()> {
let mut gpt_state = State::load().context(error::PartitionTableRead)?;
gpt_state.upgrade_to_inactive();
gpt_state
.upgrade_to_inactive()
.context(error::InactivePartitionUpgrade)?;
gpt_state.write().context(error::PartitionTableWrite)?;
Ok(())
}
Expand Down Expand Up @@ -592,7 +597,6 @@ fn main_inner() -> Result<()> {
}
}
Command::UpdateApply => {
// TODO Guard against being called repeatedly
update_flags()?;
if arguments.reboot {
process::Command::new("shutdown")
Expand Down

0 comments on commit c137992

Please sign in to comment.