Skip to content

Commit 448c4e4

Browse files
slegendrMikulas Patocka
authored andcommitted
dm vdo: force read-only mode for a corrupt recovery journal
Ensure the recovery journal does not attempt recovery when blocks with mismatched metadata versions are detected. This check is performed after determining that the blocks are otherwise valid so that it does not interfere with normal recovery. Signed-off-by: Susan LeGendre-McGhee <[email protected]> Signed-off-by: Matthew Sakai <[email protected]> Signed-off-by: Mikulas Patocka <[email protected]>
1 parent f3ff668 commit 448c4e4

File tree

3 files changed

+24
-19
lines changed

3 files changed

+24
-19
lines changed

drivers/md/dm-vdo/repair.c

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,17 +1202,14 @@ static bool __must_check is_valid_recovery_journal_block(const struct recovery_j
12021202
* @journal: The journal to use.
12031203
* @header: The unpacked block header to check.
12041204
* @sequence: The expected sequence number.
1205-
* @type: The expected metadata type.
12061205
*
12071206
* Return: True if the block matches.
12081207
*/
12091208
static bool __must_check is_exact_recovery_journal_block(const struct recovery_journal *journal,
12101209
const struct recovery_block_header *header,
1211-
sequence_number_t sequence,
1212-
enum vdo_metadata_type type)
1210+
sequence_number_t sequence)
12131211
{
1214-
return ((header->metadata_type == type) &&
1215-
(header->sequence_number == sequence) &&
1212+
return ((header->sequence_number == sequence) &&
12161213
(is_valid_recovery_journal_block(journal, header, true)));
12171214
}
12181215

@@ -1371,7 +1368,8 @@ static void extract_entries_from_block(struct repair_completion *repair,
13711368
get_recovery_journal_block_header(journal, repair->journal_data,
13721369
sequence);
13731370

1374-
if (!is_exact_recovery_journal_block(journal, &header, sequence, format)) {
1371+
if (!is_exact_recovery_journal_block(journal, &header, sequence) ||
1372+
(header.metadata_type != format)) {
13751373
/* This block is invalid, so skip it. */
13761374
return;
13771375
}
@@ -1557,10 +1555,13 @@ static int parse_journal_for_recovery(struct repair_completion *repair)
15571555
sequence_number_t i, head;
15581556
bool found_entries = false;
15591557
struct recovery_journal *journal = repair->completion.vdo->recovery_journal;
1558+
struct recovery_block_header header;
1559+
enum vdo_metadata_type expected_format;
15601560

15611561
head = min(repair->block_map_head, repair->slab_journal_head);
1562+
header = get_recovery_journal_block_header(journal, repair->journal_data, head);
1563+
expected_format = header.metadata_type;
15621564
for (i = head; i <= repair->highest_tail; i++) {
1563-
struct recovery_block_header header;
15641565
journal_entry_count_t block_entries;
15651566
u8 j;
15661567

@@ -1572,17 +1573,15 @@ static int parse_journal_for_recovery(struct repair_completion *repair)
15721573
};
15731574

15741575
header = get_recovery_journal_block_header(journal, repair->journal_data, i);
1575-
if (header.metadata_type == VDO_METADATA_RECOVERY_JOURNAL) {
1576-
/* This is an old format block, so we need to upgrade */
1577-
vdo_log_error_strerror(VDO_UNSUPPORTED_VERSION,
1578-
"Recovery journal is in the old format. Downgrade and complete recovery, then upgrade with a clean volume");
1579-
return VDO_UNSUPPORTED_VERSION;
1580-
}
1581-
1582-
if (!is_exact_recovery_journal_block(journal, &header, i,
1583-
VDO_METADATA_RECOVERY_JOURNAL_2)) {
1576+
if (!is_exact_recovery_journal_block(journal, &header, i)) {
15841577
/* A bad block header was found so this must be the end of the journal. */
15851578
break;
1579+
} else if (header.metadata_type != expected_format) {
1580+
/* There is a mix of old and new format blocks, so we need to rebuild. */
1581+
vdo_log_error_strerror(VDO_CORRUPT_JOURNAL,
1582+
"Recovery journal is in an invalid format, a read-only rebuild is required.");
1583+
vdo_enter_read_only_mode(repair->completion.vdo, VDO_CORRUPT_JOURNAL);
1584+
return VDO_CORRUPT_JOURNAL;
15861585
}
15871586

15881587
block_entries = header.entry_count;
@@ -1618,8 +1617,14 @@ static int parse_journal_for_recovery(struct repair_completion *repair)
16181617
break;
16191618
}
16201619

1621-
if (!found_entries)
1620+
if (!found_entries) {
16221621
return validate_heads(repair);
1622+
} else if (expected_format == VDO_METADATA_RECOVERY_JOURNAL) {
1623+
/* All journal blocks have the old format, so we need to upgrade. */
1624+
vdo_log_error_strerror(VDO_UNSUPPORTED_VERSION,
1625+
"Recovery journal is in the old format. Downgrade and complete recovery, then upgrade with a clean volume");
1626+
return VDO_UNSUPPORTED_VERSION;
1627+
}
16231628

16241629
/* Set the tail to the last valid tail block, if there is one. */
16251630
if (repair->tail_recovery_point.sector_count == 0)

drivers/md/dm-vdo/status-codes.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ const struct error_info vdo_status_list[] = {
2828
{ "VDO_LOCK_ERROR", "A lock is held incorrectly" },
2929
{ "VDO_READ_ONLY", "The device is in read-only mode" },
3030
{ "VDO_SHUTTING_DOWN", "The device is shutting down" },
31-
{ "VDO_CORRUPT_JOURNAL", "Recovery journal entries corrupted" },
31+
{ "VDO_CORRUPT_JOURNAL", "Recovery journal corrupted" },
3232
{ "VDO_TOO_MANY_SLABS", "Exceeds maximum number of slabs supported" },
3333
{ "VDO_INVALID_FRAGMENT", "Compressed block fragment is invalid" },
3434
{ "VDO_RETRY_AFTER_REBUILD", "Retry operation after rebuilding finishes" },

drivers/md/dm-vdo/status-codes.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ enum vdo_status_codes {
5252
VDO_READ_ONLY,
5353
/* the VDO is shutting down */
5454
VDO_SHUTTING_DOWN,
55-
/* the recovery journal has corrupt entries */
55+
/* the recovery journal has corrupt entries or corrupt metadata */
5656
VDO_CORRUPT_JOURNAL,
5757
/* exceeds maximum number of slabs supported */
5858
VDO_TOO_MANY_SLABS,

0 commit comments

Comments
 (0)