Skip to content

Commit 22f2281

Browse files
StaticHeader::setup Improve error reporting
1 parent 65c47da commit 22f2281

File tree

1 file changed

+109
-42
lines changed
  • src/engine/strat_engine/backstore/metadata

1 file changed

+109
-42
lines changed

src/engine/strat_engine/backstore/metadata/bda.rs

Lines changed: 109 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,11 @@ impl BDA {
178178
F: Read + Seek + SyncAll,
179179
{
180180
let header = match StaticHeader::setup(f)? {
181-
Some(header) => header,
181+
Some(SetupResult::Ok(header)) => header,
182+
Some(SetupResult::OkWithError(header, err)) => {
183+
setup_warn(&header, err);
184+
header
185+
}
182186
None => return Ok(None),
183187
};
184188

@@ -272,10 +276,36 @@ impl BDA {
272276
where
273277
F: Read + Seek + SyncAll,
274278
{
275-
StaticHeader::setup(f).map(|sh| sh.map(|sh| (sh.pool_uuid, sh.dev_uuid)))
279+
StaticHeader::setup(f).map(|sh| {
280+
sh.map(|sh| match sh {
281+
SetupResult::OkWithError(sh, err) => {
282+
setup_warn(&sh, err);
283+
(sh.pool_uuid, sh.dev_uuid)
284+
}
285+
SetupResult::Ok(sh) => (sh.pool_uuid, sh.dev_uuid),
286+
})
287+
})
276288
}
277289
}
278290

291+
// This function is called in case a failure occurs while trying to repair a header to pretty
292+
// print a warning.
293+
fn setup_warn(header: &StaticHeader, err: StratisError) {
294+
warn!(
295+
"Experienced an I/O error while attempting to repair an ill-formed, \
296+
unreadable, or stale signature block: {:?}. \
297+
Read and returned static header {:?}.",
298+
err, header
299+
);
300+
}
301+
302+
#[derive(Debug)]
303+
#[must_use]
304+
pub enum SetupResult {
305+
Ok(StaticHeader),
306+
OkWithError(StaticHeader, StratisError),
307+
}
308+
279309
#[derive(Eq, PartialEq)]
280310
pub struct StaticHeader {
281311
blkdev_size: Sectors,
@@ -312,20 +342,67 @@ impl StaticHeader {
312342
}
313343

314344
/// Try to find a valid StaticHeader on a device.
345+
///
315346
/// Return the latest copy that validates as a Stratis BDA, however verify both
316347
/// copies and if one validates but one does not, re-write the one that is incorrect. If both
317348
/// copies are valid, but one is newer than the other, rewrite the older one to match.
349+
///
318350
/// Return None if it's not a Stratis device.
351+
///
319352
/// Return an error if the metadata seems to indicate that the device is
320353
/// a Stratis device, but no well-formed signature block could be read.
354+
///
321355
/// Return an error if neither sigblock location can be read.
356+
///
322357
/// Return an error if the sigblocks differ in some unaccountable way.
323-
/// Returns an error if a write intended to repair an ill-formed,
324-
/// unreadable, or stale signature block failed.
325-
fn setup<F>(f: &mut F) -> StratisResult<Option<StaticHeader>>
358+
///
359+
/// Return the latest copy alongside the associated error if a write intended to repair
360+
/// an ill-formed, unreadable, or stale signature failed.
361+
fn setup<F>(f: &mut F) -> StratisResult<Option<SetupResult>>
326362
where
327363
F: Read + Seek + SyncAll,
328364
{
365+
fn write_check<F>(
366+
f: &mut F,
367+
sh_buf: &[u8],
368+
which: MetadataLocation,
369+
header: StaticHeader,
370+
) -> StratisResult<Option<SetupResult>>
371+
where
372+
F: Read + Seek + SyncAll,
373+
{
374+
Ok(match BDA::write(f, &sh_buf, which) {
375+
Ok(_) => Some(SetupResult::Ok(header)),
376+
Err(err) => Some(SetupResult::OkWithError(header, StratisError::Io(err))),
377+
})
378+
}
379+
380+
// Action to take if there appeared to be one malformed sigblock on the device.
381+
//
382+
// If the other sigblock appears not to exist at all, return an error.
383+
// If the other sigblock exists, attempt a repair of the malformed
384+
//
385+
// sigblock and return the other sigblock.
386+
// sh_buf are the bytes of the other sigblock
387+
// sh is the optional other sigblock
388+
// sh_error is the error indicating a malformed sigblock
389+
// write_location is where to write the optional repair.
390+
fn repair_on_sigblock_read_error<F>(
391+
f: &mut F,
392+
sh_buf: &[u8],
393+
sh: Option<StaticHeader>,
394+
sh_error: StratisError,
395+
write_location: MetadataLocation,
396+
) -> StratisResult<Option<SetupResult>>
397+
where
398+
F: Read + Seek + SyncAll,
399+
{
400+
match sh {
401+
Some(sh) => write_check(f, sh_buf, write_location, sh),
402+
None => Err(sh_error),
403+
}
404+
}
405+
329406
match BDA::read(f) {
330407
// We read both copies without an IO error.
331408
(Ok(buf_loc_1), Ok(buf_loc_2)) => match (
@@ -335,7 +412,7 @@ impl StaticHeader {
335412
(Ok(loc_1), Ok(loc_2)) => match (loc_1, loc_2) {
336413
(Some(loc_1), Some(loc_2)) => {
337414
if loc_1 == loc_2 {
338-
Ok(Some(loc_1))
415+
Ok(Some(SetupResult::Ok(loc_1)))
339416
} else if loc_1.initialization_time == loc_2.initialization_time {
340417
// Inexplicable disagreement among static headers
341418
let err_str =
@@ -344,49 +421,37 @@ impl StaticHeader {
344421
} else if loc_1.initialization_time > loc_2.initialization_time {
345422
// If the first header block is newer, overwrite second with
346423
// contents of first.
347-
BDA::write(f, &buf_loc_1, MetadataLocation::Second)?;
348-
Ok(Some(loc_1))
424+
write_check(f, &buf_loc_1, MetadataLocation::Second, loc_1)
349425
} else {
350426
// The second header block must be newer, so overwrite first
351427
// with contents of second.
352-
BDA::write(f, &buf_loc_2, MetadataLocation::First)?;
353-
Ok(Some(loc_2))
428+
write_check(f, &buf_loc_2, MetadataLocation::First, loc_2)
354429
}
355430
}
356431
(None, None) => Ok(None),
357432
(Some(loc_1), None) => {
358433
// Copy 1 has valid Stratis BDA, copy 2 has no magic, re-write copy 2
359-
BDA::write(f, &buf_loc_1, MetadataLocation::Second)?;
360-
Ok(Some(loc_1))
434+
write_check(f, &buf_loc_1, MetadataLocation::Second, loc_1)
361435
}
362436
(None, Some(loc_2)) => {
363437
// Copy 2 has valid Stratis BDA, copy 1 has no magic, re-write copy 1
364-
BDA::write(f, &buf_loc_2, MetadataLocation::First)?;
365-
Ok(Some(loc_2))
438+
write_check(f, &buf_loc_2, MetadataLocation::First, loc_2)
366439
}
367440
},
368-
(Ok(loc_1), Err(loc_2)) => {
369-
if loc_1.is_some() {
370-
BDA::write(f, &buf_loc_1, MetadataLocation::Second)?;
371-
Ok(loc_1)
372-
} else {
373-
// Location 1 doesn't have a signature, but location 2 did, but it got an error,
374-
// lets return the error instead as this appears to be a stratis device that
375-
// has gotten in a bad state.
376-
Err(loc_2)
377-
}
378-
}
379-
(Err(loc_1), Ok(loc_2)) => {
380-
if loc_2.is_some() {
381-
BDA::write(f, &buf_loc_2, MetadataLocation::First)?;
382-
Ok(loc_2)
383-
} else {
384-
// Location 2 doesn't have a signature, but location 1 did, but it got an error,
385-
// lets return the error instead as this appears to be a stratis device that
386-
// has gotten in a bad state.
387-
Err(loc_1)
388-
}
389-
}
441+
(Ok(loc_1), Err(loc_2)) => repair_on_sigblock_read_error(
442+
f,
443+
&buf_loc_1,
444+
loc_1,
445+
loc_2,
446+
MetadataLocation::Second,
447+
),
448+
(Err(loc_1), Ok(loc_2)) => repair_on_sigblock_read_error(
449+
f,
450+
&buf_loc_2,
451+
loc_2,
452+
loc_1,
453+
MetadataLocation::First,
454+
),
390455
(Err(_), Err(_)) => {
391456
let err_str = "Appeared to be a Stratis device, but no valid sigblock found";
392457
Err(StratisError::Engine(ErrorEnum::Invalid, err_str.into()))
@@ -395,10 +460,11 @@ impl StaticHeader {
395460
// Copy 1 read OK, 2 resulted in an IO error
396461
(Ok(buf_loc_1), Err(_)) => match StaticHeader::sigblock_from_buf(&buf_loc_1) {
397462
Ok(loc_1) => {
398-
if loc_1.is_some() {
399-
BDA::write(f, &buf_loc_1, MetadataLocation::Second)?;
463+
if let Some(loc_1) = loc_1 {
464+
write_check(f, &buf_loc_1, MetadataLocation::Second, loc_1)
465+
} else {
466+
Ok(None)
400467
}
401-
Ok(loc_1)
402468
}
403469
Err(e) => {
404470
// Unable to determine if location 2 has a signature, but location 1 did,
@@ -410,10 +476,11 @@ impl StaticHeader {
410476
// Copy 2 read OK, 1 resulted in IO Error
411477
(Err(_), Ok(buf_loc_2)) => match StaticHeader::sigblock_from_buf(&buf_loc_2) {
412478
Ok(loc_2) => {
413-
if loc_2.is_some() {
414-
BDA::write(f, &buf_loc_2, MetadataLocation::First)?;
479+
if let Some(loc_2) = loc_2 {
480+
write_check(f, &buf_loc_2, MetadataLocation::First, loc_2)
481+
} else {
482+
Ok(None)
415483
}
416-
Ok(loc_2)
417484
}
418485
Err(e) => {
419486
// Unable to determine if location 1 has a signature, but location 2 did,

0 commit comments

Comments
 (0)