@@ -178,7 +178,11 @@ impl BDA {
178
178
F : Read + Seek + SyncAll ,
179
179
{
180
180
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
+ }
182
186
None => return Ok ( None ) ,
183
187
} ;
184
188
@@ -272,10 +276,36 @@ impl BDA {
272
276
where
273
277
F : Read + Seek + SyncAll ,
274
278
{
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
+ } )
276
288
}
277
289
}
278
290
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
+
279
309
#[ derive( Eq , PartialEq ) ]
280
310
pub struct StaticHeader {
281
311
blkdev_size : Sectors ,
@@ -312,20 +342,67 @@ impl StaticHeader {
312
342
}
313
343
314
344
/// Try to find a valid StaticHeader on a device.
345
+ ///
315
346
/// Return the latest copy that validates as a Stratis BDA, however verify both
316
347
/// copies and if one validates but one does not, re-write the one that is incorrect. If both
317
348
/// copies are valid, but one is newer than the other, rewrite the older one to match.
349
+ ///
318
350
/// Return None if it's not a Stratis device.
351
+ ///
319
352
/// Return an error if the metadata seems to indicate that the device is
320
353
/// a Stratis device, but no well-formed signature block could be read.
354
+ ///
321
355
/// Return an error if neither sigblock location can be read.
356
+ ///
322
357
/// 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 > >
326
362
where
327
363
F : Read + Seek + SyncAll ,
328
364
{
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
+
329
406
match BDA :: read ( f) {
330
407
// We read both copies without an IO error.
331
408
( Ok ( buf_loc_1) , Ok ( buf_loc_2) ) => match (
@@ -335,7 +412,7 @@ impl StaticHeader {
335
412
( Ok ( loc_1) , Ok ( loc_2) ) => match ( loc_1, loc_2) {
336
413
( Some ( loc_1) , Some ( loc_2) ) => {
337
414
if loc_1 == loc_2 {
338
- Ok ( Some ( loc_1) )
415
+ Ok ( Some ( SetupResult :: Ok ( loc_1) ) )
339
416
} else if loc_1. initialization_time == loc_2. initialization_time {
340
417
// Inexplicable disagreement among static headers
341
418
let err_str =
@@ -344,49 +421,37 @@ impl StaticHeader {
344
421
} else if loc_1. initialization_time > loc_2. initialization_time {
345
422
// If the first header block is newer, overwrite second with
346
423
// 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)
349
425
} else {
350
426
// The second header block must be newer, so overwrite first
351
427
// 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)
354
429
}
355
430
}
356
431
( None , None ) => Ok ( None ) ,
357
432
( Some ( loc_1) , None ) => {
358
433
// 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)
361
435
}
362
436
( None , Some ( loc_2) ) => {
363
437
// 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)
366
439
}
367
440
} ,
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
+ ) ,
390
455
( Err ( _) , Err ( _) ) => {
391
456
let err_str = "Appeared to be a Stratis device, but no valid sigblock found" ;
392
457
Err ( StratisError :: Engine ( ErrorEnum :: Invalid , err_str. into ( ) ) )
@@ -395,10 +460,11 @@ impl StaticHeader {
395
460
// Copy 1 read OK, 2 resulted in an IO error
396
461
( Ok ( buf_loc_1) , Err ( _) ) => match StaticHeader :: sigblock_from_buf ( & buf_loc_1) {
397
462
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 )
400
467
}
401
- Ok ( loc_1)
402
468
}
403
469
Err ( e) => {
404
470
// Unable to determine if location 2 has a signature, but location 1 did,
@@ -410,10 +476,11 @@ impl StaticHeader {
410
476
// Copy 2 read OK, 1 resulted in IO Error
411
477
( Err ( _) , Ok ( buf_loc_2) ) => match StaticHeader :: sigblock_from_buf ( & buf_loc_2) {
412
478
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 )
415
483
}
416
- Ok ( loc_2)
417
484
}
418
485
Err ( e) => {
419
486
// Unable to determine if location 1 has a signature, but location 2 did,
0 commit comments