Commit ed0a224b authored by Eugene Kosov's avatar Eugene Kosov

MDEV-26747 improve corruption check for encrypted tables on ALTER IMPORT

fil_space_decrypt(): change signature to return status via dberr_t only.
Also replace impossible condition with an assertion and prove it via
test cases.
parent 8f24f5fe
call mtr.add_suppression("InnoDB: .*: Page 0 at offset 0 looks corrupted");
call mtr.add_suppression("Index for table 'dst' is corrupt; try to repair it");
call mtr.add_suppression("Page for tablespace .* is index page with id .* but that index is not found from configuration file");
CREATE TABLE src (pk INT PRIMARY KEY, value INT) ENGINE=INNODB;
INSERT INTO src VALUES (1, 1), (2, 2), (3, 3);
FLUSH TABLES src FOR EXPORT;
UNLOCK TABLES;
DROP TABLE src;
CREATE TABLE dst (pk INT PRIMARY KEY, value INT) ENGINE=INNODB;
ALTER TABLE dst DISCARD TABLESPACE;
ALTER TABLE dst IMPORT TABLESPACE;
ERROR HY000: Internal error: Cannot reset LSNs in table `test`.`dst` : Data structure corruption
DROP TABLE dst;
[crc32]
innodb-checksum-algorithm=crc32
[none]
innodb-checksum-algorithm=none
[innodb]
innodb-checksum-algorithm=innodb
--source include/have_innodb.inc
--source include/have_example_key_management_plugin.inc
call mtr.add_suppression("InnoDB: .*: Page 0 at offset 0 looks corrupted");
call mtr.add_suppression("Index for table 'dst' is corrupt; try to repair it");
call mtr.add_suppression("Page for tablespace .* is index page with id .* but that index is not found from configuration file");
let MYSQLD_DATADIR = `SELECT @@datadir`;
CREATE TABLE src (pk INT PRIMARY KEY, value INT) ENGINE=INNODB;
INSERT INTO src VALUES (1, 1), (2, 2), (3, 3);
FLUSH TABLES src FOR EXPORT;
--copy_file $MYSQLD_DATADIR/test/src.ibd $MYSQLD_DATADIR/test/tmp.ibd
--copy_file $MYSQLD_DATADIR/test/src.cfg $MYSQLD_DATADIR/test/tmp.cfg
perl;
use strict;
die unless open(FILE, "+<$ENV{MYSQLD_DATADIR}/test/tmp.ibd");
binmode FILE;
die unless seek(FILE, 3 * 16384 + 26, 0);
print FILE pack("N", 0x00000000);
close(FILE);
EOF
UNLOCK TABLES;
DROP TABLE src;
CREATE TABLE dst (pk INT PRIMARY KEY, value INT) ENGINE=INNODB;
ALTER TABLE dst DISCARD TABLESPACE;
--copy_file $MYSQLD_DATADIR/test/tmp.ibd $MYSQLD_DATADIR/test/dst.ibd
--copy_file $MYSQLD_DATADIR/test/tmp.cfg $MYSQLD_DATADIR/test/dst.cfg
--error ER_INTERNAL_ERROR
ALTER TABLE dst IMPORT TABLESPACE;
DROP TABLE dst;
--remove_file $MYSQLD_DATADIR/test/tmp.ibd
--remove_file $MYSQLD_DATADIR/test/tmp.cfg
......@@ -668,16 +668,14 @@ fil_space_encrypt(
@param[in] tmp_frame Temporary buffer
@param[in] page_size Page size
@param[in,out] src_frame Page to decrypt
@param[out] err DB_SUCCESS or DB_DECRYPTION_FAILED
@return true if page decrypted, false if not.*/
@return DB_SUCCESS or error */
UNIV_INTERN
bool
dberr_t
fil_space_decrypt(
fil_space_crypt_t* crypt_data,
byte* tmp_frame,
const page_size_t& page_size,
byte* src_frame,
dberr_t* err)
byte* src_frame)
{
ulint page_type = mach_read_from_2(src_frame+FIL_PAGE_TYPE);
uint key_version = mach_read_from_4(src_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION);
......@@ -686,12 +684,7 @@ fil_space_decrypt(
uint space = mach_read_from_4(src_frame + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
ib_uint64_t lsn = mach_read_from_8(src_frame + FIL_PAGE_LSN);
*err = DB_SUCCESS;
if (key_version == ENCRYPTION_KEY_NOT_ENCRYPTED) {
return false;
}
ut_a(key_version != ENCRYPTION_KEY_NOT_ENCRYPTED);
ut_a(crypt_data != NULL && crypt_data->is_encrypted());
/* read space & lsn */
......@@ -722,8 +715,7 @@ fil_space_decrypt(
if (! ((rc == MY_AES_OK) && ((ulint) dstlen == srclen))) {
if (rc == -1) {
*err = DB_DECRYPTION_FAILED;
return false;
return DB_DECRYPTION_FAILED;
}
ib::fatal() << "Unable to decrypt data-block "
......@@ -748,7 +740,7 @@ fil_space_decrypt(
srv_stats.pages_decrypted.inc();
return true; /* page was decrypted */
return DB_SUCCESS; /* page was decrypted */
}
/**
......@@ -765,27 +757,21 @@ fil_space_decrypt(
byte* tmp_frame,
byte* src_frame)
{
dberr_t err = DB_SUCCESS;
byte* res = NULL;
const page_size_t page_size(space->flags);
ut_ad(space->crypt_data != NULL && space->crypt_data->is_encrypted());
ut_ad(space->n_pending_ios > 0);
bool encrypted = fil_space_decrypt(space->crypt_data, tmp_frame,
page_size, src_frame, &err);
if (err == DB_SUCCESS) {
if (encrypted) {
/* Copy the decrypted page back to page buffer, not
really any other options. */
memcpy(src_frame, tmp_frame, page_size.physical());
}
res = src_frame;
if (DB_SUCCESS != fil_space_decrypt(space->crypt_data, tmp_frame,
page_size, src_frame)) {
return NULL;
}
return res;
/* Copy the decrypted page back to page buffer, not
really any other options. */
memcpy(src_frame, tmp_frame, page_size.physical());
return src_frame;
}
/******************************************************************
......
......@@ -359,16 +359,14 @@ Decrypt a page.
@param[in] tmp_frame Temporary buffer
@param[in] page_size Page size
@param[in,out] src_frame Page to decrypt
@param[out] err DB_SUCCESS or error
@return true if page decrypted, false if not.*/
@return DB_SUCCESS or error */
UNIV_INTERN
bool
dberr_t
fil_space_decrypt(
fil_space_crypt_t* crypt_data,
byte* tmp_frame,
const page_size_t& page_size,
byte* src_frame,
dberr_t* err);
byte* src_frame);
/******************************************************************
Decrypt a page
......
......@@ -3502,9 +3502,12 @@ dberr_t FetchIndexRootPages::run(const fil_iterator_t& iter,
if (!fil_space_verify_crypt_checksum(readptr, get_page_size()))
goto page_corrupted;
if (!fil_space_decrypt(iter.crypt_data, readptr,
get_page_size(), readptr, &err) ||
err != DB_SUCCESS)
if (ENCRYPTION_KEY_NOT_ENCRYPTED ==
mach_read_from_4(readptr + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION))
goto page_corrupted;
if ((err = fil_space_decrypt(iter.crypt_data, readptr,
get_page_size(), readptr)))
goto func_exit;
}
......@@ -3647,7 +3650,6 @@ static dberr_t fil_iterate(
} else if (!mach_read_from_4(
FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION
+ src)) {
not_encrypted:
if (block->page.id.page_no() == 0
&& block->page.zip.data) {
block->page.zip.data = src;
......@@ -3666,18 +3668,13 @@ static dberr_t fil_iterate(
goto page_corrupted;
}
decrypted = fil_space_decrypt(
if ((err = fil_space_decrypt(
iter.crypt_data, dst,
callback.get_page_size(), src, &err);
if (err != DB_SUCCESS) {
callback.get_page_size(), src))) {
goto func_exit;
}
if (!decrypted) {
goto not_encrypted;
}
decrypted = true;
updated = true;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment