From f8cacd03a79e56746434f7c12e2ed8dd6a534b8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Wed, 13 May 2015 11:41:22 +0300 Subject: [PATCH] MDEV-8143: InnoDB: Database page corruption on disk or a failed file read Analysis: Problem was that we did create crypt data for encrypted table but this new crypt data was not written to page 0. Instead a default crypt data was written to page 0 at table creation. Fixed by explicitly writing new crypt data to page 0 after successfull table creation. --- ...nodb-page_encryption_log_encryption.result | 16 +++-- .../innodb-page_encryption_log_encryption.opt | 4 +- ...innodb-page_encryption_log_encryption.test | 18 ++++- storage/innobase/buf/buf0buf.cc | 39 +++++++++++ storage/innobase/fil/fil0crypt.cc | 26 ++++--- storage/innobase/fil/fil0fil.cc | 2 +- storage/innobase/handler/ha_innodb.cc | 26 ++++++- storage/innobase/include/fil0crypt.h | 5 +- storage/innobase/include/fil0fil.ic | 66 ++++++++++++++++++ storage/innobase/srv/srv0start.cc | 2 +- storage/xtradb/buf/buf0buf.cc | 39 +++++++++++ storage/xtradb/fil/fil0crypt.cc | 26 ++++--- storage/xtradb/fil/fil0fil.cc | 2 +- storage/xtradb/handler/ha_innodb.cc | 26 ++++++- storage/xtradb/include/fil0crypt.h | 5 +- storage/xtradb/include/fil0fil.ic | 67 +++++++++++++++++++ storage/xtradb/srv/srv0start.cc | 2 +- 17 files changed, 335 insertions(+), 36 deletions(-) diff --git a/mysql-test/suite/encryption/r/innodb-page_encryption_log_encryption.result b/mysql-test/suite/encryption/r/innodb-page_encryption_log_encryption.result index 5a3a46e3620..0318ad50cbb 100644 --- a/mysql-test/suite/encryption/r/innodb-page_encryption_log_encryption.result +++ b/mysql-test/suite/encryption/r/innodb-page_encryption_log_encryption.result @@ -217,11 +217,11 @@ select count(*) from innodb_redundant t1, innodb_normal t2 where t1.c1 = t2.c1 and t1.b = t2.b; count(*) 2000 -SELECT variable_value = 0 FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_num_pages_encrypted'; -variable_value = 0 +SELECT variable_value >= 0 FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_num_pages_encrypted'; +variable_value >= 0 1 -SELECT variable_value = 0 FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_num_pages_decrypted'; -variable_value = 0 +SELECT variable_value >= 0 FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_num_pages_decrypted'; +variable_value >= 0 1 drop procedure innodb_insert_proc; drop table innodb_normal; @@ -229,3 +229,11 @@ drop table innodb_compact; drop table innodb_compressed; drop table innodb_dynamic; drop table innodb_redundant; +CREATE TABLE t1 (pk INT PRIMARY KEY) ENGINE=InnoDB ENCRYPTION_KEY_ID=2 ENCRYPTED=YES; +INSERT INTO t1 VALUES (1),(2); +# Restarting server... +SELECT * FROM t1; +pk +1 +2 +DROP TABLE t1; diff --git a/mysql-test/suite/encryption/t/innodb-page_encryption_log_encryption.opt b/mysql-test/suite/encryption/t/innodb-page_encryption_log_encryption.opt index f14c376c3b9..d09b26a375e 100644 --- a/mysql-test/suite/encryption/t/innodb-page_encryption_log_encryption.opt +++ b/mysql-test/suite/encryption/t/innodb-page_encryption_log_encryption.opt @@ -1 +1,3 @@ ---innodb-encrypt-log +--innodb-encrypt-log=ON +--innodb-encrypt-tables=ON + diff --git a/mysql-test/suite/encryption/t/innodb-page_encryption_log_encryption.test b/mysql-test/suite/encryption/t/innodb-page_encryption_log_encryption.test index fec5f062a71..3cd0cf0d2aa 100644 --- a/mysql-test/suite/encryption/t/innodb-page_encryption_log_encryption.test +++ b/mysql-test/suite/encryption/t/innodb-page_encryption_log_encryption.test @@ -133,9 +133,8 @@ t1.c1 = t2.c1 and t1.b = t2.b; select count(*) from innodb_redundant t1, innodb_normal t2 where t1.c1 = t2.c1 and t1.b = t2.b; -# After alter+restart these should be 0 -SELECT variable_value = 0 FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_num_pages_encrypted'; -SELECT variable_value = 0 FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_num_pages_decrypted'; +SELECT variable_value >= 0 FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_num_pages_encrypted'; +SELECT variable_value >= 0 FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_num_pages_decrypted'; drop procedure innodb_insert_proc; drop table innodb_normal; @@ -144,6 +143,19 @@ drop table innodb_compressed; drop table innodb_dynamic; drop table innodb_redundant; +# +# MDEV-8143: InnoDB: Database page corruption on disk or a failed file read +# +CREATE TABLE t1 (pk INT PRIMARY KEY) ENGINE=InnoDB ENCRYPTION_KEY_ID=2 ENCRYPTED=YES; +INSERT INTO t1 VALUES (1),(2); + +--echo # Restarting server... +--source include/restart_mysqld.inc + +SELECT * FROM t1; + +DROP TABLE t1; + # reset system --disable_query_log EVAL SET GLOBAL innodb_file_per_table = $innodb_file_per_table_orig; diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index 64f40fad1d9..778d4b0f3d8 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -5701,6 +5701,10 @@ buf_page_encrypt_before_write( fil_space_crypt_t* crypt_data = fil_space_get_crypt_data(space_id); bpage->real_size = UNIV_PAGE_SIZE; +#ifdef UNIV_DEBUG + fil_page_type_validate(src_frame); +#endif + if (crypt_data != NULL && crypt_data->encryption == FIL_SPACE_ENCRYPTION_OFF) { /* Encryption is disabled */ return const_cast(src_frame); @@ -5754,6 +5758,11 @@ buf_page_encrypt_before_write( ut_ad(key_version == 0 || key_version >= bpage->key_version); bpage->key_version = key_version; bpage->real_size = page_size; + +#ifdef UNIV_DEBUG + fil_page_type_validate(dst_frame); +#endif + } else { /* First we compress the page content */ ulint out_len = 0; @@ -5775,6 +5784,10 @@ buf_page_encrypt_before_write( bpage->real_size = out_len; +#ifdef UNIV_DEBUG + fil_page_type_validate(tmp); +#endif + /* And then we encrypt the page content */ fil_space_encrypt(bpage->space, bpage->offset, @@ -5784,6 +5797,10 @@ buf_page_encrypt_before_write( dst_frame); } +#ifdef UNIV_DEBUG + fil_page_type_validate(dst_frame); +#endif + // return dst_frame which will be written return dst_frame; } @@ -5822,6 +5839,10 @@ buf_page_decrypt_after_read( /* Find free slot from temporary memory array */ buf_tmp_buffer_t* slot = buf_pool_reserve_tmp_slot(buf_pool, page_compressed); +#ifdef UNIV_DEBUG + fil_page_type_validate(dst_frame); +#endif + fil_decompress_page(slot->comp_buf, dst_frame, size, @@ -5830,6 +5851,10 @@ buf_page_decrypt_after_read( /* Mark this slot as free */ slot->reserved = false; } + +#ifdef UNIV_DEBUG + fil_page_type_validate(dst_frame); +#endif } else { /* the page we read is encrypted */ /* Find free slot from temporary memory array */ @@ -5837,12 +5862,22 @@ buf_page_decrypt_after_read( memcpy(slot->crypt_buf, dst_frame, size); +#ifdef UNIV_DEBUG + fil_page_type_validate(dst_frame); + fil_page_type_validate(slot->crypt_buf); +#endif + /* decrypt from crypt_buf to dst_frame */ fil_space_decrypt(bpage->space, slot->crypt_buf, size, dst_frame); +#ifdef UNIV_DEBUG + fil_page_type_validate(dst_frame); + fil_page_type_validate(slot->crypt_buf); +#endif + /* decompress from dst_frame to comp_buf and then copy to buffer pool */ if (page_compressed) { @@ -5852,6 +5887,10 @@ buf_page_decrypt_after_read( &bpage->write_size); } +#ifdef UNIV_DEBUG + fil_page_type_validate(dst_frame); +#endif + /* Mark this slot as free */ slot->reserved = false; } diff --git a/storage/innobase/fil/fil0crypt.cc b/storage/innobase/fil/fil0crypt.cc index 665e8a99f7d..513bdf594e9 100644 --- a/storage/innobase/fil/fil0crypt.cc +++ b/storage/innobase/fil/fil0crypt.cc @@ -272,8 +272,10 @@ Create a fil_space_crypt_t object @return crypt object */ UNIV_INTERN fil_space_crypt_t* -fil_space_create_crypt_data(uint key_id) -/*=========================*/ +fil_space_create_crypt_data( +/*========================*/ + fil_encryption_t encrypt_mode, /*!< in: encryption mode */ + uint key_id) /*!< in: encryption key id */ { const uint iv_length = CRYPT_SCHEME_1_IV_LEN; const uint sz = sizeof(fil_space_crypt_t) + iv_length; @@ -282,7 +284,8 @@ fil_space_create_crypt_data(uint key_id) memset(crypt_data, 0, sz); - if (!srv_encrypt_tables) { + if (encrypt_mode == FIL_SPACE_ENCRYPTION_OFF || + (!srv_encrypt_tables && encrypt_mode == FIL_SPACE_ENCRYPTION_DEFAULT)) { crypt_data->type = CRYPT_SCHEME_UNENCRYPTED; crypt_data->min_key_version = 0; } else { @@ -515,10 +518,15 @@ fil_space_write_crypt_data( { fil_space_crypt_t* crypt_data = fil_space_get_crypt_data(space); - /* If no crypt data is stored on memory cache for this space - or space is not encrypted and encryption is not enabled, then - do not continue writing crypt data to page 0. */ - if (crypt_data == NULL || !srv_encrypt_tables) { + /* If no crypt data is stored on memory cache for this space, + then do not continue writing crypt data to page 0. */ + if (crypt_data == NULL) { + return; + } + + /* If tablespace encryption is disabled and encryption mode is + DEFAULT, then do not continue writing crypt data to page 0. */ + if (!srv_encrypt_tables && crypt_data->encryption == FIL_SPACE_ENCRYPTION_DEFAULT) { return; } @@ -577,7 +585,7 @@ fil_parse_write_crypt_data( return NULL; } - fil_space_crypt_t* crypt_data = fil_space_create_crypt_data(key_id); + fil_space_crypt_t* crypt_data = fil_space_create_crypt_data(encryption, key_id); crypt_data->page0_offset = offset; crypt_data->min_key_version = min_key_version; crypt_data->encryption = encryption; @@ -1112,7 +1120,7 @@ fil_crypt_start_encrypting_space( * crypt data in page 0 */ /* 1 - create crypt data */ - crypt_data = fil_space_create_crypt_data(FIL_DEFAULT_ENCRYPTION_KEY); + crypt_data = fil_space_create_crypt_data(FIL_SPACE_ENCRYPTION_DEFAULT, FIL_DEFAULT_ENCRYPTION_KEY); if (crypt_data == NULL) { mutex_exit(&fil_crypt_threads_mutex); return pending_op; diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index 0ce2317f956..3ac16a1f647 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -3474,7 +3474,7 @@ fil_create_new_single_table_tablespace( } success = fil_space_create(tablename, space_id, flags, FIL_TABLESPACE, - fil_space_create_crypt_data(FIL_DEFAULT_ENCRYPTION_KEY)); + fil_space_create_crypt_data(FIL_SPACE_ENCRYPTION_DEFAULT, FIL_DEFAULT_ENCRYPTION_KEY)); if (!success || !fil_node_create(path, size, space_id, FALSE)) { err = DB_ERROR; diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index c95c7fc931e..ded1680bfb2 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -11718,12 +11718,12 @@ ha_innobase::create( /* If user has requested that table should be encrypted or table should remain as unencrypted store crypt data */ if (encrypt != FIL_SPACE_ENCRYPTION_DEFAULT) { - ulint maxsize; + ulint maxsize=0; ulint zip_size = fil_space_get_zip_size(innobase_table->space); fil_space_crypt_t* old_crypt_data = fil_space_get_crypt_data(innobase_table->space); fil_space_crypt_t* crypt_data; - crypt_data = fil_space_create_crypt_data(key_id); + crypt_data = fil_space_create_crypt_data(encrypt, key_id); crypt_data->page0_offset = fsp_header_get_crypt_offset(zip_size, &maxsize); crypt_data->encryption = encrypt; @@ -11733,7 +11733,29 @@ ha_innobase::create( crypt_data->iv_length = old_crypt_data->iv_length; } + mtr_t mtr; + mtr_start(&mtr); + /* Get page 0*/ + ulint offset = 0; + buf_block_t* block = buf_page_get_gen(innobase_table->space, + zip_size, + offset, + RW_X_LATCH, + NULL, + BUF_GET, + __FILE__, __LINE__, + &mtr); + + /* Set up new crypt data */ fil_space_set_crypt_data(innobase_table->space, crypt_data); + + /* Compute location to store crypt data */ + byte* frame = buf_block_get_frame(block); + + /* Write crypt data to page 0 */ + fil_space_write_crypt_data(innobase_table->space, frame, crypt_data->page0_offset, maxsize, &mtr); + + mtr_commit(&mtr); } innobase_copy_frm_flags_from_create_info(innobase_table, create_info); diff --git a/storage/innobase/include/fil0crypt.h b/storage/innobase/include/fil0crypt.h index 65c51c75d41..12f0946f28c 100644 --- a/storage/innobase/include/fil0crypt.h +++ b/storage/innobase/include/fil0crypt.h @@ -118,7 +118,10 @@ fil_space_crypt_cleanup(); Create crypt data, i.e data that is used for a single tablespace */ UNIV_INTERN fil_space_crypt_t * -fil_space_create_crypt_data(uint key_id); +fil_space_create_crypt_data( +/*========================*/ + fil_encryption_t encrypt_mode, /*!< in: encryption mode */ + uint key_id); /*!< in: encryption key id */ /********************************************************************* Destroy crypt data */ diff --git a/storage/innobase/include/fil0fil.ic b/storage/innobase/include/fil0fil.ic index b1e65e6dddb..6ec7c1adec8 100644 --- a/storage/innobase/include/fil0fil.ic +++ b/storage/innobase/include/fil0fil.ic @@ -105,4 +105,70 @@ fil_node_get_block_size( return (node->file_block_size); } +#ifdef UNIV_DEBUG +/****************************************************************//** +Validate page type. +@return true if valid, false if not */ +UNIV_INLINE +bool +fil_page_type_validate( + const byte* page) /*!< in: page */ +{ + ulint page_type = mach_read_from_2(page + FIL_PAGE_TYPE); +#ifdef UNIV_ENCRYPTION_EXTRA_DEBUG + uint key_version = mach_read_from_4(page + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION); + bool page_compressed = (page_type == FIL_PAGE_PAGE_COMPRESSED); + ulint space = mach_read_from_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID); + ulint offset = mach_read_from_4(page + FIL_PAGE_OFFSET); + ib_uint64_t lsn = mach_read_from_8(page + FIL_PAGE_LSN); + ulint compressed_len = mach_read_from_2(page + FIL_PAGE_DATA); + fil_system_enter(); + fil_space_t* rspace = fil_space_get_by_id(space); + fil_system_exit(); + + /* Dump out the page info */ + fprintf(stderr, "InnoDB: Space %lu offset %lu name %s page_type %lu page_type_name %s\n" + "InnoDB: key_version %u page_compressed %d lsn %lu compressed_len %lu\n", + space, offset, rspace->name, page_type, fil_get_page_type_name(page_type), + key_version, page_compressed, lsn, compressed_len); + fflush(stderr); +#endif + + /* Validate page type */ + if (!((page_type == FIL_PAGE_PAGE_COMPRESSED || + page_type == FIL_PAGE_INDEX || + page_type == FIL_PAGE_UNDO_LOG || + page_type == FIL_PAGE_INODE || + page_type == FIL_PAGE_IBUF_FREE_LIST || + page_type == FIL_PAGE_TYPE_ALLOCATED || + page_type == FIL_PAGE_IBUF_BITMAP || + page_type == FIL_PAGE_TYPE_SYS || + page_type == FIL_PAGE_TYPE_TRX_SYS || + page_type == FIL_PAGE_TYPE_FSP_HDR || + page_type == FIL_PAGE_TYPE_XDES || + page_type == FIL_PAGE_TYPE_BLOB || + page_type == FIL_PAGE_TYPE_ZBLOB || + page_type == FIL_PAGE_TYPE_COMPRESSED))) { + + ut_ad(page_type == FIL_PAGE_PAGE_COMPRESSED || + page_type == FIL_PAGE_INDEX || + page_type == FIL_PAGE_UNDO_LOG || + page_type == FIL_PAGE_INODE || + page_type == FIL_PAGE_IBUF_FREE_LIST || + page_type == FIL_PAGE_TYPE_ALLOCATED || + page_type == FIL_PAGE_IBUF_BITMAP || + page_type == FIL_PAGE_TYPE_SYS || + page_type == FIL_PAGE_TYPE_TRX_SYS || + page_type == FIL_PAGE_TYPE_FSP_HDR || + page_type == FIL_PAGE_TYPE_XDES || + page_type == FIL_PAGE_TYPE_BLOB || + page_type == FIL_PAGE_TYPE_ZBLOB || + page_type == FIL_PAGE_TYPE_COMPRESSED); + return false; + } + + return true; +} +#endif /* UNIV_DEBUG */ + #endif /* fil0fil_ic */ diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index 9e5fe152f54..5d26af7782e 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -1120,7 +1120,7 @@ check_first_page: *sum_of_new_sizes += srv_data_file_sizes[i]; - crypt_data = fil_space_create_crypt_data(FIL_DEFAULT_ENCRYPTION_KEY); + crypt_data = fil_space_create_crypt_data(FIL_SPACE_ENCRYPTION_DEFAULT, FIL_DEFAULT_ENCRYPTION_KEY); } ret = os_file_close(files[i]); diff --git a/storage/xtradb/buf/buf0buf.cc b/storage/xtradb/buf/buf0buf.cc index dc2b81872ae..e0ed1bc848f 100644 --- a/storage/xtradb/buf/buf0buf.cc +++ b/storage/xtradb/buf/buf0buf.cc @@ -5859,6 +5859,10 @@ buf_page_encrypt_before_write( fil_space_crypt_t* crypt_data = fil_space_get_crypt_data(space_id); bpage->real_size = UNIV_PAGE_SIZE; +#ifdef UNIV_DEBUG + fil_page_type_validate(src_frame); +#endif + if (crypt_data != NULL && crypt_data->encryption == FIL_SPACE_ENCRYPTION_OFF) { /* Encryption is disabled */ return const_cast(src_frame); @@ -5912,6 +5916,11 @@ buf_page_encrypt_before_write( ut_ad(key_version == 0 || key_version >= bpage->key_version); bpage->key_version = key_version; bpage->real_size = page_size; + +#ifdef UNIV_DEBUG + fil_page_type_validate(dst_frame); +#endif + } else { /* First we compress the page content */ ulint out_len = 0; @@ -5933,6 +5942,10 @@ buf_page_encrypt_before_write( bpage->real_size = out_len; +#ifdef UNIV_DEBUG + fil_page_type_validate(tmp); +#endif + /* And then we encrypt the page content */ fil_space_encrypt(bpage->space, bpage->offset, @@ -5942,6 +5955,10 @@ buf_page_encrypt_before_write( dst_frame); } +#ifdef UNIV_DEBUG + fil_page_type_validate(dst_frame); +#endif + // return dst_frame which will be written return dst_frame; } @@ -5977,6 +5994,10 @@ buf_page_decrypt_after_read( /* Find free slot from temporary memory array */ buf_tmp_buffer_t* slot = buf_pool_reserve_tmp_slot(buf_pool, page_compressed); +#ifdef UNIV_DEBUG + fil_page_type_validate(dst_frame); +#endif + fil_decompress_page(slot->comp_buf, dst_frame, size, @@ -5985,22 +6006,40 @@ buf_page_decrypt_after_read( /* Mark this slot as free */ slot->reserved = false; } + +#ifdef UNIV_DEBUG + fil_page_type_validate(dst_frame); +#endif } else { /* Find free slot from temporary memory array */ buf_tmp_buffer_t* slot = buf_pool_reserve_tmp_slot(buf_pool, page_compressed); memcpy(slot->crypt_buf, dst_frame, size); +#ifdef UNIV_DEBUG + fil_page_type_validate(dst_frame); + fil_page_type_validate(slot->crypt_buf); +#endif + /* decrypt from crypt_buf to dst_frame */ fil_space_decrypt(bpage->space, slot->crypt_buf, size, dst_frame); +#ifdef UNIV_DEBUG + fil_page_type_validate(dst_frame); + fil_page_type_validate(slot->crypt_buf); +#endif + if (page_compressed) { fil_decompress_page(slot->comp_buf, dst_frame, size, &bpage->write_size); + +#ifdef UNIV_DEBUG + fil_page_type_validate(dst_frame); +#endif } /* Mark this slot as free */ diff --git a/storage/xtradb/fil/fil0crypt.cc b/storage/xtradb/fil/fil0crypt.cc index 9a18d01fcb6..2d8ac3cef39 100644 --- a/storage/xtradb/fil/fil0crypt.cc +++ b/storage/xtradb/fil/fil0crypt.cc @@ -272,8 +272,10 @@ Create a fil_space_crypt_t object @return crypt object */ UNIV_INTERN fil_space_crypt_t* -fil_space_create_crypt_data(uint key_id) -/*=========================*/ +fil_space_create_crypt_data( +/*========================*/ + fil_encryption_t encrypt_mode, /*!< in: encryption mode */ + uint key_id) /*!< in: encryption key id */ { const uint iv_length = CRYPT_SCHEME_1_IV_LEN; const uint sz = sizeof(fil_space_crypt_t) + iv_length; @@ -282,7 +284,8 @@ fil_space_create_crypt_data(uint key_id) memset(crypt_data, 0, sz); - if (!srv_encrypt_tables) { + if (encrypt_mode == FIL_SPACE_ENCRYPTION_OFF || + (!srv_encrypt_tables && encrypt_mode == FIL_SPACE_ENCRYPTION_DEFAULT)) { crypt_data->type = CRYPT_SCHEME_UNENCRYPTED; crypt_data->min_key_version = 0; } else { @@ -515,10 +518,15 @@ fil_space_write_crypt_data( { fil_space_crypt_t* crypt_data = fil_space_get_crypt_data(space); - /* If no crypt data is stored on memory cache for this space - or space is not encrypted and encryption is not enabled, then - do not continue writing crypt data to page 0. */ - if (crypt_data == NULL || !srv_encrypt_tables) { + /* If no crypt data is stored on memory cache for this space, + then do not continue writing crypt data to page 0. */ + if (crypt_data == NULL) { + return; + } + + /* If tablespace encryption is disabled and encryption mode is + DEFAULT, then do not continue writing crypt data to page 0. */ + if (!srv_encrypt_tables && crypt_data->encryption == FIL_SPACE_ENCRYPTION_DEFAULT) { return; } @@ -577,7 +585,7 @@ fil_parse_write_crypt_data( return NULL; } - fil_space_crypt_t* crypt_data = fil_space_create_crypt_data(key_id); + fil_space_crypt_t* crypt_data = fil_space_create_crypt_data(encryption, key_id); crypt_data->page0_offset = offset; crypt_data->min_key_version = min_key_version; crypt_data->encryption = encryption; @@ -1112,7 +1120,7 @@ fil_crypt_start_encrypting_space( * crypt data in page 0 */ /* 1 - create crypt data */ - crypt_data = fil_space_create_crypt_data(FIL_DEFAULT_ENCRYPTION_KEY); + crypt_data = fil_space_create_crypt_data(FIL_SPACE_ENCRYPTION_DEFAULT, FIL_DEFAULT_ENCRYPTION_KEY); if (crypt_data == NULL) { mutex_exit(&fil_crypt_threads_mutex); return pending_op; diff --git a/storage/xtradb/fil/fil0fil.cc b/storage/xtradb/fil/fil0fil.cc index 24f47923c63..f0f92cb71eb 100644 --- a/storage/xtradb/fil/fil0fil.cc +++ b/storage/xtradb/fil/fil0fil.cc @@ -3508,7 +3508,7 @@ fil_create_new_single_table_tablespace( } success = fil_space_create(tablename, space_id, flags, FIL_TABLESPACE, - fil_space_create_crypt_data(FIL_DEFAULT_ENCRYPTION_KEY)); + fil_space_create_crypt_data(FIL_SPACE_ENCRYPTION_DEFAULT, FIL_DEFAULT_ENCRYPTION_KEY)); if (!success || !fil_node_create(path, size, space_id, FALSE)) { err = DB_ERROR; diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index c0d35671574..7097c72a721 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -12231,12 +12231,12 @@ ha_innobase::create( /* If user has requested that table should be encrypted or table should remain as unencrypted store crypt data */ if (encrypt != FIL_SPACE_ENCRYPTION_DEFAULT) { - ulint maxsize; + ulint maxsize=0; ulint zip_size = fil_space_get_zip_size(innobase_table->space); fil_space_crypt_t* old_crypt_data = fil_space_get_crypt_data(innobase_table->space); fil_space_crypt_t* crypt_data; - crypt_data = fil_space_create_crypt_data(key_id); + crypt_data = fil_space_create_crypt_data(encrypt, key_id); crypt_data->page0_offset = fsp_header_get_crypt_offset(zip_size, &maxsize); crypt_data->encryption = encrypt; @@ -12246,7 +12246,29 @@ ha_innobase::create( crypt_data->iv_length = old_crypt_data->iv_length; } + mtr_t mtr; + mtr_start(&mtr); + /* Get page 0*/ + ulint offset = 0; + buf_block_t* block = buf_page_get_gen(innobase_table->space, + zip_size, + offset, + RW_X_LATCH, + NULL, + BUF_GET, + __FILE__, __LINE__, + &mtr); + + /* Set up new crypt data */ fil_space_set_crypt_data(innobase_table->space, crypt_data); + + /* Compute location to store crypt data */ + byte* frame = buf_block_get_frame(block); + + /* Write crypt data to page 0 */ + fil_space_write_crypt_data(innobase_table->space, frame, crypt_data->page0_offset, maxsize, &mtr); + + mtr_commit(&mtr); } innobase_copy_frm_flags_from_create_info(innobase_table, create_info); diff --git a/storage/xtradb/include/fil0crypt.h b/storage/xtradb/include/fil0crypt.h index 65c51c75d41..12f0946f28c 100644 --- a/storage/xtradb/include/fil0crypt.h +++ b/storage/xtradb/include/fil0crypt.h @@ -118,7 +118,10 @@ fil_space_crypt_cleanup(); Create crypt data, i.e data that is used for a single tablespace */ UNIV_INTERN fil_space_crypt_t * -fil_space_create_crypt_data(uint key_id); +fil_space_create_crypt_data( +/*========================*/ + fil_encryption_t encrypt_mode, /*!< in: encryption mode */ + uint key_id); /*!< in: encryption key id */ /********************************************************************* Destroy crypt data */ diff --git a/storage/xtradb/include/fil0fil.ic b/storage/xtradb/include/fil0fil.ic index b1e65e6dddb..cfb82aba31b 100644 --- a/storage/xtradb/include/fil0fil.ic +++ b/storage/xtradb/include/fil0fil.ic @@ -105,4 +105,71 @@ fil_node_get_block_size( return (node->file_block_size); } +#ifdef UNIV_DEBUG +/****************************************************************//** +Validate page type. +@return true if valid, false if not */ +UNIV_INLINE +bool +fil_page_type_validate( + const byte* page) /*!< in: page */ +{ + ulint page_type = mach_read_from_2(page + FIL_PAGE_TYPE); +#ifdef UNIV_ENCRYPTION_EXTRA_DEBUG + uint key_version = mach_read_from_4(page + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION); + bool page_compressed = (page_type == FIL_PAGE_PAGE_COMPRESSED); + ulint space = mach_read_from_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID); + ulint offset = mach_read_from_4(page + FIL_PAGE_OFFSET); + ib_uint64_t lsn = mach_read_from_8(page + FIL_PAGE_LSN); + ulint compressed_len = mach_read_from_2(page + FIL_PAGE_DATA); + fil_system_enter(); + fil_space_t* rspace = fil_space_get_by_id(space); + fil_system_exit(); + + + /* Dump out the page info */ + fprintf(stderr, "InnoDB: Space %lu offset %lu name %s page_type %lu page_type_name %s\n" + "InnoDB: key_version %u page_compressed %d lsn %lu compressed_len %lu\n", + space, offset, rspace->name, page_type, fil_get_page_type_name(page_type), + key_version, page_compressed, lsn, compressed_len); + fflush(stderr); +#endif + + /* Validate page type */ + if (!((page_type == FIL_PAGE_PAGE_COMPRESSED || + page_type == FIL_PAGE_INDEX || + page_type == FIL_PAGE_UNDO_LOG || + page_type == FIL_PAGE_INODE || + page_type == FIL_PAGE_IBUF_FREE_LIST || + page_type == FIL_PAGE_TYPE_ALLOCATED || + page_type == FIL_PAGE_IBUF_BITMAP || + page_type == FIL_PAGE_TYPE_SYS || + page_type == FIL_PAGE_TYPE_TRX_SYS || + page_type == FIL_PAGE_TYPE_FSP_HDR || + page_type == FIL_PAGE_TYPE_XDES || + page_type == FIL_PAGE_TYPE_BLOB || + page_type == FIL_PAGE_TYPE_ZBLOB || + page_type == FIL_PAGE_TYPE_COMPRESSED))) { + + ut_ad(page_type == FIL_PAGE_PAGE_COMPRESSED || + page_type == FIL_PAGE_INDEX || + page_type == FIL_PAGE_UNDO_LOG || + page_type == FIL_PAGE_INODE || + page_type == FIL_PAGE_IBUF_FREE_LIST || + page_type == FIL_PAGE_TYPE_ALLOCATED || + page_type == FIL_PAGE_IBUF_BITMAP || + page_type == FIL_PAGE_TYPE_SYS || + page_type == FIL_PAGE_TYPE_TRX_SYS || + page_type == FIL_PAGE_TYPE_FSP_HDR || + page_type == FIL_PAGE_TYPE_XDES || + page_type == FIL_PAGE_TYPE_BLOB || + page_type == FIL_PAGE_TYPE_ZBLOB || + page_type == FIL_PAGE_TYPE_COMPRESSED); + return false; + } + + return true; +} +#endif /* UNIV_DEBUG */ + #endif /* fil0fil_ic */ diff --git a/storage/xtradb/srv/srv0start.cc b/storage/xtradb/srv/srv0start.cc index 6045de503ac..a4330d0661f 100644 --- a/storage/xtradb/srv/srv0start.cc +++ b/storage/xtradb/srv/srv0start.cc @@ -1154,7 +1154,7 @@ check_first_page: *sum_of_new_sizes += srv_data_file_sizes[i]; - crypt_data = fil_space_create_crypt_data(FIL_DEFAULT_ENCRYPTION_KEY); + crypt_data = fil_space_create_crypt_data(FIL_SPACE_ENCRYPTION_DEFAULT, FIL_DEFAULT_ENCRYPTION_KEY); } ret = os_file_close(files[i]);