diff --git a/src/engine/strat_engine/backstore/metadata/bda.rs b/src/engine/strat_engine/backstore/metadata/bda.rs index e8ca24e6c34..53a6181ea54 100644 --- a/src/engine/strat_engine/backstore/metadata/bda.rs +++ b/src/engine/strat_engine/backstore/metadata/bda.rs @@ -152,7 +152,11 @@ impl BDA { F: Read + Seek + SyncAll, { let header = match StaticHeader::setup(f)? { - Some(header) => header, + Some(SetupResult::Ok(header)) => header, + Some(SetupResult::OkWithError(header, err)) => { + warn!("StaticHeader::setup didn't completely succeed: {:?}", err); + header + } None => return Ok(None), }; @@ -241,6 +245,12 @@ impl BDA { } } +#[derive(Debug)] +pub enum SetupResult { + Ok(StaticHeader), + OkWithError(StaticHeader, StratisError), +} + #[derive(Eq, PartialEq)] pub struct StaticHeader { blkdev_size: Sectors, @@ -273,17 +283,26 @@ impl StaticHeader { } /// Try to find a valid StaticHeader on a device. + /// /// Return the latest copy that validates as a Stratis BDA, however verify both /// copies and if one validates but one does not, re-write the one that is incorrect. If both /// copies are valid, but one is newer than the other, rewrite the older one to match. + /// /// Return None if it's not a Stratis device. + /// /// Return an error if the metadata seems to indicate that the device is /// a Stratis device, but no well-formed signature block could be read. + /// /// Return an error if neither sigblock location can be read. + /// /// Return an error if the sigblocks differ in some unaccountable way. - /// Returns an error if a write intended to repair an ill-formed, + /// + /// Return an error if a write intended to repair an ill-formed, /// unreadable, or stale signature block failed. - fn setup(f: &mut F) -> StratisResult> + /// + /// Return the latest copy alongside an error (`SetupResult::OkWithError`) if writing the copy + /// failed. + fn setup(f: &mut F) -> StratisResult> where F: Read + Seek + SyncAll, { @@ -298,7 +317,7 @@ impl StaticHeader { match (loc_1, loc_2) { (Some(loc_1), Some(loc_2)) => { if loc_1 == loc_2 { - Ok(Some(loc_1)) + Ok(Some(SetupResult::Ok(loc_1))) } else if loc_1.initialization_time == loc_2.initialization_time { // Inexplicable disagreement among static headers let err_str = "Appeared to be a Stratis device, but signature blocks disagree."; @@ -307,32 +326,36 @@ impl StaticHeader { // If the first header block is newer, overwrite second with // contents of first. BDA::write(f, &buf_loc_1, MetadataLocation::Second)?; - Ok(Some(loc_1)) + Ok(Some(SetupResult::Ok(loc_1))) } else { // The second header block must be newer, so overwrite first // with contents of second. BDA::write(f, &buf_loc_2, MetadataLocation::First)?; - Ok(Some(loc_2)) + Ok(Some(SetupResult::Ok(loc_2))) } } (None, None) => Ok(None), (Some(loc_1), None) => { // Copy 1 has valid Stratis BDA, copy 2 has no magic, re-write copy 2 BDA::write(f, &buf_loc_1, MetadataLocation::Second)?; - Ok(Some(loc_1)) + Ok(Some(SetupResult::Ok(loc_1))) } (None, Some(loc_2)) => { // Copy 2 has valid Stratis BDA, copy 1 has no magic, re-write copy 1 BDA::write(f, &buf_loc_2, MetadataLocation::First)?; - Ok(Some(loc_2)) + Ok(Some(SetupResult::Ok(loc_2))) } } } (Ok(loc_1), Err(loc_2)) => { // Re-write copy 2 - if loc_1.is_some() { - BDA::write(f, &buf_loc_1, MetadataLocation::Second)?; - Ok(loc_1) + if let Some(loc_1) = loc_1 { + match BDA::write(f, &buf_loc_1, MetadataLocation::Second) { + Ok(_) => Ok(Some(SetupResult::Ok(loc_1))), + Err(err) => { + Ok(Some(SetupResult::OkWithError(loc_1, StratisError::Io(err)))) + } + } } else { // Location 1 doesn't have a signature, but location 2 did, but it got an error, // lets return the error instead as this appears to be a stratis device that @@ -342,9 +365,13 @@ impl StaticHeader { } (Err(loc_1), Ok(loc_2)) => { // Re-write copy 1 - if loc_2.is_some() { - BDA::write(f, &buf_loc_2, MetadataLocation::First)?; - Ok(loc_2) + if let Some(loc_2) = loc_2 { + match BDA::write(f, &buf_loc_2, MetadataLocation::First) { + Ok(_) => Ok(Some(SetupResult::Ok(loc_2))), + Err(err) => { + Ok(Some(SetupResult::OkWithError(loc_2, StratisError::Io(err)))) + } + } } else { // Location 2 doesn't have a signature, but location 1 did, but it got an error, // lets return the error instead as this appears to be a stratis device that @@ -363,10 +390,16 @@ impl StaticHeader { // Copy 1 read OK, 2 resulted in an IO error match StaticHeader::sigblock_from_buf(&buf_loc_1) { Ok(loc_1) => { - if loc_1.is_some() { - BDA::write(f, &buf_loc_1, MetadataLocation::Second)?; + if let Some(loc_1) = loc_1 { + match BDA::write(f, &buf_loc_1, MetadataLocation::Second) { + Ok(_) => Ok(Some(SetupResult::Ok(loc_1))), + Err(err) => { + Ok(Some(SetupResult::OkWithError(loc_1, StratisError::Io(err)))) + } + } + } else { + Ok(None) } - Ok(loc_1) } Err(e) => { // Unable to determine if location 2 has a signature, but location 1 did, @@ -380,10 +413,16 @@ impl StaticHeader { // Copy 2 read OK, 1 resulted in IO Error match StaticHeader::sigblock_from_buf(&buf_loc_2) { Ok(loc_2) => { - if loc_2.is_some() { - BDA::write(f, &buf_loc_2, MetadataLocation::First)?; + if let Some(loc_2) = loc_2 { + match BDA::write(f, &buf_loc_2, MetadataLocation::First) { + Ok(_) => Ok(Some(SetupResult::Ok(loc_2))), + Err(err) => { + Ok(Some(SetupResult::OkWithError(loc_2, StratisError::Io(err)))) + } + } + } else { + Ok(None) } - Ok(loc_2) } Err(e) => { // Unable to determine if location 1 has a signature, but location 2 did, @@ -411,7 +450,11 @@ impl StaticHeader { // it must also have correct CRC, no weird stuff in fields, // etc! match StaticHeader::setup(f) { - Ok(Some(sh)) => Ok(Some((sh.pool_uuid, sh.dev_uuid))), + Ok(Some(SetupResult::Ok(sh))) => Ok(Some((sh.pool_uuid, sh.dev_uuid))), + Ok(Some(SetupResult::OkWithError(sh, err))) => { + warn!("StaticHeader::setup didn't completely succeed: {:?}", err); + Ok(Some((sh.pool_uuid, sh.dev_uuid))) + } Ok(None) => Ok(None), Err(err) => Err(err), }