diff options
author | Thirunarayanan Balathandayuthapani <thiru@mariadb.com> | 2019-06-28 18:49:43 +0530 |
---|---|---|
committer | Thirunarayanan Balathandayuthapani <thiru@mariadb.com> | 2019-06-28 18:58:52 +0530 |
commit | e4a0dbfb4aa77a9d41039f5cd7144d98a6b9baed (patch) | |
tree | d2c2344720e5b47345b0aecf642165ec17954f76 /extra/innochecksum.cc | |
parent | f7a4a8719bd59eca27e3e5e467c138853aa63dd5 (diff) | |
download | mariadb-git-e4a0dbfb4aa77a9d41039f5cd7144d98a6b9baed.tar.gz |
MDEV-19781 Add page id matching check in innochecksum tool
Added the condition in innochecksum tool to check page id mismatch.
This could catch the write corruption caused by InnoDB.
Added the debug insert inside fil_io() to check whether it writes
the page to wrong offset.
Diffstat (limited to 'extra/innochecksum.cc')
-rw-r--r-- | extra/innochecksum.cc | 101 |
1 files changed, 88 insertions, 13 deletions
diff --git a/extra/innochecksum.cc b/extra/innochecksum.cc index 3abc541b028..514058cc3f3 100644 --- a/extra/innochecksum.cc +++ b/extra/innochecksum.cc @@ -100,6 +100,8 @@ ulong srv_page_size; page_size_t univ_page_size(0, 0, false); /* Current page number (0 based). */ unsigned long long cur_page_num; +/* Current space. */ +unsigned long long cur_space; /* Skip the checksum verification. */ static bool no_check; /* Enabled for strict checksum verification. */ @@ -451,6 +453,27 @@ ulong read_file( return bytes; } +/** Check whether the page contains all zeroes. +@param[in] buf page +@param[in] size physical size of the page +@return true if the page is all zeroes; else false */ +static bool is_page_all_zeroes( + byte* buf, + ulint size) +{ + /* On pages that are not all zero, the page number + must match. */ + const ulint* p = reinterpret_cast<const ulint*>(buf); + const ulint* const end = reinterpret_cast<const ulint*>(buf + size); + do { + if (*p++) { + return false; + } + } while (p != end); + + return true; +} + /** Check if page is corrupted or not. @param[in] buf page frame @param[in] page_size page size @@ -462,10 +485,10 @@ ulong read_file( static bool is_page_corrupted( - byte* buf, + byte* buf, const page_size_t& page_size, - bool is_encrypted, - bool is_compressed) + bool is_encrypted, + bool is_compressed) { /* enable if page is corrupted. */ @@ -478,6 +501,24 @@ is_page_corrupted( ulint space_id = mach_read_from_4( buf + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID); + if (mach_read_from_4(buf + FIL_PAGE_OFFSET) != cur_page_num + || space_id != cur_space) { + /* On pages that are not all zero, the page number + must match. */ + if (is_page_all_zeroes(buf, page_size.physical())) { + return false; + } + + if (is_log_enabled) { + fprintf(log_file, + "page id mismatch space::" ULINTPF + " page::%llu \n", + space_id, cur_page_num); + } + + return true; + } + /* We can't trust only a page type, thus we take account also fsp_flags or crypt_data on page 0 */ if ((page_type == FIL_PAGE_PAGE_COMPRESSED && is_compressed) || @@ -1576,9 +1617,6 @@ int main( FILE* fil_page_type = NULL; fpos_t pos; - /* Use to check the space id of given file. If space_id is zero, - then check whether page is doublewrite buffer.*/ - ulint space_id = 0UL; /* enable when space_id of given file is zero. */ bool is_system_tablespace = false; @@ -1700,9 +1738,8 @@ int main( /* enable variable is_system_tablespace when space_id of given file is zero. Use to skip the checksum verification and rewrite for doublewrite pages. */ - is_system_tablespace = (!memcmp(&space_id, buf + - FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, 4)) - ? true : false; + cur_space = mach_read_from_4(buf + FIL_PAGE_SPACE_ID); + cur_page_num = mach_read_from_4(buf + FIL_PAGE_OFFSET); /* Determine page size, zip_size and page compression from fsp_flags and encryption metadata from page 0 */ @@ -1715,7 +1752,9 @@ int main( srv_page_size = page_size.logical(); bool is_compressed = FSP_FLAGS_HAS_PAGE_COMPRESSION(flags); - if (page_size.physical() > UNIV_ZIP_SIZE_MIN) { + if (physical_page_size == UNIV_ZIP_SIZE_MIN) { + partial_page_read = false; + } else { /* Read rest of the page 0 to determine crypt_data */ bytes = ulong(read_file(buf, partial_page_read, page_size.physical(), fil_in)); @@ -1731,6 +1770,7 @@ int main( partial_page_read = false; } + /* Now that we have full page 0 in buffer, check encryption */ bool is_encrypted = check_encryption(filename, page_size, buf); @@ -1741,7 +1781,9 @@ int main( unsigned long long tmp_allow_mismatches = allow_mismatches; allow_mismatches = 0; - exit_status = verify_checksum(buf, page_size, is_encrypted, is_compressed, &mismatch_count); + exit_status = verify_checksum( + buf, page_size, is_encrypted, + is_compressed, &mismatch_count); if (exit_status) { fprintf(stderr, "Error: Page 0 checksum mismatch, can't continue. \n"); @@ -1805,6 +1847,36 @@ int main( } } + off_t cur_offset = 0; + /* Find the first non all-zero page and fetch the + space id from there. */ + while (is_page_all_zeroes(buf, physical_page_size)) { + bytes = ulong(read_file( + buf, false, physical_page_size, + fil_in)); + + if (feof(fil_in)) { + fprintf(stderr, "All are " + "zero-filled pages."); + goto my_exit; + } + + cur_offset++; + } + + cur_space = mach_read_from_4(buf + FIL_PAGE_SPACE_ID); + is_system_tablespace = (cur_space == 0); + + if (cur_offset > 0) { + /* Re-read the non-zero page to check the + checksum. So move the file pointer to + previous position and reset the page number too. */ + cur_page_num = mach_read_from_4(buf + FIL_PAGE_OFFSET); + if (!start_page) { + goto first_non_zero; + } + } + /* seek to the necessary position */ if (start_page) { if (!read_from_stdin) { @@ -1902,6 +1974,7 @@ int main( goto my_exit; } +first_non_zero: if (is_system_tablespace) { /* enable when page is double write buffer.*/ skip_page = is_page_doublewritebuffer(buf); @@ -1922,8 +1995,10 @@ int main( checksum verification.*/ if (!no_check && !skip_page - && (exit_status = verify_checksum(buf, page_size, - is_encrypted, is_compressed, &mismatch_count))) { + && (exit_status = verify_checksum( + buf, page_size, + is_encrypted, is_compressed, + &mismatch_count))) { goto my_exit; } |