diff options
author | Jan Lindström <jan.lindstrom@mariadb.com> | 2016-10-27 08:18:14 +0300 |
---|---|---|
committer | Jan Lindström <jan.lindstrom@mariadb.com> | 2016-10-29 10:09:06 +0300 |
commit | bc323727de312b32e80ae9590e2346414746a594 (patch) | |
tree | 565973c26de468451713d9637fbea74d4ce1ad19 /storage | |
parent | c1bbedbd4a20a8bd9354296244b6ec6263b29c6b (diff) | |
download | mariadb-git-bc323727de312b32e80ae9590e2346414746a594.tar.gz |
MDEV-10977: [ERROR] InnoDB: Block in space_id 0 in file ibdata1 encrypted.
MDEV-10394: Innodb system table space corrupted
Analysis: After we have read the page in buf_page_io_complete try to
find if the page is encrypted or corrupted. Encryption was determined
by reading FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION field from FIL-header
as a key_version. However, this field is not always zero even when
encryption is not used. Thus, incorrect key_version could lead situation where
decryption is tried to page that is not encrypted.
Fix: We still read key_version information from FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION
field but also check if tablespace has encryption information before trying
encrypt the page.
Diffstat (limited to 'storage')
-rw-r--r-- | storage/innobase/buf/buf0buf.cc | 78 | ||||
-rw-r--r-- | storage/xtradb/buf/buf0buf.cc | 269 |
2 files changed, 240 insertions, 107 deletions
diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index b3eaf4bf5a9..94913098063 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -526,6 +526,14 @@ buf_page_is_checksum_valid_crc32( { ib_uint32_t crc32 = buf_calc_page_crc32(read_buf); +#ifdef UNIV_DEBUG_LEVEL2 + if (!(checksum_field1 == crc32 && checksum_field2 == crc32)) { + ib_logf(IB_LOG_LEVEL_INFO, + "Page checksum crc32 not valid field1 %lu field2 %lu crc32 %lu.", + checksum_field1, checksum_field2, crc32); + } +#endif + return(checksum_field1 == crc32 && checksum_field2 == crc32); } @@ -553,6 +561,13 @@ buf_page_is_checksum_valid_innodb( if (checksum_field2 != mach_read_from_4(read_buf + FIL_PAGE_LSN) && checksum_field2 != buf_calc_page_old_checksum(read_buf)) { +#ifdef UNIV_DEBUG_LEVEL2 + ib_logf(IB_LOG_LEVEL_INFO, + "Page checksum innodb not valid field1 %lu field2 %lu crc32 %lu lsn %lu.", + checksum_field1, checksum_field2, buf_calc_page_old_checksum(read_buf), + mach_read_from_4(read_buf + FIL_PAGE_LSN) + ); +#endif return(false); } @@ -563,6 +578,13 @@ buf_page_is_checksum_valid_innodb( if (checksum_field1 != 0 && checksum_field1 != buf_calc_page_new_checksum(read_buf)) { +#ifdef UNIV_DEBUG_LEVEL2 + ib_logf(IB_LOG_LEVEL_INFO, + "Page checksum innodb not valid field1 %lu field2 %lu crc32 %lu lsn %lu.", + checksum_field1, checksum_field2, buf_calc_page_old_checksum(read_buf), + mach_read_from_4(read_buf + FIL_PAGE_LSN) + ); +#endif return(false); } @@ -581,6 +603,16 @@ buf_page_is_checksum_valid_none( ulint checksum_field1, ulint checksum_field2) { +#ifdef UNIV_DEBUG_LEVEL2 + if (!(checksum_field1 == checksum_field2 || checksum_field1 == BUF_NO_CHECKSUM_MAGIC)) { + ib_logf(IB_LOG_LEVEL_INFO, + "Page checksum none not valid field1 %lu field2 %lu crc32 %lu lsn %lu.", + checksum_field1, checksum_field2, buf_calc_page_old_checksum(read_buf), + mach_read_from_4(read_buf + FIL_PAGE_LSN) + ); + } +#endif + return(checksum_field1 == checksum_field2 && checksum_field1 == BUF_NO_CHECKSUM_MAGIC); } @@ -598,9 +630,21 @@ buf_page_is_corrupted( ulint zip_size) /*!< in: size of compressed page; 0 for uncompressed pages */ { - ulint page_encrypted = fil_page_is_encrypted(read_buf); ulint checksum_field1; ulint checksum_field2; + ulint space_id = mach_read_from_4( + read_buf + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID); + fil_space_crypt_t* crypt_data = fil_space_get_crypt_data(space_id); + bool page_encrypted = false; + + /* Page is encrypted if encryption information is found from + tablespace and page contains used key_version. This is true + also for pages first compressed and then encrypted. */ + if (crypt_data && + crypt_data->type != CRYPT_SCHEME_UNENCRYPTED && + fil_page_is_encrypted(read_buf)) { + page_encrypted = true; + } if (!page_encrypted && !zip_size && memcmp(read_buf + FIL_PAGE_LSN + 4, @@ -610,6 +654,11 @@ buf_page_is_corrupted( /* Stored log sequence numbers at the start and the end of page do not match */ + ib_logf(IB_LOG_LEVEL_INFO, + "Log sequence number at the start %lu and the end %lu do not match.", + mach_read_from_4(read_buf + FIL_PAGE_LSN + 4), + mach_read_from_4(read_buf + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM + 4)); + return(TRUE); } @@ -676,6 +725,9 @@ buf_page_is_corrupted( /* make sure that the page is really empty */ for (ulint i = 0; i < UNIV_PAGE_SIZE; i++) { if (read_buf[i] != 0) { + ib_logf(IB_LOG_LEVEL_INFO, + "Checksum fields zero but page is not empty."); + return(TRUE); } } @@ -686,7 +738,7 @@ buf_page_is_corrupted( DBUG_EXECUTE_IF("buf_page_is_corrupt_failure", return(TRUE); ); ulint page_no = mach_read_from_4(read_buf + FIL_PAGE_OFFSET); - ulint space_id = mach_read_from_4(read_buf + FIL_PAGE_SPACE_ID); + const srv_checksum_algorithm_t curr_algo = static_cast<srv_checksum_algorithm_t>(srv_checksum_algorithm); @@ -4531,7 +4583,7 @@ buf_page_io_complete( if (io_type == BUF_IO_READ) { ulint read_page_no; ulint read_space_id; - byte* frame; + byte* frame = NULL; if (!buf_page_decrypt_after_read(bpage)) { /* encryption error! */ @@ -4540,7 +4592,8 @@ buf_page_io_complete( } else { frame = ((buf_block_t*) bpage)->frame; } - goto corrupt; + + goto database_corrupted; } if (buf_page_get_zip_size(bpage)) { @@ -4551,7 +4604,7 @@ buf_page_io_complete( FALSE)) { buf_pool->n_pend_unzip--; - goto corrupt; + goto database_corrupted; } buf_pool->n_pend_unzip--; } else { @@ -4614,7 +4667,7 @@ buf_page_io_complete( } goto page_not_corrupt; ;); -corrupt: +database_corrupted: bool corrupted = buf_page_check_corrupt(bpage); if (corrupted) { @@ -6177,6 +6230,19 @@ buf_page_decrypt_after_read( bool page_compressed_encrypted = fil_page_is_compressed_encrypted(dst_frame); buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); bool success = true; + ulint space_id = mach_read_from_4( + dst_frame + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID); + fil_space_crypt_t* crypt_data = fil_space_get_crypt_data(space_id); + + /* Page is encrypted if encryption information is found from + tablespace and page contains used key_version. This is true + also for pages first compressed and then encrypted. */ + if (!crypt_data || + (crypt_data && + crypt_data->type == CRYPT_SCHEME_UNENCRYPTED && + key_version != 0)) { + key_version = 0; + } /* If page is encrypted read post-encryption checksum */ if (!page_compressed_encrypted && key_version != 0) { diff --git a/storage/xtradb/buf/buf0buf.cc b/storage/xtradb/buf/buf0buf.cc index a81d21a04b5..e77225a3bd2 100644 --- a/storage/xtradb/buf/buf0buf.cc +++ b/storage/xtradb/buf/buf0buf.cc @@ -595,6 +595,14 @@ buf_page_is_checksum_valid_crc32( { ib_uint32_t crc32 = buf_calc_page_crc32(read_buf); +#ifdef UNIV_DEBUG_LEVEL2 + if (!(checksum_field1 == crc32 && checksum_field2 == crc32)) { + ib_logf(IB_LOG_LEVEL_INFO, + "Page checksum crc32 not valid field1 %lu field2 %lu crc32 %lu.", + checksum_field1, checksum_field2, crc32); + } +#endif + return(checksum_field1 == crc32 && checksum_field2 == crc32); } @@ -622,6 +630,13 @@ buf_page_is_checksum_valid_innodb( if (checksum_field2 != mach_read_from_4(read_buf + FIL_PAGE_LSN) && checksum_field2 != buf_calc_page_old_checksum(read_buf)) { +#ifdef UNIV_DEBUG_LEVEL2 + ib_logf(IB_LOG_LEVEL_INFO, + "Page checksum innodb not valid field1 %lu field2 %lu crc32 %lu lsn %lu.", + checksum_field1, checksum_field2, buf_calc_page_old_checksum(read_buf), + mach_read_from_4(read_buf + FIL_PAGE_LSN) + ); +#endif return(false); } @@ -632,6 +647,13 @@ buf_page_is_checksum_valid_innodb( if (checksum_field1 != 0 && checksum_field1 != buf_calc_page_new_checksum(read_buf)) { +#ifdef UNIV_DEBUG_LEVEL2 + ib_logf(IB_LOG_LEVEL_INFO, + "Page checksum innodb not valid field1 %lu field2 %lu crc32 %lu lsn %lu.", + checksum_field1, checksum_field2, buf_calc_page_old_checksum(read_buf), + mach_read_from_4(read_buf + FIL_PAGE_LSN) + ); +#endif return(false); } @@ -650,6 +672,16 @@ buf_page_is_checksum_valid_none( ulint checksum_field1, ulint checksum_field2) { +#ifdef UNIV_DEBUG_LEVEL2 + if (!(checksum_field1 == checksum_field2 || checksum_field1 == BUF_NO_CHECKSUM_MAGIC)) { + ib_logf(IB_LOG_LEVEL_INFO, + "Page checksum none not valid field1 %lu field2 %lu crc32 %lu lsn %lu.", + checksum_field1, checksum_field2, buf_calc_page_old_checksum(read_buf), + mach_read_from_4(read_buf + FIL_PAGE_LSN) + ); + } +#endif + return(checksum_field1 == checksum_field2 && checksum_field1 == BUF_NO_CHECKSUM_MAGIC); } @@ -667,9 +699,21 @@ buf_page_is_corrupted( ulint zip_size) /*!< in: size of compressed page; 0 for uncompressed pages */ { - ulint page_encrypted = fil_page_is_encrypted(read_buf); ulint checksum_field1; ulint checksum_field2; + ulint space_id = mach_read_from_4( + read_buf + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID); + fil_space_crypt_t* crypt_data = fil_space_get_crypt_data(space_id); + bool page_encrypted = false; + + /* Page is encrypted if encryption information is found from + tablespace and page contains used key_version. This is true + also for pages first compressed and then encrypted. */ + if (crypt_data && + crypt_data->type != CRYPT_SCHEME_UNENCRYPTED && + fil_page_is_encrypted(read_buf)) { + page_encrypted = true; + } if (!page_encrypted && !zip_size && memcmp(read_buf + FIL_PAGE_LSN + 4, @@ -679,6 +723,11 @@ buf_page_is_corrupted( /* Stored log sequence numbers at the start and the end of page do not match */ + ib_logf(IB_LOG_LEVEL_INFO, + "Log sequence number at the start %lu and the end %lu do not match.", + mach_read_from_4(read_buf + FIL_PAGE_LSN + 4), + mach_read_from_4(read_buf + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM + 4)); + return(TRUE); } @@ -745,6 +794,9 @@ buf_page_is_corrupted( /* make sure that the page is really empty */ for (ulint i = 0; i < UNIV_PAGE_SIZE; i++) { if (read_buf[i] != 0) { + ib_logf(IB_LOG_LEVEL_INFO, + "Checksum fields zero but page is not empty."); + return(TRUE); } } @@ -755,7 +807,7 @@ buf_page_is_corrupted( DBUG_EXECUTE_IF("buf_page_is_corrupt_failure", return(TRUE); ); ulint page_no = mach_read_from_4(read_buf + FIL_PAGE_OFFSET); - ulint space_id = mach_read_from_4(read_buf + FIL_PAGE_SPACE_ID); + const srv_checksum_algorithm_t curr_algo = static_cast<srv_checksum_algorithm_t>(srv_checksum_algorithm); @@ -4645,7 +4697,7 @@ buf_page_io_complete( if (io_type == BUF_IO_READ) { ulint read_page_no; ulint read_space_id; - byte* frame; + byte* frame = NULL; if (!buf_page_decrypt_after_read(bpage)) { /* encryption error! */ @@ -4654,7 +4706,8 @@ buf_page_io_complete( } else { frame = ((buf_block_t*) bpage)->frame; } - goto corrupt; + + goto database_corrupted; } if (buf_page_get_zip_size(bpage)) { @@ -4666,7 +4719,8 @@ buf_page_io_complete( os_atomic_decrement_ulint( &buf_pool->n_pend_unzip, 1); - goto corrupt; + + goto database_corrupted; } os_atomic_decrement_ulint(&buf_pool->n_pend_unzip, 1); } else { @@ -4714,119 +4768,119 @@ buf_page_io_complete( if (UNIV_LIKELY(!bpage->is_corrupt || !srv_pass_corrupt_table)) { - /* From version 3.23.38 up we store the page checksum - to the 4 first bytes of the page end lsn field */ - - if (buf_page_is_corrupted(true, frame, - buf_page_get_zip_size(bpage))) { - - /* Not a real corruption if it was triggered by - error injection */ - DBUG_EXECUTE_IF("buf_page_is_corrupt_failure", - if (bpage->space > TRX_SYS_SPACE - && buf_mark_space_corrupt(bpage)) { - ib_logf(IB_LOG_LEVEL_INFO, - "Simulated page corruption"); - return(true); - } - goto page_not_corrupt; - ;); -corrupt: + /* From version 3.23.38 up we store the page checksum + to the 4 first bytes of the page end lsn field */ + + if (buf_page_is_corrupted(true, frame, + buf_page_get_zip_size(bpage))) { + + /* Not a real corruption if it was triggered by + error injection */ + DBUG_EXECUTE_IF("buf_page_is_corrupt_failure", + if (bpage->space > TRX_SYS_SPACE + && buf_mark_space_corrupt(bpage)) { + ib_logf(IB_LOG_LEVEL_INFO, + "Simulated page corruption"); + return(true); + } + goto page_not_corrupt; + ;); +database_corrupted: - bool corrupted = buf_page_check_corrupt(bpage); + bool corrupted = buf_page_check_corrupt(bpage); - if (corrupted) { - fil_system_enter(); - space = fil_space_get_by_id(bpage->space); - fil_system_exit(); - ib_logf(IB_LOG_LEVEL_ERROR, - "Database page corruption on disk" - " or a failed"); - ib_logf(IB_LOG_LEVEL_ERROR, - "Space %u file %s read of page %u.", - bpage->space, - space ? space->name : "NULL", - bpage->offset); - ib_logf(IB_LOG_LEVEL_ERROR, - "You may have to recover" - " from a backup."); + if (corrupted) { + fil_system_enter(); + space = fil_space_get_by_id(bpage->space); + fil_system_exit(); + ib_logf(IB_LOG_LEVEL_ERROR, + "Database page corruption on disk" + " or a failed"); + ib_logf(IB_LOG_LEVEL_ERROR, + "Space %u file %s read of page %u.", + bpage->space, + space ? space->name : "NULL", + bpage->offset); + ib_logf(IB_LOG_LEVEL_ERROR, + "You may have to recover" + " from a backup."); - buf_page_print(frame, buf_page_get_zip_size(bpage), - BUF_PAGE_PRINT_NO_CRASH); + buf_page_print(frame, buf_page_get_zip_size(bpage), + BUF_PAGE_PRINT_NO_CRASH); - ib_logf(IB_LOG_LEVEL_ERROR, - "It is also possible that your operating" - "system has corrupted its own file cache."); - ib_logf(IB_LOG_LEVEL_ERROR, - "and rebooting your computer removes the error."); - ib_logf(IB_LOG_LEVEL_ERROR, - "If the corrupt page is an index page you can also try to"); - ib_logf(IB_LOG_LEVEL_ERROR, - "fix the corruption by dumping, dropping, and reimporting"); - ib_logf(IB_LOG_LEVEL_ERROR, - "the corrupt table. You can use CHECK"); - ib_logf(IB_LOG_LEVEL_ERROR, - "TABLE to scan your table for corruption."); - ib_logf(IB_LOG_LEVEL_ERROR, - "See also " - REFMAN "forcing-innodb-recovery.html" - " about forcing recovery."); - } - - if (srv_pass_corrupt_table && bpage->space != 0 - && bpage->space < SRV_LOG_SPACE_FIRST_ID) { - trx_t* trx; - - fprintf(stderr, - "InnoDB: space %u will be treated as corrupt.\n", - bpage->space); - fil_space_set_corrupt(bpage->space); - - trx = innobase_get_trx(); - if (trx && trx->dict_operation_lock_mode == RW_X_LATCH) { - dict_table_set_corrupt_by_space(bpage->space, FALSE); - } else { - dict_table_set_corrupt_by_space(bpage->space, TRUE); + ib_logf(IB_LOG_LEVEL_ERROR, + "It is also possible that your operating" + "system has corrupted its own file cache."); + ib_logf(IB_LOG_LEVEL_ERROR, + "and rebooting your computer removes the error."); + ib_logf(IB_LOG_LEVEL_ERROR, + "If the corrupt page is an index page you can also try to"); + ib_logf(IB_LOG_LEVEL_ERROR, + "fix the corruption by dumping, dropping, and reimporting"); + ib_logf(IB_LOG_LEVEL_ERROR, + "the corrupt table. You can use CHECK"); + ib_logf(IB_LOG_LEVEL_ERROR, + "TABLE to scan your table for corruption."); + ib_logf(IB_LOG_LEVEL_ERROR, + "See also " + REFMAN "forcing-innodb-recovery.html" + " about forcing recovery."); } - bpage->is_corrupt = TRUE; - } - if (srv_force_recovery < SRV_FORCE_IGNORE_CORRUPT) { - /* If page space id is larger than TRX_SYS_SPACE - (0), we will attempt to mark the corresponding - table as corrupted instead of crashing server */ - if (bpage->space > TRX_SYS_SPACE - && buf_mark_space_corrupt(bpage)) { - return(false); - } else { - corrupted = buf_page_check_corrupt(bpage); + if (srv_pass_corrupt_table && bpage->space != 0 + && bpage->space < SRV_LOG_SPACE_FIRST_ID) { + trx_t* trx; - if (corrupted) { - ib_logf(IB_LOG_LEVEL_ERROR, - "Ending processing because of a corrupt database page."); + fprintf(stderr, + "InnoDB: space %u will be treated as corrupt.\n", + bpage->space); + fil_space_set_corrupt(bpage->space); - ut_error; + trx = innobase_get_trx(); + if (trx && trx->dict_operation_lock_mode == RW_X_LATCH) { + dict_table_set_corrupt_by_space(bpage->space, FALSE); + } else { + dict_table_set_corrupt_by_space(bpage->space, TRUE); } + bpage->is_corrupt = TRUE; + } - ib_push_warning(innobase_get_trx(), DB_DECRYPTION_FAILED, - "Table in tablespace %lu encrypted." - "However key management plugin or used key_id %u is not found or" - " used encryption algorithm or method does not match." - " Can't continue opening the table.", - (ulint)bpage->space, bpage->key_version); + if (srv_force_recovery < SRV_FORCE_IGNORE_CORRUPT) { + /* If page space id is larger than TRX_SYS_SPACE + (0), we will attempt to mark the corresponding + table as corrupted instead of crashing server */ + if (bpage->space > TRX_SYS_SPACE + && buf_mark_space_corrupt(bpage)) { + return(false); + } else { + corrupted = buf_page_check_corrupt(bpage); - if (bpage->space > TRX_SYS_SPACE) { if (corrupted) { - buf_mark_space_corrupt(bpage); + ib_logf(IB_LOG_LEVEL_ERROR, + "Ending processing because of a corrupt database page."); + + ut_error; } - } else { - ut_error; + + ib_push_warning(innobase_get_trx(), DB_DECRYPTION_FAILED, + "Table in tablespace %lu encrypted." + "However key management plugin or used key_id %u is not found or" + " used encryption algorithm or method does not match." + " Can't continue opening the table.", + (ulint)bpage->space, bpage->key_version); + + if (bpage->space > TRX_SYS_SPACE) { + if (corrupted) { + buf_mark_space_corrupt(bpage); + } + } else { + ut_error; + } + return(false); } - return(false); } } - } } /**/ DBUG_EXECUTE_IF("buf_page_is_corrupt_failure", @@ -6374,6 +6428,19 @@ buf_page_decrypt_after_read( bool page_compressed_encrypted = fil_page_is_compressed_encrypted(dst_frame); buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); bool success = true; + ulint space_id = mach_read_from_4( + dst_frame + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID); + fil_space_crypt_t* crypt_data = fil_space_get_crypt_data(space_id); + + /* Page is encrypted if encryption information is found from + tablespace and page contains used key_version. This is true + also for pages first compressed and then encrypted. */ + if (!crypt_data || + (crypt_data && + crypt_data->type == CRYPT_SCHEME_UNENCRYPTED && + key_version != 0)) { + key_version = 0; + } /* If page is encrypted read post-encryption checksum */ if (!page_compressed_encrypted && key_version != 0) { |