From: Susan LeGendre-McGhee <slege...@redhat.com>

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 <slege...@redhat.com>
Signed-off-by: Matthew Sakai <msa...@redhat.com>
---
 drivers/md/dm-vdo/repair.c       | 39 ++++++++++++++++++--------------
 drivers/md/dm-vdo/status-codes.c |  2 +-
 drivers/md/dm-vdo/status-codes.h |  2 +-
 3 files changed, 24 insertions(+), 19 deletions(-)

diff --git a/drivers/md/dm-vdo/repair.c b/drivers/md/dm-vdo/repair.c
index 28475eee0058..c8a8a75b45b9 100644
--- a/drivers/md/dm-vdo/repair.c
+++ b/drivers/md/dm-vdo/repair.c
@@ -1201,17 +1201,14 @@ static bool __must_check 
is_valid_recovery_journal_block(const struct recovery_j
  * @journal: The journal to use.
  * @header: The unpacked block header to check.
  * @sequence: The expected sequence number.
- * @type: The expected metadata type.
  *
  * Return: True if the block matches.
  */
 static bool __must_check is_exact_recovery_journal_block(const struct 
recovery_journal *journal,
                                                         const struct 
recovery_block_header *header,
-                                                        sequence_number_t 
sequence,
-                                                        enum vdo_metadata_type 
type)
+                                                        sequence_number_t 
sequence)
 {
-       return ((header->metadata_type == type) &&
-               (header->sequence_number == sequence) &&
+       return ((header->sequence_number == sequence) &&
                (is_valid_recovery_journal_block(journal, header, true)));
 }
 
@@ -1370,7 +1367,8 @@ static void extract_entries_from_block(struct 
repair_completion *repair,
                get_recovery_journal_block_header(journal, repair->journal_data,
                                                  sequence);
 
-       if (!is_exact_recovery_journal_block(journal, &header, sequence, 
format)) {
+       if (!is_exact_recovery_journal_block(journal, &header, sequence) ||
+           (header.metadata_type != format)) {
                /* This block is invalid, so skip it. */
                return;
        }
@@ -1556,10 +1554,13 @@ static int parse_journal_for_recovery(struct 
repair_completion *repair)
        sequence_number_t i, head;
        bool found_entries = false;
        struct recovery_journal *journal = 
repair->completion.vdo->recovery_journal;
+       struct recovery_block_header header;
+       enum vdo_metadata_type expected_format;
 
        head = min(repair->block_map_head, repair->slab_journal_head);
+       header = get_recovery_journal_block_header(journal, 
repair->journal_data, head);
+       expected_format = header.metadata_type;
        for (i = head; i <= repair->highest_tail; i++) {
-               struct recovery_block_header header;
                journal_entry_count_t block_entries;
                u8 j;
 
@@ -1571,17 +1572,15 @@ static int parse_journal_for_recovery(struct 
repair_completion *repair)
                };
 
                header = get_recovery_journal_block_header(journal, 
repair->journal_data, i);
-               if (header.metadata_type == VDO_METADATA_RECOVERY_JOURNAL) {
-                       /* This is an old format block, so we need to upgrade */
-                       vdo_log_error_strerror(VDO_UNSUPPORTED_VERSION,
-                                              "Recovery journal is in the old 
format. Downgrade and complete recovery, then upgrade with a clean volume");
-                       return VDO_UNSUPPORTED_VERSION;
-               }
-
-               if (!is_exact_recovery_journal_block(journal, &header, i,
-                                                    
VDO_METADATA_RECOVERY_JOURNAL_2)) {
+               if (!is_exact_recovery_journal_block(journal, &header, i)) {
                        /* A bad block header was found so this must be the end 
of the journal. */
                        break;
+               } else if (header.metadata_type != expected_format) {
+                       /* There is a mix of old and new format blocks, so we 
need to rebuild. */
+                       vdo_log_error_strerror(VDO_CORRUPT_JOURNAL,
+                                              "Recovery journal is in an 
invalid format, a read-only rebuild is required.");
+                       vdo_enter_read_only_mode(repair->completion.vdo, 
VDO_CORRUPT_JOURNAL);
+                       return VDO_CORRUPT_JOURNAL;
                }
 
                block_entries = header.entry_count;
@@ -1617,8 +1616,14 @@ static int parse_journal_for_recovery(struct 
repair_completion *repair)
                        break;
        }
 
-       if (!found_entries)
+       if (!found_entries) {
                return validate_heads(repair);
+       } else if (expected_format == VDO_METADATA_RECOVERY_JOURNAL) {
+               /* All journal blocks have the old format, so we need to 
upgrade. */
+               vdo_log_error_strerror(VDO_UNSUPPORTED_VERSION,
+                                      "Recovery journal is in the old format. 
Downgrade and complete recovery, then upgrade with a clean volume");
+               return VDO_UNSUPPORTED_VERSION;
+       }
 
        /* Set the tail to the last valid tail block, if there is one. */
        if (repair->tail_recovery_point.sector_count == 0)
diff --git a/drivers/md/dm-vdo/status-codes.c b/drivers/md/dm-vdo/status-codes.c
index d3493450b169..dd252d660b6d 100644
--- a/drivers/md/dm-vdo/status-codes.c
+++ b/drivers/md/dm-vdo/status-codes.c
@@ -28,7 +28,7 @@ const struct error_info vdo_status_list[] = {
        { "VDO_LOCK_ERROR", "A lock is held incorrectly" },
        { "VDO_READ_ONLY", "The device is in read-only mode" },
        { "VDO_SHUTTING_DOWN", "The device is shutting down" },
-       { "VDO_CORRUPT_JOURNAL", "Recovery journal entries corrupted" },
+       { "VDO_CORRUPT_JOURNAL", "Recovery journal corrupted" },
        { "VDO_TOO_MANY_SLABS", "Exceeds maximum number of slabs supported" },
        { "VDO_INVALID_FRAGMENT", "Compressed block fragment is invalid" },
        { "VDO_RETRY_AFTER_REBUILD", "Retry operation after rebuilding 
finishes" },
diff --git a/drivers/md/dm-vdo/status-codes.h b/drivers/md/dm-vdo/status-codes.h
index 72da04159f88..426dc8e2ca5d 100644
--- a/drivers/md/dm-vdo/status-codes.h
+++ b/drivers/md/dm-vdo/status-codes.h
@@ -52,7 +52,7 @@ enum vdo_status_codes {
        VDO_READ_ONLY,
        /* the VDO is shutting down */
        VDO_SHUTTING_DOWN,
-       /* the recovery journal has corrupt entries */
+       /* the recovery journal has corrupt entries or corrupt metadata */
        VDO_CORRUPT_JOURNAL,
        /* exceeds maximum number of slabs supported */
        VDO_TOO_MANY_SLABS,
-- 
2.45.2


Reply via email to