1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-07 00:04:31 +03:00

MDEV-8588: Assertion failure in file ha_innodb.cc line 21140 if at least one encrypted table exists and encryption service is not available

Analysis: Problem was that in fil_read_first_page we do find that
    table has encryption information and that encryption service
    or used key_id is not available. But, then we just printed
    fatal error message that causes above assertion.

    Fix: When we open single table tablespace if it has encryption
    information (crypt_data) store this crypt data to the table
    structure. When we open a table and we find out that tablespace
    is not available, check has table a encryption information
    and from there is encryption service or used key_id is not available.
    If it is, add additional warning for SQL-layer.
This commit is contained in:
Jan Lindström
2015-08-31 19:47:14 +03:00
parent e1978234eb
commit 7e916bb86f
44 changed files with 1546 additions and 408 deletions

View File

@@ -1,6 +1,11 @@
call mtr.add_suppression("Plugin 'file_key_management' init function returned error");
call mtr.add_suppression("InnoDB: Database page corruption on disk or a failed.*");
call mtr.add_suppression("Plugin 'file_key_management' registration.*failed");
call mtr.add_suppression("InnoDB: Block in space_id .* in file test/.* encrypted");
call mtr.add_suppression("InnoDB: However key management plugin or used key_id 1 is not found or used encryption algorithm or method does not match.");
call mtr.add_suppression("InnoDB: Marking tablespace as missing. You may drop this table or install correct key management plugin and key file.");
call mtr.add_suppression(".*InnoDB: Cannot open table test/.* from the internal data dictionary of InnoDB though the .frm file for the table exists. See .* for how you can resolve the problem.");
call mtr.add_suppression("InnoDB: .ibd file is missing for table test/.*");
# Start server with keys2.txt
SET GLOBAL innodb_file_format = `Barracuda`;
@@ -33,3 +38,98 @@ Warning 1812 Tablespace is missing for table 'test/t1'
Warning 155 Table test/t1 is encrypted but encryption service or used key_id 2 is not available. Can't continue reading table.
Error 1932 Table 'test.t1' doesn't exist in engine
DROP TABLE t1;
# Start server with keys.txt
CREATE TABLE t2 (c VARCHAR(8), id int not null primary key, b int, key(b)) ENGINE=InnoDB ENCRYPTED=YES;
INSERT INTO t2 VALUES ('foobar',1,2);
# Restart server with keys2.txt
SELECT * FROM t2;
Got one of the listed errors
SHOW WARNINGS;
Level Code Message
Warning 155 Table test/t2 in tablespace 7 is encrypted but encryption service or used key_id is not available. Can't continue reading table.
Warning 155 Table test/t2 in tablespace 7 is encrypted but encryption service or used key_id is not available. Can't continue reading table.
Warning 155 Table test/t2 is encrypted but encryption service or used key_id is not available. Can't continue reading table.
Error 1932 Table 'test.t2' doesn't exist in engine
SELECT * FROM t2 where id = 1;
Got one of the listed errors
SHOW WARNINGS;
Level Code Message
Warning 1812 Tablespace is missing for table 'test/t2'
Warning 155 Table test/t2 is encrypted but encryption service or used key_id is not available. Can't continue reading table.
Error 1932 Table 'test.t2' doesn't exist in engine
SELECT * FROM t2 where b = 1;
Got one of the listed errors
SHOW WARNINGS;
Level Code Message
Warning 1812 Tablespace is missing for table 'test/t2'
Warning 155 Table test/t2 is encrypted but encryption service or used key_id is not available. Can't continue reading table.
Error 1932 Table 'test.t2' doesn't exist in engine
INSERT INTO t2 VALUES ('tmp',3,3);
ERROR 42S02: Table 'test.t2' doesn't exist in engine
SHOW WARNINGS;
Level Code Message
Warning 1812 Tablespace is missing for table 'test/t2'
Warning 155 Table test/t2 is encrypted but encryption service or used key_id is not available. Can't continue reading table.
Error 1932 Table 'test.t2' doesn't exist in engine
DELETE FROM t2 where b = 3;
Got one of the listed errors
SHOW WARNINGS;
Level Code Message
Warning 1812 Tablespace is missing for table 'test/t2'
Warning 155 Table test/t2 is encrypted but encryption service or used key_id is not available. Can't continue reading table.
Error 1932 Table 'test.t2' doesn't exist in engine
DELETE FROM t2 where id = 3;
Got one of the listed errors
SHOW WARNINGS;
Level Code Message
Warning 1812 Tablespace is missing for table 'test/t2'
Warning 155 Table test/t2 is encrypted but encryption service or used key_id is not available. Can't continue reading table.
Error 1932 Table 'test.t2' doesn't exist in engine
UPDATE t2 set b = b +1;
Got one of the listed errors
SHOW WARNINGS;
Level Code Message
Warning 1812 Tablespace is missing for table 'test/t2'
Warning 155 Table test/t2 is encrypted but encryption service or used key_id is not available. Can't continue reading table.
Error 1932 Table 'test.t2' doesn't exist in engine
OPTIMIZE TABLE t2;
Table Op Msg_type Msg_text
test.t2 optimize Warning Tablespace is missing for table 'test/t2'
test.t2 optimize Warning Table test/t2 is encrypted but encryption service or used key_id is not available. Can't continue reading table.
test.t2 optimize Error Table 'test.t2' doesn't exist in engine
test.t2 optimize status Operation failed
SHOW WARNINGS;
Level Code Message
ALTER TABLE t2 ADD COLUMN c INT;
ERROR 42S02: Table 'test.t2' doesn't exist in engine
SHOW WARNINGS;
Level Code Message
Warning 1812 Tablespace is missing for table 'test/t2'
Warning 155 Table test/t2 is encrypted but encryption service or used key_id is not available. Can't continue reading table.
Error 1932 Table 'test.t2' doesn't exist in engine
ANALYZE TABLE t2;
Table Op Msg_type Msg_text
test.t2 analyze Warning Tablespace is missing for table 'test/t2'
test.t2 analyze Warning Table test/t2 is encrypted but encryption service or used key_id is not available. Can't continue reading table.
test.t2 analyze Error Table 'test.t2' doesn't exist in engine
test.t2 analyze status Operation failed
SHOW WARNINGS;
Level Code Message
TRUNCATE TABLE t2;
ERROR 42S02: Table 'test.t2' doesn't exist in engine
SHOW WARNINGS;
Level Code Message
Warning 1812 Tablespace is missing for table 'test/t2'
Warning 155 Table test/t2 is encrypted but encryption service or used key_id is not available. Can't continue reading table.
Error 1932 Table 'test.t2' doesn't exist in engine
DROP TABLE t2;
ERROR HY000: Table 't2' is read only
SHOW WARNINGS;
Level Code Message
Error 1036 Table 't2' is read only
# Restart server with keys.txt
DROP TABLE t2;
SHOW WARNINGS;
Level Code Message

View File

@@ -2,10 +2,24 @@
-- source include/have_file_key_management_plugin.inc
# embedded does not support restart
-- source include/not_embedded.inc
-- source include/not_valgrind.inc
# Avoid CrashReporter popup on Mac
-- source include/not_crashrep.inc
-- source include/not_windows.inc
#
# MDEV-8588: Assertion failure in file ha_innodb.cc line 21140 if at least one encrypted
# table exists and encryption service is not available.
#
call mtr.add_suppression("Plugin 'file_key_management' init function returned error");
call mtr.add_suppression("InnoDB: Database page corruption on disk or a failed.*");
call mtr.add_suppression("Plugin 'file_key_management' registration.*failed");
call mtr.add_suppression("InnoDB: Block in space_id .* in file test/.* encrypted");
call mtr.add_suppression("InnoDB: However key management plugin or used key_id 1 is not found or used encryption algorithm or method does not match.");
call mtr.add_suppression("InnoDB: Marking tablespace as missing. You may drop this table or install correct key management plugin and key file.");
call mtr.add_suppression(".*InnoDB: Cannot open table test/.* from the internal data dictionary of InnoDB though the .frm file for the table exists. See .* for how you can resolve the problem.");
call mtr.add_suppression("InnoDB: .ibd file is missing for table test/.*");
--echo
--echo # Start server with keys2.txt
@@ -44,3 +58,63 @@ SHOW WARNINGS;
-- let $restart_parameters=--file-key-management-filename=$MYSQL_TEST_DIR/std_data/keysbad3.txt
-- source include/restart_mysqld.inc
DROP TABLE t1;
#
# MDEV-8591: Database page corruption on disk or a failed space, Assertion failure in file buf0buf.cc
# line 2856 on querying a table using wrong default encryption key
#
--echo # Start server with keys.txt
-- let $restart_parameters=--file-key-management-filename=$MYSQL_TEST_DIR/std_data/keys.txt
-- source include/restart_mysqld.inc
CREATE TABLE t2 (c VARCHAR(8), id int not null primary key, b int, key(b)) ENGINE=InnoDB ENCRYPTED=YES;
INSERT INTO t2 VALUES ('foobar',1,2);
--echo
--echo # Restart server with keys2.txt
-- let $restart_parameters=--file-key-management-filename=$MYSQL_TEST_DIR/std_data/keys2.txt
-- source include/restart_mysqld.inc
--error 1932,1712
SELECT * FROM t2;
SHOW WARNINGS;
--error 1932,1712
SELECT * FROM t2 where id = 1;
SHOW WARNINGS;
--error 1932,1712
SELECT * FROM t2 where b = 1;
SHOW WARNINGS;
--error 1932
INSERT INTO t2 VALUES ('tmp',3,3);
SHOW WARNINGS;
--error 1932,1712
DELETE FROM t2 where b = 3;
SHOW WARNINGS;
--error 1932,1712
DELETE FROM t2 where id = 3;
SHOW WARNINGS;
--error 1932,1712
UPDATE t2 set b = b +1;
SHOW WARNINGS;
OPTIMIZE TABLE t2;
SHOW WARNINGS;
--error 1932
ALTER TABLE t2 ADD COLUMN c INT;
SHOW WARNINGS;
ANALYZE TABLE t2;
SHOW WARNINGS;
--error 1932
TRUNCATE TABLE t2;
SHOW WARNINGS;
--error 1036
DROP TABLE t2;
SHOW WARNINGS;
--echo
--echo # Restart server with keys.txt
-- let $restart_parameters=--file-key-management-filename=$MYSQL_TEST_DIR/std_data/keys.txt
-- source include/restart_mysqld.inc
DROP TABLE t2;
SHOW WARNINGS;

View File

@@ -2,6 +2,7 @@
Copyright (c) 1994, 2013, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2012, Facebook Inc.
Copyright (c) 2014, 2015, MariaDB Corporation
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -734,6 +735,20 @@ btr_root_block_get(
root_page_no = dict_index_get_page(index);
block = btr_block_get(space, zip_size, root_page_no, mode, index, mtr);
if (!block) {
index->table->is_encrypted = TRUE;
index->table->corrupted = FALSE;
ib_push_warning(index->table->thd, DB_ENCRYPTED_DECRYPT_FAILED,
"Table %s in tablespace %lu is encrypted but encryption service or"
" used key_id is not available. "
" Can't continue reading table.",
index->table->name, space);
return NULL;
}
btr_assert_not_corrupted(block, index);
#ifdef UNIV_BTR_DEBUG
if (!dict_index_is_ibuf(index)) {
@@ -759,8 +774,10 @@ btr_root_get(
const dict_index_t* index, /*!< in: index tree */
mtr_t* mtr) /*!< in: mtr */
{
return(buf_block_get_frame(btr_root_block_get(index, RW_X_LATCH,
mtr)));
buf_block_t* root = btr_root_block_get(index, RW_X_LATCH,
mtr);
return(root ? buf_block_get_frame(root) : NULL);
}
/**************************************************************//**
@@ -775,7 +792,7 @@ btr_height_get(
dict_index_t* index, /*!< in: index tree */
mtr_t* mtr) /*!< in/out: mini-transaction */
{
ulint height;
ulint height=0;
buf_block_t* root_block;
ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index),
@@ -786,6 +803,7 @@ btr_height_get(
/* S latches the page */
root_block = btr_root_block_get(index, RW_S_LATCH, mtr);
if (root_block) {
height = btr_page_get_level(buf_block_get_frame(root_block), mtr);
/* Release the S latch on the root page. */
@@ -793,6 +811,7 @@ btr_height_get(
#ifdef UNIV_SYNC_DEBUG
sync_thread_reset_level(&root_block->lock);
#endif /* UNIV_SYNC_DEBUG */
}
return(height);
}
@@ -1240,7 +1259,7 @@ btr_get_size_and_reserved(
{
fseg_header_t* seg_header;
page_t* root;
ulint n;
ulint n=ULINT_UNDEFINED;
ulint dummy;
ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index),
@@ -1254,6 +1273,9 @@ btr_get_size_and_reserved(
}
root = btr_root_get(index, mtr);
*used = 0;
if (root) {
seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF;
@@ -1266,6 +1288,7 @@ btr_get_size_and_reserved(
*used += dummy;
}
}
return(n);
}

View File

@@ -3,6 +3,7 @@
Copyright (c) 1994, 2014, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
Copyright (c) 2012, Facebook Inc.
Copyright (c) 2015, MariaDB Corporation.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
@@ -347,7 +348,7 @@ search tuple should be performed in the B-tree. InnoDB does an insert
immediately after the cursor. Thus, the cursor may end up on a user record,
or on a page infimum record. */
UNIV_INTERN
void
dberr_t
btr_cur_search_to_nth_level(
/*========================*/
dict_index_t* index, /*!< in: index */
@@ -397,6 +398,7 @@ btr_cur_search_to_nth_level(
page_cur_t* page_cursor;
btr_op_t btr_op;
ulint root_height = 0; /* remove warning */
dberr_t err = DB_SUCCESS;
#ifdef BTR_CUR_ADAPT
btr_search_t* info;
@@ -513,7 +515,7 @@ btr_cur_search_to_nth_level(
|| mode != PAGE_CUR_LE);
btr_cur_n_sea++;
return;
return err;
}
# endif /* BTR_CUR_HASH_ADAPT */
#endif /* BTR_CUR_ADAPT */
@@ -609,7 +611,21 @@ search_loop:
retry_page_get:
block = buf_page_get_gen(
space, zip_size, page_no, rw_latch, guess, buf_mode,
file, line, mtr);
file, line, mtr, &err);
if (err != DB_SUCCESS) {
if (err == DB_ENCRYPTED_DECRYPT_FAILED) {
ib_push_warning((void *)NULL,
DB_ENCRYPTED_DECRYPT_FAILED,
"Table %s is encrypted but encryption service or"
" used key_id is not available. "
" Can't continue reading table.",
index->table->name);
index->table->is_encrypted = true;
}
goto func_exit;
}
if (block == NULL) {
/* This must be a search to perform an insert/delete
@@ -822,12 +838,14 @@ func_exit:
rw_lock_s_lock(&btr_search_latch);
}
return err;
}
/*****************************************************************//**
Opens a cursor at either end of an index. */
UNIV_INTERN
void
dberr_t
btr_cur_open_at_index_side_func(
/*============================*/
bool from_left, /*!< in: true if open to the low end,
@@ -853,6 +871,8 @@ btr_cur_open_at_index_side_func(
mem_heap_t* heap = NULL;
ulint offsets_[REC_OFFS_NORMAL_SIZE];
ulint* offsets = offsets_;
dberr_t err = DB_SUCCESS;
rec_offs_init(offsets_);
estimate = latch_mode & BTR_ESTIMATE;
@@ -890,11 +910,26 @@ btr_cur_open_at_index_side_func(
height = ULINT_UNDEFINED;
for (;;) {
buf_block_t* block;
page_t* page;
buf_block_t* block=NULL;
page_t* page=NULL;
block = buf_page_get_gen(space, zip_size, page_no,
RW_NO_LATCH, NULL, BUF_GET,
file, line, mtr);
file, line, mtr, &err);
if (err != DB_SUCCESS) {
if (err == DB_ENCRYPTED_DECRYPT_FAILED) {
ib_push_warning((void *)NULL,
DB_ENCRYPTED_DECRYPT_FAILED,
"Table %s is encrypted but encryption service or"
" used key_id is not available. "
" Can't continue reading table.",
index->table->name);
index->table->is_encrypted = true;
}
goto exit_loop;
}
page = buf_block_get_frame(block);
ut_ad(fil_page_get_type(page) == FIL_PAGE_INDEX);
ut_ad(index->id == btr_page_get_index_id(page));
@@ -979,9 +1014,12 @@ btr_cur_open_at_index_side_func(
page_no = btr_node_ptr_get_child_page_no(node_ptr, offsets);
}
exit_loop:
if (heap) {
mem_heap_free(heap);
}
return err;
}
/**********************************************************************//**
@@ -1029,10 +1067,25 @@ btr_cur_open_at_rnd_pos_func(
for (;;) {
buf_block_t* block;
page_t* page;
dberr_t err=DB_SUCCESS;
block = buf_page_get_gen(space, zip_size, page_no,
RW_NO_LATCH, NULL, BUF_GET,
file, line, mtr);
file, line, mtr, &err);
if (err != DB_SUCCESS) {
if (err == DB_ENCRYPTED_DECRYPT_FAILED) {
ib_push_warning((void *)NULL,
DB_ENCRYPTED_DECRYPT_FAILED,
"Table %s is encrypted but encryption service or"
" used key_id is not available. "
" Can't continue reading table.",
index->table->name);
index->table->is_encrypted = true;
}
goto exit_loop;
}
page = buf_block_get_frame(block);
ut_ad(fil_page_get_type(page) == FIL_PAGE_INDEX);
ut_ad(index->id == btr_page_get_index_id(page));
@@ -1066,6 +1119,7 @@ btr_cur_open_at_rnd_pos_func(
page_no = btr_node_ptr_get_child_page_no(node_ptr, offsets);
}
exit_loop:
if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
@@ -3562,6 +3616,7 @@ btr_estimate_n_rows_in_range_on_level(
mtr_t mtr;
page_t* page;
buf_block_t* block;
dberr_t err=DB_SUCCESS;
mtr_start(&mtr);
@@ -3572,7 +3627,23 @@ btr_estimate_n_rows_in_range_on_level(
silence a debug assertion about this. */
block = buf_page_get_gen(space, zip_size, page_no, RW_S_LATCH,
NULL, BUF_GET_POSSIBLY_FREED,
__FILE__, __LINE__, &mtr);
__FILE__, __LINE__, &mtr, &err);
if (err != DB_SUCCESS) {
if (err == DB_ENCRYPTED_DECRYPT_FAILED) {
ib_push_warning((void *)NULL,
DB_ENCRYPTED_DECRYPT_FAILED,
"Table %s is encrypted but encryption service or"
" used key_id is not available. "
" Can't continue reading table.",
index->table->name);
index->table->is_encrypted = true;
}
mtr_commit(&mtr);
goto inexact;
}
page = buf_block_get_frame(block);

View File

@@ -56,6 +56,7 @@ Created 11/5/1995 Heikki Tuuri
#include "srv0mon.h"
#include "buf0checksum.h"
#include "fil0pagecompress.h"
#include "ha_prototypes.h"
#include "ut0byte.h"
#include <new>
@@ -312,6 +313,18 @@ on the io_type */
? (counter##_READ) \
: (counter##_WRITTEN))
/********************************************************************//**
Check if page is maybe compressed, encrypted or both when we encounter
corrupted page. Note that we can't be 100% sure if page is corrupted
or decrypt/decompress just failed.
*/
static
ibool
buf_page_check_corrupt(
/*===================*/
buf_page_t* bpage); /*!< in/out: buffer page read from
disk */
/********************************************************************//**
Gets the smallest oldest_modification lsn for any page in the pool. Returns
zero if all modified pages have been flushed to disk.
@@ -1052,6 +1065,9 @@ buf_block_init(
block->page.key_version = 0;
block->page.page_encrypted = false;
block->page.page_compressed = false;
block->page.encrypted = false;
block->page.stored_checksum = BUF_NO_CHECKSUM_MAGIC;
block->page.calculated_checksum = BUF_NO_CHECKSUM_MAGIC;
block->page.real_size = 0;
block->page.write_size = 0;
block->modify_clock = 0;
@@ -2243,7 +2259,7 @@ lookup:
/* Page not in buf_pool: needs to be read from file */
ut_ad(!hash_lock);
buf_read_page(space, zip_size, offset);
buf_read_page(space, zip_size, offset, NULL);
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
ut_a(++buf_dbg_counter % 5771 || buf_validate());
@@ -2718,7 +2734,8 @@ buf_page_get_gen(
BUF_GET_IF_IN_POOL_OR_WATCH */
const char* file, /*!< in: file name */
ulint line, /*!< in: line where called */
mtr_t* mtr) /*!< in: mini-transaction */
mtr_t* mtr, /*!< in: mini-transaction */
dberr_t* err) /*!< out: error code */
{
buf_block_t* block;
ulint fold;
@@ -2735,6 +2752,11 @@ buf_page_get_gen(
ut_ad((rw_latch == RW_S_LATCH)
|| (rw_latch == RW_X_LATCH)
|| (rw_latch == RW_NO_LATCH));
if (err) {
*err = DB_SUCCESS;
}
#ifdef UNIV_DEBUG
switch (mode) {
case BUF_GET_NO_LATCH:
@@ -2795,6 +2817,8 @@ loop:
}
if (block == NULL) {
buf_page_t* bpage=NULL;
/* Page not in buf_pool: needs to be read from file */
if (mode == BUF_GET_IF_IN_POOL_OR_WATCH) {
@@ -2827,19 +2851,47 @@ loop:
return(NULL);
}
if (buf_read_page(space, zip_size, offset)) {
if (buf_read_page(space, zip_size, offset, &bpage)) {
buf_read_ahead_random(space, zip_size, offset,
ibuf_inside(mtr));
retries = 0;
} else if (retries < BUF_PAGE_READ_MAX_RETRIES) {
++retries;
bool corrupted = true;
if (bpage) {
corrupted = buf_page_check_corrupt(bpage);
}
/* Do not try again for encrypted pages */
if (!corrupted) {
ib_mutex_t* pmutex = buf_page_get_mutex(bpage);
buf_pool_mutex_enter(buf_pool);
mutex_enter(pmutex);
buf_page_set_io_fix(bpage, BUF_IO_NONE);
buf_pool_mutex_exit(buf_pool);
mutex_exit(pmutex);
if (err) {
*err = DB_ENCRYPTED_DECRYPT_FAILED;
}
return (NULL);
}
DBUG_EXECUTE_IF(
"innodb_page_corruption_retries",
retries = BUF_PAGE_READ_MAX_RETRIES;
);
} else {
bool corrupted = true;
if (bpage) {
corrupted = buf_page_check_corrupt(bpage);
}
if (corrupted) {
fprintf(stderr, "InnoDB: Error: Unable"
" to read tablespace %lu page no"
" %lu into the buffer pool after"
@@ -2857,6 +2909,19 @@ loop:
BUF_PAGE_READ_MAX_RETRIES);
ut_error;
} else {
ib_mutex_t* pmutex = buf_page_get_mutex(bpage);
buf_pool_mutex_enter(buf_pool);
mutex_enter(pmutex);
buf_page_set_io_fix(bpage, BUF_IO_NONE);
buf_pool_mutex_exit(buf_pool);
mutex_exit(pmutex);
if (err) {
*err = DB_ENCRYPTED_DECRYPT_FAILED;
}
return (NULL);
}
}
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
@@ -3591,8 +3656,11 @@ buf_page_init_low(
bpage->oldest_modification = 0;
bpage->write_size = 0;
bpage->key_version = 0;
bpage->stored_checksum = BUF_NO_CHECKSUM_MAGIC;
bpage->calculated_checksum = BUF_NO_CHECKSUM_MAGIC;
bpage->page_encrypted = false;
bpage->page_compressed = false;
bpage->encrypted = false;
bpage->real_size = 0;
bpage->slot = NULL;
@@ -4245,6 +4313,7 @@ buf_mark_space_corrupt(
ulint space = bpage->space;
ibool ret = TRUE;
if (!bpage->encrypted) {
/* First unfix and release lock on the bpage */
buf_pool_mutex_enter(buf_pool);
mutex_enter(buf_page_get_mutex(bpage));
@@ -4261,18 +4330,23 @@ buf_mark_space_corrupt(
}
mutex_exit(buf_page_get_mutex(bpage));
}
/* Find the table with specified space id, and mark it corrupted */
if (dict_set_corrupted_by_space(space)) {
if (!bpage->encrypted) {
buf_LRU_free_one_page(bpage);
}
} else {
ret = FALSE;
}
if (!bpage->encrypted) {
ut_ad(buf_pool->n_pend_reads > 0);
buf_pool->n_pend_reads--;
buf_pool_mutex_exit(buf_pool);
}
return(ret);
}
@@ -4283,42 +4357,77 @@ corrupted page. Note that we can't be 100% sure if page is corrupted
or decrypt/decompress just failed.
*/
static
void
ibool
buf_page_check_corrupt(
/*===================*/
const buf_page_t* bpage) /*!< in/out: buffer page read from disk */
buf_page_t* bpage) /*!< in/out: buffer page read from disk */
{
ulint zip_size = buf_page_get_zip_size(bpage);
byte* dst_frame = (zip_size) ? bpage->zip.data :
((buf_block_t*) bpage)->frame;
unsigned key_version = bpage->key_version;
bool page_compressed = bpage->page_encrypted;
ulint stored_checksum = bpage->stored_checksum;
ulint calculated_checksum = bpage->stored_checksum;
bool page_compressed_encrypted = bpage->page_compressed;
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);
fil_space_t* space = fil_space_found_by_id(space_id);
bool corrupted = true;
if (key_version != 0 || page_compressed_encrypted) {
bpage->encrypted = true;
}
if (key_version != 0 ||
(crypt_data && crypt_data->type != CRYPT_SCHEME_UNENCRYPTED) ||
page_compressed || page_compressed_encrypted) {
/* Page is really corrupted if post encryption stored
checksum does not match calculated checksum after page was
read. For pages compressed and then encrypted, there is no
checksum. */
corrupted = (!page_compressed_encrypted && stored_checksum != calculated_checksum);
if (corrupted) {
ib_logf(IB_LOG_LEVEL_ERROR,
"Maybe corruption: Block space_id %lu in file %s maybe corrupted.",
"%s: Block in space_id %lu in file %s corrupted.",
page_compressed_encrypted ? "Maybe corruption" : "Corruption",
space_id, space ? space->name : "NULL");
ib_logf(IB_LOG_LEVEL_ERROR,
"Page based on contents %s encrypted.",
(key_version == 0 && page_compressed_encrypted == false) ? "not" : "maybe");
if (stored_checksum != BUF_NO_CHECKSUM_MAGIC || calculated_checksum != BUF_NO_CHECKSUM_MAGIC) {
ib_logf(IB_LOG_LEVEL_ERROR,
"Page stored checksum %lu but calculated checksum %lu.",
stored_checksum, calculated_checksum);
}
ib_logf(IB_LOG_LEVEL_ERROR,
"Reason could be that key_version %u in page "
"or in crypt_data %p could not be found.",
key_version, crypt_data);
ib_logf(IB_LOG_LEVEL_ERROR,
"Reason could be also that key management plugin is not found or"
"used encryption algorithm or method does not match.");
" used encryption algorithm or method does not match.");
ib_logf(IB_LOG_LEVEL_ERROR,
"Based on page page compressed %d, compressed and encrypted %d.",
page_compressed, page_compressed_encrypted);
} else {
ib_logf(IB_LOG_LEVEL_ERROR,
"Block in space_id %lu in file %s encrypted.",
space_id, space ? space->name : "NULL");
ib_logf(IB_LOG_LEVEL_ERROR,
"However key management plugin or used key_id %u is not found or"
" used encryption algorithm or method does not match.",
key_version);
ib_logf(IB_LOG_LEVEL_ERROR,
"Marking tablespace as missing. You may drop this table or"
" install correct key management plugin and key file.");
}
}
return corrupted;
}
/********************************************************************//**
@@ -4437,10 +4546,12 @@ buf_page_io_complete(
goto page_not_corrupt;
;);
corrupt:
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");
@@ -4453,7 +4564,6 @@ corrupt:
"You may have to recover"
" from a backup.");
buf_page_check_corrupt(bpage);
buf_page_print(frame, buf_page_get_zip_size(bpage),
BUF_PAGE_PRINT_NO_CRASH);
@@ -4475,6 +4585,7 @@ corrupt:
"See also "
REFMAN "forcing-innodb-recovery.html"
" about forcing recovery.");
}
if (srv_force_recovery < SRV_FORCE_IGNORE_CORRUPT) {
/* If page space id is larger than TRX_SYS_SPACE
@@ -4484,13 +4595,31 @@ corrupt:
&& buf_mark_space_corrupt(bpage)) {
return(false);
} else {
buf_page_check_corrupt(bpage);
corrupted = buf_page_check_corrupt(bpage);
if (corrupted) {
ib_logf(IB_LOG_LEVEL_ERROR,
"Ending processing because of a corrupt database page.");
ut_error;
}
ib_push_warning((void *)NULL, DB_ENCRYPTED_DECRYPT_FAILED,
"Table in tablespace %lu encrypted."
"However key management plugin or used key_id %lu is not found or"
" used encryption algorithm or method does not match."
" Can't continue opening the table.",
bpage->key_version);
if (bpage->space > TRX_SYS_SPACE) {
if (corrupted) {
buf_mark_space_corrupt(bpage);
}
} else {
ut_error;
}
return(false);
}
}
}
@@ -4630,6 +4759,7 @@ buf_all_freed_instance(
const buf_block_t* block = buf_chunk_not_freed(chunk);
if (UNIV_LIKELY_NULL(block)) {
if (block->page.key_version == 0) {
fprintf(stderr,
"Page %lu %lu still fixed or dirty\n",
(ulong) block->page.space,
@@ -4637,6 +4767,7 @@ buf_all_freed_instance(
ut_error;
}
}
}
buf_pool_mutex_exit(buf_pool);
@@ -5950,6 +6081,11 @@ 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);
/* If page is encrypted read post-encryption checksum */
if (!page_compressed_encrypted && key_version != 0) {
bpage->stored_checksum = mach_read_from_4(dst_frame + + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION + 4);
}
ut_ad(bpage->key_version == 0);
if (bpage->offset == 0) {
@@ -5994,6 +6130,13 @@ buf_page_decrypt_after_read(
#ifdef UNIV_DEBUG
fil_page_type_validate(dst_frame);
#endif
/* Calculate checksum before decrypt, this will be
used later to find out if incorrect key was used. */
if (!page_compressed_encrypted) {
bpage->calculated_checksum = fil_crypt_calculate_checksum(zip_size, dst_frame);
}
/* decrypt using crypt_buf to dst_frame */
fil_space_decrypt(bpage->space,
slot->crypt_buf,

View File

@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2015. MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -119,7 +120,8 @@ buf_read_page_low(
treat the tablespace as dropped; this is a timestamp we
use to stop dangling page reads from a tablespace
which we have DISCARDed + IMPORTed back */
ulint offset) /*!< in: page number */
ulint offset, /*!< in: page number */
buf_page_t** rbpage) /*!< out: page */
{
buf_page_t* bpage;
ulint wake_later;
@@ -214,10 +216,17 @@ buf_read_page_low(
/* The i/o is already completed when we arrive from
fil_read */
if (!buf_page_io_complete(bpage)) {
if (rbpage) {
*rbpage = bpage;
}
return(0);
}
}
if (rbpage) {
*rbpage = bpage;
}
return(1);
}
@@ -348,7 +357,7 @@ read_ahead:
&err, false,
ibuf_mode | OS_AIO_SIMULATED_WAKE_LATER,
space, zip_size, FALSE,
tablespace_version, i);
tablespace_version, i, NULL);
if (err == DB_TABLESPACE_DELETED) {
ut_print_timestamp(stderr);
fprintf(stderr,
@@ -398,7 +407,8 @@ buf_read_page(
/*==========*/
ulint space, /*!< in: space id */
ulint zip_size,/*!< in: compressed page size in bytes, or 0 */
ulint offset) /*!< in: page number */
ulint offset, /*!< in: page number */
buf_page_t** bpage) /*!< out: page */
{
ib_int64_t tablespace_version;
ulint count;
@@ -411,7 +421,7 @@ buf_read_page(
count = buf_read_page_low(&err, true, BUF_READ_ANY_PAGE, space,
zip_size, FALSE,
tablespace_version, offset);
tablespace_version, offset, bpage);
srv_stats.buf_pool_reads.add(count);
if (err == DB_TABLESPACE_DELETED) {
ut_print_timestamp(stderr);
@@ -459,7 +469,7 @@ buf_read_page_async(
| OS_AIO_SIMULATED_WAKE_LATER
| BUF_READ_IGNORE_NONEXISTENT_PAGES,
space, zip_size, FALSE,
tablespace_version, offset);
tablespace_version, offset, NULL);
srv_stats.buf_pool_reads.add(count);
/* We do not increment number of I/O operations used for LRU policy
@@ -718,7 +728,7 @@ buf_read_ahead_linear(
count += buf_read_page_low(
&err, false,
ibuf_mode,
space, zip_size, FALSE, tablespace_version, i);
space, zip_size, FALSE, tablespace_version, i, NULL);
if (err == DB_TABLESPACE_DELETED) {
ut_print_timestamp(stderr);
fprintf(stderr,
@@ -808,7 +818,7 @@ buf_read_ibuf_merge_pages(
buf_read_page_low(&err, sync && (i + 1 == n_stored),
BUF_READ_ANY_PAGE, space_ids[i],
zip_size, TRUE, space_versions[i],
page_nos[i]);
page_nos[i], NULL);
if (UNIV_UNLIKELY(err == DB_TABLESPACE_DELETED)) {
tablespace_deleted:
@@ -903,12 +913,12 @@ buf_read_recv_pages(
if ((i + 1 == n_stored) && sync) {
buf_read_page_low(&err, true, BUF_READ_ANY_PAGE, space,
zip_size, TRUE, tablespace_version,
page_nos[i]);
page_nos[i], NULL);
} else {
buf_read_page_low(&err, false, BUF_READ_ANY_PAGE
| OS_AIO_SIMULATED_WAKE_LATER,
space, zip_size, TRUE,
tablespace_version, page_nos[i]);
tablespace_version, page_nos[i], NULL);
}
}

View File

@@ -650,31 +650,8 @@ fil_space_encrypt(
/* handle post encryption checksum */
ib_uint32_t checksum = 0;
srv_checksum_algorithm_t algorithm =
static_cast<srv_checksum_algorithm_t>(srv_checksum_algorithm);
if (zip_size == 0) {
switch (algorithm) {
case SRV_CHECKSUM_ALGORITHM_CRC32:
case SRV_CHECKSUM_ALGORITHM_STRICT_CRC32:
checksum = buf_calc_page_crc32(dst_frame);
break;
case SRV_CHECKSUM_ALGORITHM_INNODB:
case SRV_CHECKSUM_ALGORITHM_STRICT_INNODB:
checksum = (ib_uint32_t) buf_calc_page_new_checksum(
dst_frame);
break;
case SRV_CHECKSUM_ALGORITHM_NONE:
case SRV_CHECKSUM_ALGORITHM_STRICT_NONE:
checksum = BUF_NO_CHECKSUM_MAGIC;
break;
/* no default so the compiler will emit a warning
* if new enum is added and not handled here */
}
} else {
checksum = page_zip_calc_checksum(dst_frame, zip_size,
algorithm);
}
checksum = fil_crypt_calculate_checksum(zip_size, dst_frame);
// store the post-encryption checksum after the key-version
mach_write_to_4(dst_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION + 4, checksum);
@@ -818,6 +795,47 @@ fil_space_decrypt(
return src_frame;
}
/******************************************************************
Calculate post encryption checksum
@return page checksum or BUF_NO_CHECKSUM_MAGIC
not needed. */
UNIV_INTERN
ulint
fil_crypt_calculate_checksum(
/*=========================*/
ulint zip_size, /*!< in: zip_size or 0 */
byte* dst_frame) /*!< in: page where to calculate */
{
ib_uint32_t checksum = 0;
srv_checksum_algorithm_t algorithm =
static_cast<srv_checksum_algorithm_t>(srv_checksum_algorithm);
if (zip_size == 0) {
switch (algorithm) {
case SRV_CHECKSUM_ALGORITHM_CRC32:
case SRV_CHECKSUM_ALGORITHM_STRICT_CRC32:
checksum = buf_calc_page_crc32(dst_frame);
break;
case SRV_CHECKSUM_ALGORITHM_INNODB:
case SRV_CHECKSUM_ALGORITHM_STRICT_INNODB:
checksum = (ib_uint32_t) buf_calc_page_new_checksum(
dst_frame);
break;
case SRV_CHECKSUM_ALGORITHM_NONE:
case SRV_CHECKSUM_ALGORITHM_STRICT_NONE:
checksum = BUF_NO_CHECKSUM_MAGIC;
break;
/* no default so the compiler will emit a warning
* if new enum is added and not handled here */
}
} else {
checksum = page_zip_calc_checksum(dst_frame, zip_size,
algorithm);
}
return checksum;
}
/*********************************************************************
Verify checksum for a page (iff it's encrypted)
NOTE: currently this function can only be run in single threaded mode

View File

@@ -1747,6 +1747,7 @@ convert_error_code_to_mysql(
case DB_TABLESPACE_DELETED:
case DB_TABLE_NOT_FOUND:
case DB_ENCRYPTED_DECRYPT_FAILED:
return(HA_ERR_NO_SUCH_TABLE);
case DB_TABLESPACE_NOT_FOUND:
@@ -5592,7 +5593,14 @@ table_opened:
innobase_copy_frm_flags_from_table_share(ib_table, table->s);
ib_table->thd = (void*)thd;
/* No point to init any statistics if tablespace is still encrypted. */
if (!ib_table->is_encrypted) {
dict_stats_init(ib_table);
} else {
ib_table->stat_initialized = 1;
}
MONITOR_INC(MONITOR_TABLE_OPEN);
@@ -5621,6 +5629,11 @@ table_opened:
file, best to play it safe. */
no_tablespace = true;
} else if (ib_table->is_encrypted) {
/* This means that tablespace was found but we could not
decrypt encrypted page. */
no_tablespace = true;
ib_table->ibd_file_missing = true;
} else {
no_tablespace = false;
}
@@ -5632,9 +5645,9 @@ table_opened:
/* If table has no talespace but it has crypt data, check
is tablespace made unaccessible because encryption service
or used key_id is not available. */
if (ib_table && ib_table->crypt_data) {
if (ib_table) {
fil_space_crypt_t* crypt_data = ib_table->crypt_data;
if ((crypt_data->encryption == FIL_SPACE_ENCRYPTION_ON) ||
if ((crypt_data && crypt_data->encryption == FIL_SPACE_ENCRYPTION_ON) ||
(srv_encrypt_tables &&
crypt_data && crypt_data->encryption == FIL_SPACE_ENCRYPTION_DEFAULT)) {
@@ -5646,6 +5659,13 @@ table_opened:
" Can't continue reading table.",
ib_table->name, crypt_data->key_id);
}
} else if (ib_table->is_encrypted) {
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
HA_ERR_NO_SUCH_TABLE,
"Table %s is encrypted but encryption service or"
" used key_id is not available. "
" Can't continue reading table.",
ib_table->name);
}
}
@@ -20212,3 +20232,59 @@ static void innodb_remember_check_sysvar_funcs()
ut_ad((MYSQL_SYSVAR_NAME(checksum_algorithm).flags & 0x1FF) == PLUGIN_VAR_ENUM);
check_sysvar_enum = MYSQL_SYSVAR_NAME(checksum_algorithm).check;
}
/********************************************************************//**
Helper function to push warnings from InnoDB internals to SQL-layer. */
UNIV_INTERN
void
ib_push_warning(
trx_t* trx, /*!< in: trx */
ulint error, /*!< in: error code to push as warning */
const char *format,/*!< in: warning message */
...)
{
va_list args;
THD *thd = (THD *)trx->mysql_thd;
char *buf;
#define MAX_BUF_SIZE 4*1024
va_start(args, format);
buf = (char *)my_malloc(MAX_BUF_SIZE, MYF(MY_WME));
vsprintf(buf,format, args);
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
convert_error_code_to_mysql((dberr_t)error, 0, thd),
buf);
my_free(buf);
va_end(args);
}
/********************************************************************//**
Helper function to push warnings from InnoDB internals to SQL-layer. */
UNIV_INTERN
void
ib_push_warning(
void* ithd, /*!< in: thd */
ulint error, /*!< in: error code to push as warning */
const char *format,/*!< in: warning message */
...)
{
va_list args;
THD *thd = (THD *)ithd;
char *buf;
#define MAX_BUF_SIZE 4*1024
if (ithd == NULL) {
thd = current_thd;
}
va_start(args, format);
buf = (char *)my_malloc(MAX_BUF_SIZE, MYF(MY_WME));
vsprintf(buf,format, args);
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
convert_error_code_to_mysql((dberr_t)error, 0, thd),
buf);
my_free(buf);
va_end(args);
}

View File

@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1994, 2012, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2015, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -59,12 +60,14 @@ btr_block_get_func(
block = buf_page_get_gen(space, zip_size, page_no, mode,
NULL, BUF_GET, file, line, mtr);
if (block) {
if (mode != RW_NO_LATCH) {
buf_block_dbg_add_level(
block, index != NULL && dict_index_is_ibuf(index)
? SYNC_IBUF_TREE_NODE : SYNC_TREE_NODE);
}
}
return(block);
}

View File

@@ -136,7 +136,7 @@ Note that if mode is PAGE_CUR_LE, which is used in inserts, then
cursor->up_match and cursor->low_match both will have sensible values.
If mode is PAGE_CUR_GE, then up_match will a have a sensible value. */
UNIV_INTERN
void
dberr_t
btr_cur_search_to_nth_level(
/*========================*/
dict_index_t* index, /*!< in: index */
@@ -173,7 +173,7 @@ btr_cur_search_to_nth_level(
/*****************************************************************//**
Opens a cursor at either end of an index. */
UNIV_INTERN
void
dberr_t
btr_cur_open_at_index_side_func(
/*============================*/
bool from_left, /*!< in: true if open to the low end,

View File

@@ -114,7 +114,7 @@ btr_pcur_open_low(
Opens an persistent cursor to an index tree without initializing the
cursor. */
UNIV_INLINE
void
dberr_t
btr_pcur_open_with_no_init_func(
/*============================*/
dict_index_t* index, /*!< in: index */
@@ -143,7 +143,7 @@ btr_pcur_open_with_no_init_func(
/*****************************************************************//**
Opens a persistent cursor at either end of an index. */
UNIV_INLINE
void
dberr_t
btr_pcur_open_at_index_side(
/*========================*/
bool from_left, /*!< in: true if open to the low end,

View File

@@ -447,7 +447,7 @@ btr_pcur_open_low(
Opens an persistent cursor to an index tree without initializing the
cursor. */
UNIV_INLINE
void
dberr_t
btr_pcur_open_with_no_init_func(
/*============================*/
dict_index_t* index, /*!< in: index */
@@ -472,6 +472,7 @@ btr_pcur_open_with_no_init_func(
mtr_t* mtr) /*!< in: mtr */
{
btr_cur_t* btr_cursor;
dberr_t err = DB_SUCCESS;
cursor->latch_mode = latch_mode;
cursor->search_mode = mode;
@@ -480,7 +481,7 @@ btr_pcur_open_with_no_init_func(
btr_cursor = btr_pcur_get_btr_cur(cursor);
btr_cur_search_to_nth_level(index, 0, tuple, mode, latch_mode,
err = btr_cur_search_to_nth_level(index, 0, tuple, mode, latch_mode,
btr_cursor, has_search_latch,
file, line, mtr);
cursor->pos_state = BTR_PCUR_IS_POSITIONED;
@@ -488,12 +489,13 @@ btr_pcur_open_with_no_init_func(
cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
cursor->trx_if_known = NULL;
return err;
}
/*****************************************************************//**
Opens a persistent cursor at either end of an index. */
UNIV_INLINE
void
dberr_t
btr_pcur_open_at_index_side(
/*========================*/
bool from_left, /*!< in: true if open to the low end,
@@ -506,6 +508,8 @@ btr_pcur_open_at_index_side(
(0=leaf) */
mtr_t* mtr) /*!< in/out: mini-transaction */
{
dberr_t err = DB_SUCCESS;
pcur->latch_mode = BTR_LATCH_MODE_WITHOUT_FLAGS(latch_mode);
pcur->search_mode = from_left ? PAGE_CUR_G : PAGE_CUR_L;
@@ -514,13 +518,15 @@ btr_pcur_open_at_index_side(
btr_pcur_init(pcur);
}
btr_cur_open_at_index_side(from_left, index, latch_mode,
err = btr_cur_open_at_index_side(from_left, index, latch_mode,
btr_pcur_get_btr_cur(pcur), level, mtr);
pcur->pos_state = BTR_PCUR_IS_POSITIONED;
pcur->old_stored = BTR_PCUR_OLD_NOT_STORED;
pcur->trx_if_known = NULL;
return (err);
}
/**********************************************************************//**

View File

@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1995, 2014, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2013, 2014, SkySQL Ab. All Rights Reserved.
Copyright (c) 2013, 2015, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -430,7 +430,8 @@ buf_page_get_gen(
BUF_GET_IF_IN_POOL_OR_WATCH */
const char* file, /*!< in: file name */
ulint line, /*!< in: line where called */
mtr_t* mtr); /*!< in: mini-transaction */
mtr_t* mtr, /*!< in: mini-transaction */
dberr_t* err = NULL); /*!< out: error code */
/********************************************************************//**
Initializes a page to the buffer buf_pool. The page is usually not read
from a file even if it cannot be found in the buffer buf_pool. This is one
@@ -1582,9 +1583,14 @@ struct buf_page_t{
operation needed. */
unsigned key_version; /*!< key version for this block */
bool page_encrypted; /*!< page is encrypted */
bool page_encrypted; /*!< page is page encrypted */
bool page_compressed;/*!< page is page compressed */
ulint stored_checksum;/*!< stored page checksum if page
encrypted */
bool encrypted; /*!< page is still encrypted */
ulint calculated_checksum;
/*!< calculated checksum if page
encrypted */
ulint real_size; /*!< Real size of the page
Normal pages == UNIV_PAGE_SIZE
page compressed pages, payload

View File

@@ -663,13 +663,18 @@ buf_block_get_frame(
/*================*/
const buf_block_t* block) /*!< in: pointer to the control block */
{
ut_ad(block);
if (!block) {
return NULL;
}
switch (buf_block_get_state(block)) {
case BUF_BLOCK_POOL_WATCH:
case BUF_BLOCK_ZIP_PAGE:
case BUF_BLOCK_ZIP_DIRTY:
case BUF_BLOCK_NOT_USED:
if (block->page.encrypted) {
goto ok;
}
ut_error;
break;
case BUF_BLOCK_FILE_PAGE:

View File

@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2015, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -41,7 +42,8 @@ buf_read_page(
/*==========*/
ulint space, /*!< in: space id */
ulint zip_size,/*!< in: compressed page size in bytes, or 0 */
ulint offset);/*!< in: page number */
ulint offset, /*!< in: page number */
buf_page_t** bpage);/*!< out: page */
/********************************************************************//**
High-level function which reads a page asynchronously from a file to the
buffer buf_pool if it is not already there. Sets the io_fix flag and sets

View File

@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2014, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2015, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -132,6 +133,11 @@ enum dberr_t {
/*< Too many words in a phrase */
DB_TOO_BIG_FOR_REDO, /* Record length greater than 10%
of redo log */
DB_ENCRYPTED_DECRYPT_FAILED, /* Tablespace encrypted and
decrypt operaton failed because
of missing key management plugin,
or missing or incorrect key or
incorret AES method or algorithm. */
/* The following are partial failure codes */
DB_FAIL = 1000,
DB_OVERFLOW,

View File

@@ -2,7 +2,7 @@
Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2012, Facebook Inc.
Copyright (c) 2013, SkySQL Ab. All Rights Reserved.
Copyright (c) 2013, 2015, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -1017,6 +1017,7 @@ struct dict_table_t{
table_id_t id; /*!< id of the table */
mem_heap_t* heap; /*!< memory heap */
char* name; /*!< table name */
void* thd; /*!< thd */
fil_space_crypt_t *crypt_data; /*!< crypt data if present */
const char* dir_path_of_temp_table;/*!< NULL or the directory path
where a TEMPORARY table that was explicitly
@@ -1330,6 +1331,7 @@ struct dict_table_t{
locks; /*!< list of locks on the table; protected
by lock_sys->mutex */
#endif /* !UNIV_HOTBACKUP */
ibool is_encrypted;
#ifdef UNIV_DEBUG
ulint magic_n;/*!< magic number */

View File

@@ -382,6 +382,17 @@ fil_crypt_set_encrypt_tables(
uint val); /*!< in: New srv_encrypt_tables setting */
/******************************************************************
Calculate post encryption checksum
@return page checksum or BUF_NO_CHECKSUM_MAGIC
not needed. */
UNIV_INTERN
ulint
fil_crypt_calculate_checksum(
/*=========================*/
ulint zip_size, /*!< in: zip_size or 0 */
byte* dst_frame); /*!< in: page where to calculate */
#ifndef UNIV_NONINL
#include "fil0crypt.ic"
#endif

View File

@@ -634,5 +634,13 @@ ib_push_warning(
ulint error, /*!< in: error code to push as warning */
const char *format,/*!< in: warning message */
...);
/********************************************************************//**
Helper function to push warnings from InnoDB internals to SQL-layer. */
UNIV_INTERN
void
ib_push_warning(
void* ithd, /*!< in: thd */
ulint error, /*!< in: error code to push as warning */
const char *format,/*!< in: warning message */
...);
#endif /* HA_INNODB_PROTOTYPES_H */

View File

@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1994, 2013, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2015, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -39,7 +40,10 @@ page_cur_get_page(
page_cur_t* cur) /*!< in: page cursor */
{
ut_ad(cur);
if (cur->rec) {
ut_ad(page_align(cur->rec) == cur->block->frame);
}
return(page_align(cur->rec));
}
@@ -54,7 +58,11 @@ page_cur_get_block(
page_cur_t* cur) /*!< in: page cursor */
{
ut_ad(cur);
if (cur->rec) {
ut_ad(page_align(cur->rec) == cur->block->frame);
}
return(cur->block);
}
@@ -80,7 +88,10 @@ page_cur_get_rec(
page_cur_t* cur) /*!< in: page cursor */
{
ut_ad(cur);
if (cur->rec) {
ut_ad(page_align(cur->rec) == cur->block->frame);
}
return(cur->rec);
}

View File

@@ -2338,7 +2338,7 @@ row_ins_clust_index_entry_low(
{
btr_cur_t cursor;
ulint* offsets = NULL;
dberr_t err;
dberr_t err = DB_SUCCESS;
big_rec_t* big_rec = NULL;
mtr_t mtr;
mem_heap_t* offsets_heap = NULL;
@@ -2361,9 +2361,16 @@ row_ins_clust_index_entry_low(
the function will return in both low_match and up_match of the
cursor sensible values */
btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE, mode,
err = btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE, mode,
&cursor, 0, __FILE__, __LINE__, &mtr);
if (err != DB_SUCCESS) {
index->table->is_encrypted = true;
index->table->ibd_file_missing = true;
mtr_commit(&mtr);
goto func_exit;
}
#ifdef UNIV_DEBUG
{
page_t* page = btr_cur_get_page(&cursor);
@@ -2669,10 +2676,23 @@ row_ins_sec_index_entry_low(
search_mode |= BTR_IGNORE_SEC_UNIQUE;
}
btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE,
err = btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE,
search_mode,
&cursor, 0, __FILE__, __LINE__, &mtr);
if (err != DB_SUCCESS) {
if (err == DB_ENCRYPTED_DECRYPT_FAILED) {
ib_push_warning(trx->mysql_thd,
DB_ENCRYPTED_DECRYPT_FAILED,
"Table %s is encrypted but encryption service or"
" used key_id is not available. "
" Can't continue reading table.",
index->table->name);
index->table->is_encrypted = true;
}
goto func_exit;
}
if (cursor.flag == BTR_CUR_INSERT_TO_IBUF) {
/* The insert was buffered during the search: we are done */
goto func_exit;

View File

@@ -623,6 +623,8 @@ handle_new_error:
case DB_FTS_INVALID_DOCID:
case DB_INTERRUPTED:
case DB_DICT_CHANGED:
case DB_TABLE_NOT_FOUND:
case DB_ENCRYPTED_DECRYPT_FAILED:
if (savept) {
/* Roll back the latest, possibly incomplete insertion
or update */
@@ -1315,7 +1317,13 @@ row_insert_for_mysql(
prebuilt->table->name);
return(DB_TABLESPACE_NOT_FOUND);
} else if (prebuilt->table->is_encrypted) {
ib_push_warning(trx, DB_ENCRYPTED_DECRYPT_FAILED,
"Table %s in tablespace %lu encrypted."
"However key management plugin or used key_id is not found or"
" used encryption algorithm or method does not match.",
prebuilt->table->name, prebuilt->table->space);
return(DB_ENCRYPTED_DECRYPT_FAILED);
} else if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) {
fprintf(stderr,
"InnoDB: Error: trying to free a corrupt\n"
@@ -1710,6 +1718,13 @@ row_update_for_mysql(
"InnoDB: how you can resolve the problem.\n",
prebuilt->table->name);
return(DB_ERROR);
} else if (prebuilt->table->is_encrypted) {
ib_push_warning(trx, DB_ENCRYPTED_DECRYPT_FAILED,
"Table %s in tablespace %lu encrypted."
"However key management plugin or used key_id is not found or"
" used encryption algorithm or method does not match.",
prebuilt->table->name, prebuilt->table->space);
return (DB_TABLE_NOT_FOUND);
}
if (UNIV_UNLIKELY(prebuilt->magic_n != ROW_PREBUILT_ALLOCATED)) {
@@ -3919,6 +3934,19 @@ row_drop_table_for_mysql(
goto funct_exit;
}
/* If table is encrypted and table page encryption failed
mark this table read only. */
if (table->is_encrypted) {
if (table->can_be_evicted) {
dict_table_move_from_lru_to_non_lru(table);
}
dict_table_close(table, TRUE, FALSE);
err = DB_READ_ONLY;
goto funct_exit;
}
/* Turn on this drop bit before we could release the dictionary
latch */
table->to_be_dropped = true;

View File

@@ -2,6 +2,7 @@
Copyright (c) 1997, 2015, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
Copyright (c) 2015, MariaDB Corporation.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
@@ -3717,6 +3718,9 @@ row_search_for_mysql(
return(DB_TABLESPACE_NOT_FOUND);
} else if (prebuilt->table->is_encrypted) {
return(DB_ENCRYPTED_DECRYPT_FAILED);
} else if (!prebuilt->index_usable) {
return(DB_MISSING_HISTORY);
@@ -4143,10 +4147,15 @@ wait_table_again:
} else if (dtuple_get_n_fields(search_tuple) > 0) {
btr_pcur_open_with_no_init(index, search_tuple, mode,
err = btr_pcur_open_with_no_init(index, search_tuple, mode,
BTR_SEARCH_LEAF,
pcur, 0, &mtr);
if (err != DB_SUCCESS) {
rec = NULL;
goto lock_wait_or_error;
}
pcur->trx_if_known = trx;
rec = btr_pcur_get_rec(pcur);
@@ -4179,9 +4188,23 @@ wait_table_again:
}
}
} else if (mode == PAGE_CUR_G || mode == PAGE_CUR_L) {
btr_pcur_open_at_index_side(
err = btr_pcur_open_at_index_side(
mode == PAGE_CUR_G, index, BTR_SEARCH_LEAF,
pcur, false, 0, &mtr);
if (err != DB_SUCCESS) {
if (err == DB_ENCRYPTED_DECRYPT_FAILED) {
ib_push_warning(trx->mysql_thd,
DB_ENCRYPTED_DECRYPT_FAILED,
"Table %s is encrypted but encryption service or"
" used key_id is not available. "
" Can't continue reading table.",
prebuilt->table->name);
index->table->is_encrypted = true;
}
rec = NULL;
goto lock_wait_or_error;
}
}
rec_loop:
@@ -4196,6 +4219,12 @@ rec_loop:
/* PHASE 4: Look for matching records in a loop */
rec = btr_pcur_get_rec(pcur);
if (!rec) {
err = DB_ENCRYPTED_DECRYPT_FAILED;
goto lock_wait_or_error;
}
ut_ad(!!page_rec_is_comp(rec) == comp);
#ifdef UNIV_SEARCH_DEBUG
/*
@@ -5113,7 +5142,9 @@ lock_wait_or_error:
/*-------------------------------------------------------------*/
if (rec) {
btr_pcur_store_position(pcur, &mtr);
}
lock_table_wait:
mtr_commit(&mtr);

View File

@@ -2,6 +2,7 @@
Copyright (c) 1994, 2013, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2012, Facebook Inc.
Copyright (c) 2014, 2015, MariaDB Corporation
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -741,6 +742,19 @@ btr_root_block_get(
block = btr_block_get(space, zip_size, root_page_no, mode, index, mtr);
if (!block) {
index->table->is_encrypted = TRUE;
index->table->corrupted = FALSE;
ib_push_warning(index->table->thd, DB_ENCRYPTED_DECRYPT_FAILED,
"Table %s in tablespace %lu is encrypted but encryption service or"
" used key_id is not available. "
" Can't continue reading table.",
index->table->name, space);
return NULL;
}
SRV_CORRUPT_TABLE_CHECK(block, return(0););
btr_assert_not_corrupted(block, index);
@@ -779,8 +793,10 @@ btr_root_get(
const dict_index_t* index, /*!< in: index tree */
mtr_t* mtr) /*!< in: mtr */
{
return(buf_block_get_frame(btr_root_block_get(index, RW_X_LATCH,
mtr)));
buf_block_t* root = btr_root_block_get(index, RW_X_LATCH,
mtr);
return(root ? buf_block_get_frame(root) : NULL);
}
/**************************************************************//**
@@ -795,7 +811,7 @@ btr_height_get(
dict_index_t* index, /*!< in: index tree */
mtr_t* mtr) /*!< in/out: mini-transaction */
{
ulint height;
ulint height=0;
buf_block_t* root_block;
ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index),
@@ -806,6 +822,8 @@ btr_height_get(
/* S latches the page */
root_block = btr_root_block_get(index, RW_S_LATCH, mtr);
if (root_block) {
height = btr_page_get_level(buf_block_get_frame_fast(root_block), mtr);
/* Release the S latch on the root page. */
@@ -813,6 +831,7 @@ btr_height_get(
#ifdef UNIV_SYNC_DEBUG
sync_thread_reset_level(&root_block->lock);
#endif /* UNIV_SYNC_DEBUG */
}
return(height);
}
@@ -1260,7 +1279,7 @@ btr_get_size_and_reserved(
{
fseg_header_t* seg_header;
page_t* root;
ulint n;
ulint n=ULINT_UNDEFINED;
ulint dummy;
ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index),
@@ -1274,6 +1293,9 @@ btr_get_size_and_reserved(
}
root = btr_root_get(index, mtr);
*used = 0;
if (root) {
seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF;
@@ -1286,6 +1308,7 @@ btr_get_size_and_reserved(
*used += dummy;
}
}
return(n);
}

View File

@@ -3,6 +3,7 @@
Copyright (c) 1994, 2014, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
Copyright (c) 2012, Facebook Inc.
Copyright (c) 2015, MariaDB Corporation.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
@@ -386,7 +387,7 @@ search tuple should be performed in the B-tree. InnoDB does an insert
immediately after the cursor. Thus, the cursor may end up on a user record,
or on a page infimum record. */
UNIV_INTERN
void
dberr_t
btr_cur_search_to_nth_level(
/*========================*/
dict_index_t* index, /*!< in: index */
@@ -436,6 +437,7 @@ btr_cur_search_to_nth_level(
page_cur_t* page_cursor;
btr_op_t btr_op;
ulint root_height = 0; /* remove warning */
dberr_t err = DB_SUCCESS;
#ifdef BTR_CUR_ADAPT
btr_search_t* info;
@@ -553,7 +555,7 @@ btr_cur_search_to_nth_level(
|| mode != PAGE_CUR_LE);
btr_cur_n_sea++;
return;
return err;
}
# endif /* BTR_CUR_HASH_ADAPT */
#endif /* BTR_CUR_ADAPT */
@@ -649,7 +651,21 @@ search_loop:
retry_page_get:
block = buf_page_get_gen(
space, zip_size, page_no, rw_latch, guess, buf_mode,
file, line, mtr);
file, line, mtr, &err);
if (err != DB_SUCCESS) {
if (err == DB_ENCRYPTED_DECRYPT_FAILED) {
ib_push_warning((void *)NULL,
DB_ENCRYPTED_DECRYPT_FAILED,
"Table %s is encrypted but encryption service or"
" used key_id is not available. "
" Can't continue reading table.",
index->table->name);
index->table->is_encrypted = true;
}
goto func_exit;
}
if (block == NULL) {
SRV_CORRUPT_TABLE_CHECK(buf_mode == BUF_GET_IF_IN_POOL ||
@@ -889,12 +905,14 @@ func_exit:
rw_lock_s_lock(btr_search_get_latch(cursor->index));
}
return err;
}
/*****************************************************************//**
Opens a cursor at either end of an index. */
UNIV_INTERN
void
dberr_t
btr_cur_open_at_index_side_func(
/*============================*/
bool from_left, /*!< in: true if open to the low end,
@@ -920,6 +938,8 @@ btr_cur_open_at_index_side_func(
mem_heap_t* heap = NULL;
ulint offsets_[REC_OFFS_NORMAL_SIZE];
ulint* offsets = offsets_;
dberr_t err = DB_SUCCESS;
rec_offs_init(offsets_);
estimate = latch_mode & BTR_ESTIMATE;
@@ -957,11 +977,26 @@ btr_cur_open_at_index_side_func(
height = ULINT_UNDEFINED;
for (;;) {
buf_block_t* block;
page_t* page;
buf_block_t* block=NULL;
page_t* page=NULL;
block = buf_page_get_gen(space, zip_size, page_no,
RW_NO_LATCH, NULL, BUF_GET,
file, line, mtr);
file, line, mtr, &err);
if (err != DB_SUCCESS) {
if (err == DB_ENCRYPTED_DECRYPT_FAILED) {
ib_push_warning((void *)NULL,
DB_ENCRYPTED_DECRYPT_FAILED,
"Table %s is encrypted but encryption service or"
" used key_id is not available. "
" Can't continue reading table.",
index->table->name);
index->table->is_encrypted = true;
}
goto exit_loop;
}
page = buf_block_get_frame(block);
SRV_CORRUPT_TABLE_CHECK(page,
@@ -1066,6 +1101,8 @@ exit_loop:
if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
return err;
}
/**********************************************************************//**
@@ -1113,10 +1150,25 @@ btr_cur_open_at_rnd_pos_func(
for (;;) {
buf_block_t* block;
page_t* page;
dberr_t err=DB_SUCCESS;
block = buf_page_get_gen(space, zip_size, page_no,
RW_NO_LATCH, NULL, BUF_GET,
file, line, mtr);
file, line, mtr, &err);
if (err != DB_SUCCESS) {
if (err == DB_ENCRYPTED_DECRYPT_FAILED) {
ib_push_warning((void *)NULL,
DB_ENCRYPTED_DECRYPT_FAILED,
"Table %s is encrypted but encryption service or"
" used key_id is not available. "
" Can't continue reading table.",
index->table->name);
index->table->is_encrypted = true;
}
goto exit_loop;
}
page = buf_block_get_frame(block);
SRV_CORRUPT_TABLE_CHECK(page,
@@ -3749,6 +3801,7 @@ btr_estimate_n_rows_in_range_on_level(
mtr_t mtr;
page_t* page;
buf_block_t* block;
dberr_t err=DB_SUCCESS;
mtr_start(&mtr);
@@ -3759,7 +3812,23 @@ btr_estimate_n_rows_in_range_on_level(
silence a debug assertion about this. */
block = buf_page_get_gen(space, zip_size, page_no, RW_S_LATCH,
NULL, BUF_GET_POSSIBLY_FREED,
__FILE__, __LINE__, &mtr);
__FILE__, __LINE__, &mtr, &err);
if (err != DB_SUCCESS) {
if (err == DB_ENCRYPTED_DECRYPT_FAILED) {
ib_push_warning((void *)NULL,
DB_ENCRYPTED_DECRYPT_FAILED,
"Table %s is encrypted but encryption service or"
" used key_id is not available. "
" Can't continue reading table.",
index->table->name);
index->table->is_encrypted = true;
}
mtr_commit(&mtr);
goto inexact;
}
page = buf_block_get_frame(block);

View File

@@ -59,11 +59,24 @@ Created 11/5/1995 Heikki Tuuri
#include "srv0start.h"
#include "ut0byte.h"
#include "fil0pagecompress.h"
#include "ha_prototypes.h"
/* prototypes for new functions added to ha_innodb.cc */
trx_t* innobase_get_trx();
/********************************************************************//**
Check if page is maybe compressed, encrypted or both when we encounter
corrupted page. Note that we can't be 100% sure if page is corrupted
or decrypt/decompress just failed.
*/
static
ibool
buf_page_check_corrupt(
/*===================*/
buf_page_t* bpage); /*!< in/out: buffer page read from
disk */
static inline
void
_increment_page_get_statistics(buf_block_t* block, trx_t* trx)
@@ -1128,6 +1141,9 @@ buf_block_init(
block->page.key_version = 0;
block->page.page_encrypted = false;
block->page.page_compressed = false;
block->page.encrypted = false;
block->page.stored_checksum = BUF_NO_CHECKSUM_MAGIC;
block->page.calculated_checksum = BUF_NO_CHECKSUM_MAGIC;
block->page.real_size = 0;
block->page.write_size = 0;
block->modify_clock = 0;
@@ -2234,7 +2250,7 @@ lookup:
/* Page not in buf_pool: needs to be read from file */
ut_ad(!hash_lock);
buf_read_page(space, zip_size, offset, trx);
buf_read_page(space, zip_size, offset, trx, NULL);
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
ut_a(++buf_dbg_counter % 5771 || buf_validate());
@@ -2753,7 +2769,8 @@ buf_page_get_gen(
BUF_GET_IF_IN_POOL_OR_WATCH */
const char* file, /*!< in: file name */
ulint line, /*!< in: line where called */
mtr_t* mtr) /*!< in: mini-transaction */
mtr_t* mtr, /*!< in: mini-transaction */
dberr_t* err) /*!< out: error code */
{
buf_block_t* block;
ulint fold;
@@ -2771,6 +2788,11 @@ buf_page_get_gen(
ut_ad((rw_latch == RW_S_LATCH)
|| (rw_latch == RW_X_LATCH)
|| (rw_latch == RW_NO_LATCH));
if (err) {
*err = DB_SUCCESS;
}
#ifdef UNIV_DEBUG
switch (mode) {
case BUF_GET_NO_LATCH:
@@ -2834,6 +2856,8 @@ loop:
}
if (block == NULL) {
buf_page_t* bpage=NULL;
/* Page not in buf_pool: needs to be read from file */
if (mode == BUF_GET_IF_IN_POOL_OR_WATCH) {
@@ -2868,19 +2892,47 @@ loop:
return(NULL);
}
if (buf_read_page(space, zip_size, offset, trx)) {
if (buf_read_page(space, zip_size, offset, trx, &bpage)) {
buf_read_ahead_random(space, zip_size, offset,
ibuf_inside(mtr), trx);
retries = 0;
} else if (retries < BUF_PAGE_READ_MAX_RETRIES) {
++retries;
bool corrupted = true;
if (bpage) {
corrupted = buf_page_check_corrupt(bpage);
}
/* Do not try again for encrypted pages */
if (!corrupted) {
ib_mutex_t* pmutex = buf_page_get_mutex(bpage);
mutex_enter(&buf_pool->LRU_list_mutex);
mutex_enter(pmutex);
buf_page_set_io_fix(bpage, BUF_IO_NONE);
buf_LRU_free_page(bpage, zip_size ? true : false);
mutex_exit(pmutex);
if (err) {
*err = DB_ENCRYPTED_DECRYPT_FAILED;
}
return (NULL);
}
DBUG_EXECUTE_IF(
"innodb_page_corruption_retries",
retries = BUF_PAGE_READ_MAX_RETRIES;
);
} else {
bool corrupted = true;
if (bpage) {
corrupted = buf_page_check_corrupt(bpage);
}
if (corrupted) {
fprintf(stderr, "InnoDB: Error: Unable"
" to read tablespace %lu page no"
" %lu into the buffer pool after"
@@ -2898,6 +2950,19 @@ loop:
BUF_PAGE_READ_MAX_RETRIES);
ut_error;
} else {
ib_mutex_t* pmutex = buf_page_get_mutex(bpage);
mutex_enter(&buf_pool->LRU_list_mutex);
mutex_enter(pmutex);
buf_page_set_io_fix(bpage, BUF_IO_NONE);
buf_LRU_free_page(bpage, zip_size ? true : false);
mutex_exit(pmutex);
if (err) {
*err = DB_ENCRYPTED_DECRYPT_FAILED;
}
return (NULL);
}
}
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
@@ -3670,8 +3735,11 @@ buf_page_init_low(
bpage->oldest_modification = 0;
bpage->write_size = 0;
bpage->key_version = 0;
bpage->stored_checksum = BUF_NO_CHECKSUM_MAGIC;
bpage->calculated_checksum = BUF_NO_CHECKSUM_MAGIC;
bpage->page_encrypted = false;
bpage->page_compressed = false;
bpage->encrypted = false;
bpage->real_size = 0;
HASH_INVALIDATE(bpage, hash);
@@ -4341,6 +4409,8 @@ buf_mark_space_corrupt(
/* First unfix and release lock on the bpage */
ut_ad(!mutex_own(&buf_pool->LRU_list_mutex));
if (!bpage->encrypted) {
mutex_enter(&buf_pool->LRU_list_mutex);
rw_lock_x_lock(hash_lock);
mutex_enter(buf_page_get_mutex(bpage));
@@ -4355,19 +4425,25 @@ buf_mark_space_corrupt(
&((buf_block_t*) bpage)->lock,
BUF_IO_READ);
}
}
/* Find the table with specified space id, and mark it corrupted */
if (dict_set_corrupted_by_space(space)) {
if (!bpage->encrypted) {
buf_LRU_free_one_page(bpage);
}
} else {
if (!bpage->encrypted) {
mutex_exit(buf_page_get_mutex(bpage));
}
ret = FALSE;
}
if(!bpage->encrypted) {
mutex_exit(&buf_pool->LRU_list_mutex);
ut_ad(buf_pool->n_pend_reads > 0);
os_atomic_decrement_ulint(&buf_pool->n_pend_reads, 1);
}
return(ret);
}
@@ -4378,42 +4454,77 @@ corrupted page. Note that we can't be 100% sure if page is corrupted
or decrypt/decompress just failed.
*/
static
void
ibool
buf_page_check_corrupt(
/*===================*/
const buf_page_t* bpage) /*!< in/out: buffer page read from disk */
buf_page_t* bpage) /*!< in/out: buffer page read from disk */
{
ulint zip_size = buf_page_get_zip_size(bpage);
byte* dst_frame = (zip_size) ? bpage->zip.data :
((buf_block_t*) bpage)->frame;
unsigned key_version = bpage->key_version;
bool page_compressed = bpage->page_encrypted;
ulint stored_checksum = bpage->stored_checksum;
ulint calculated_checksum = bpage->stored_checksum;
bool page_compressed_encrypted = bpage->page_compressed;
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);
fil_space_t* space = fil_space_found_by_id(space_id);
bool corrupted = true;
if (key_version != 0 || page_compressed_encrypted) {
bpage->encrypted = true;
}
if (key_version != 0 ||
(crypt_data && crypt_data->type != CRYPT_SCHEME_UNENCRYPTED) ||
page_compressed || page_compressed_encrypted) {
/* Page is really corrupted if post encryption stored
checksum does not match calculated checksum after page was
read. For pages compressed and then encrypted, there is no
checksum. */
corrupted = (!page_compressed_encrypted && stored_checksum != calculated_checksum);
if (corrupted) {
ib_logf(IB_LOG_LEVEL_ERROR,
"Maybe corruption: Block space_id %lu in file %s maybe corrupted.",
"%s: Block in space_id %lu in file %s corrupted.",
page_compressed_encrypted ? "Maybe corruption" : "Corruption",
space_id, space ? space->name : "NULL");
ib_logf(IB_LOG_LEVEL_ERROR,
"Page based on contents %s encrypted.",
(key_version == 0 && page_compressed_encrypted == false) ? "not" : "maybe");
if (stored_checksum != BUF_NO_CHECKSUM_MAGIC || calculated_checksum != BUF_NO_CHECKSUM_MAGIC) {
ib_logf(IB_LOG_LEVEL_ERROR,
"Page stored checksum %lu but calculated checksum %lu.",
stored_checksum, calculated_checksum);
}
ib_logf(IB_LOG_LEVEL_ERROR,
"Reason could be that key_version %u in page "
"or in crypt_data %p could not be found.",
key_version, crypt_data);
ib_logf(IB_LOG_LEVEL_ERROR,
"Reason could be also that key management plugin is not found or"
"used encryption algorithm or method does not match.");
" used encryption algorithm or method does not match.");
ib_logf(IB_LOG_LEVEL_ERROR,
"Based on page page compressed %d, compressed and encrypted %d.",
page_compressed, page_compressed_encrypted);
} else {
ib_logf(IB_LOG_LEVEL_ERROR,
"Block in space_id %lu in file %s encrypted.",
space_id, space ? space->name : "NULL");
ib_logf(IB_LOG_LEVEL_ERROR,
"However key management plugin or used key_id %u is not found or"
" used encryption algorithm or method does not match.",
key_version);
ib_logf(IB_LOG_LEVEL_ERROR,
"Marking tablespace as missing. You may drop this table or"
" install correct key management plugin and key file.");
}
}
return corrupted;
}
/********************************************************************//**
@@ -4534,6 +4645,9 @@ buf_page_io_complete(
;);
corrupt:
bool corrupted = buf_page_check_corrupt(bpage);
if (corrupted) {
fil_system_enter();
space = fil_space_get_by_id(bpage->space);
fil_system_exit();
@@ -4549,10 +4663,10 @@ corrupt:
"You may have to recover"
" from a backup.");
buf_page_check_corrupt(bpage);
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.");
@@ -4570,6 +4684,7 @@ corrupt:
"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) {
@@ -4597,13 +4712,31 @@ corrupt:
&& buf_mark_space_corrupt(bpage)) {
return(false);
} else {
buf_page_check_corrupt(bpage);
corrupted = buf_page_check_corrupt(bpage);
if (corrupted) {
ib_logf(IB_LOG_LEVEL_ERROR,
"Ending processing because of a corrupt database page.");
ut_error;
}
ib_push_warning(innobase_get_trx(), DB_ENCRYPTED_DECRYPT_FAILED,
"Table in tablespace %lu encrypted."
"However key management plugin or used key_id %lu is not found or"
" used encryption algorithm or method does not match."
" Can't continue opening the table.",
bpage->key_version);
if (bpage->space > TRX_SYS_SPACE) {
if (corrupted) {
buf_mark_space_corrupt(bpage);
}
} else {
ut_error;
}
return(false);
}
}
}
} /**/
@@ -4780,6 +4913,7 @@ buf_all_freed_instance(
mutex_exit(&buf_pool->LRU_list_mutex);
if (UNIV_LIKELY_NULL(block)) {
if (block->page.key_version == 0) {
fprintf(stderr,
"Page %lu %lu still fixed or dirty\n",
(ulong) block->page.space,
@@ -4787,6 +4921,7 @@ buf_all_freed_instance(
ut_error;
}
}
}
return(TRUE);
}
@@ -6124,6 +6259,11 @@ 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);
/* If page is encrypted read post-encryption checksum */
if (!page_compressed_encrypted && key_version != 0) {
bpage->stored_checksum = mach_read_from_4(dst_frame + + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION + 4);
}
ut_ad(bpage->key_version == 0);
if (bpage->offset == 0) {
@@ -6168,6 +6308,13 @@ buf_page_decrypt_after_read(
#ifdef UNIV_DEBUG
fil_page_type_validate(dst_frame);
#endif
/* Calculate checksum before decrypt, this will be
used later to find out if incorrect key was used. */
if (!page_compressed_encrypted) {
bpage->calculated_checksum = fil_crypt_calculate_checksum(zip_size, dst_frame);
}
/* decrypt using crypt_buf to dst_frame */
fil_space_decrypt(bpage->space,
slot->crypt_buf,

View File

@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2013, 2014, SkySQL Ab. All Rights Reserved.
Copyright (c) 2013, 2014, MariaDB Corporation. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -124,7 +124,8 @@ buf_read_page_low(
use to stop dangling page reads from a tablespace
which we have DISCARDed + IMPORTed back */
ulint offset, /*!< in: page number */
trx_t* trx)
trx_t* trx, /*!< in: trx */
buf_page_t** rbpage) /*!< out: page */
{
buf_page_t* bpage;
ulint wake_later;
@@ -259,10 +260,17 @@ not_to_recover:
/* The i/o is already completed when we arrive from
fil_read */
if (!buf_page_io_complete(bpage)) {
if (rbpage) {
*rbpage = bpage;
}
return(0);
}
}
if (rbpage) {
*rbpage = bpage;
}
return(1);
}
@@ -398,7 +406,7 @@ read_ahead:
&err, false,
ibuf_mode | OS_AIO_SIMULATED_WAKE_LATER,
space, zip_size, FALSE,
tablespace_version, i, trx);
tablespace_version, i, trx, NULL);
if (err == DB_TABLESPACE_DELETED) {
ut_print_timestamp(stderr);
fprintf(stderr,
@@ -447,9 +455,10 @@ ibool
buf_read_page(
/*==========*/
ulint space, /*!< in: space id */
ulint zip_size,/*!< in: compressed page size in bytes, or 0 */
ulint zip_size, /*!< in: compressed page size in bytes, or 0 */
ulint offset, /*!< in: page number */
trx_t* trx)
trx_t* trx, /*!< in: trx */
buf_page_t** bpage) /*!< out: page */
{
ib_int64_t tablespace_version;
ulint count;
@@ -462,7 +471,7 @@ buf_read_page(
count = buf_read_page_low(&err, true, BUF_READ_ANY_PAGE, space,
zip_size, FALSE,
tablespace_version, offset, trx);
tablespace_version, offset, trx, bpage);
srv_stats.buf_pool_reads.add(count);
if (err == DB_TABLESPACE_DELETED) {
ut_print_timestamp(stderr);
@@ -510,7 +519,7 @@ buf_read_page_async(
| OS_AIO_SIMULATED_WAKE_LATER
| BUF_READ_IGNORE_NONEXISTENT_PAGES,
space, zip_size, FALSE,
tablespace_version, offset, NULL);
tablespace_version, offset, NULL,NULL);
srv_stats.buf_pool_reads.add(count);
/* We do not increment number of I/O operations used for LRU policy
@@ -778,7 +787,7 @@ buf_read_ahead_linear(
count += buf_read_page_low(
&err, false,
ibuf_mode,
space, zip_size, FALSE, tablespace_version, i, trx);
space, zip_size, FALSE, tablespace_version, i, trx, NULL);
if (err == DB_TABLESPACE_DELETED) {
ut_print_timestamp(stderr);
fprintf(stderr,
@@ -868,7 +877,7 @@ buf_read_ibuf_merge_pages(
buf_read_page_low(&err, sync && (i + 1 == n_stored),
BUF_READ_ANY_PAGE, space_ids[i],
zip_size, TRUE, space_versions[i],
page_nos[i], NULL);
page_nos[i], NULL, NULL);
if (UNIV_UNLIKELY(err == DB_TABLESPACE_DELETED)) {
tablespace_deleted:
@@ -1008,12 +1017,12 @@ not_to_recover:
if ((i + 1 == n_stored) && sync) {
buf_read_page_low(&err, true, BUF_READ_ANY_PAGE, space,
zip_size, TRUE, tablespace_version,
page_nos[i], NULL);
page_nos[i], NULL, NULL);
} else {
buf_read_page_low(&err, false, BUF_READ_ANY_PAGE
| OS_AIO_SIMULATED_WAKE_LATER,
space, zip_size, TRUE,
tablespace_version, page_nos[i], NULL);
tablespace_version, page_nos[i], NULL, NULL);
}
}

View File

@@ -650,31 +650,8 @@ fil_space_encrypt(
/* handle post encryption checksum */
ib_uint32_t checksum = 0;
srv_checksum_algorithm_t algorithm =
static_cast<srv_checksum_algorithm_t>(srv_checksum_algorithm);
if (zip_size == 0) {
switch (algorithm) {
case SRV_CHECKSUM_ALGORITHM_CRC32:
case SRV_CHECKSUM_ALGORITHM_STRICT_CRC32:
checksum = buf_calc_page_crc32(dst_frame);
break;
case SRV_CHECKSUM_ALGORITHM_INNODB:
case SRV_CHECKSUM_ALGORITHM_STRICT_INNODB:
checksum = (ib_uint32_t) buf_calc_page_new_checksum(
dst_frame);
break;
case SRV_CHECKSUM_ALGORITHM_NONE:
case SRV_CHECKSUM_ALGORITHM_STRICT_NONE:
checksum = BUF_NO_CHECKSUM_MAGIC;
break;
/* no default so the compiler will emit a warning
* if new enum is added and not handled here */
}
} else {
checksum = page_zip_calc_checksum(dst_frame, zip_size,
algorithm);
}
checksum = fil_crypt_calculate_checksum(zip_size, dst_frame);
// store the post-encryption checksum after the key-version
mach_write_to_4(dst_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION + 4, checksum);
@@ -818,6 +795,47 @@ fil_space_decrypt(
return src_frame;
}
/******************************************************************
Calculate post encryption checksum
@return page checksum or BUF_NO_CHECKSUM_MAGIC
not needed. */
UNIV_INTERN
ulint
fil_crypt_calculate_checksum(
/*=========================*/
ulint zip_size, /*!< in: zip_size or 0 */
byte* dst_frame) /*!< in: page where to calculate */
{
ib_uint32_t checksum = 0;
srv_checksum_algorithm_t algorithm =
static_cast<srv_checksum_algorithm_t>(srv_checksum_algorithm);
if (zip_size == 0) {
switch (algorithm) {
case SRV_CHECKSUM_ALGORITHM_CRC32:
case SRV_CHECKSUM_ALGORITHM_STRICT_CRC32:
checksum = buf_calc_page_crc32(dst_frame);
break;
case SRV_CHECKSUM_ALGORITHM_INNODB:
case SRV_CHECKSUM_ALGORITHM_STRICT_INNODB:
checksum = (ib_uint32_t) buf_calc_page_new_checksum(
dst_frame);
break;
case SRV_CHECKSUM_ALGORITHM_NONE:
case SRV_CHECKSUM_ALGORITHM_STRICT_NONE:
checksum = BUF_NO_CHECKSUM_MAGIC;
break;
/* no default so the compiler will emit a warning
* if new enum is added and not handled here */
}
} else {
checksum = page_zip_calc_checksum(dst_frame, zip_size,
algorithm);
}
return checksum;
}
/*********************************************************************
Verify checksum for a page (iff it's encrypted)
NOTE: currently this function can only be run in single threaded mode

View File

@@ -2006,6 +2006,7 @@ convert_error_code_to_mysql(
case DB_TABLESPACE_DELETED:
case DB_TABLE_NOT_FOUND:
case DB_ENCRYPTED_DECRYPT_FAILED:
return(HA_ERR_NO_SUCH_TABLE);
case DB_TABLESPACE_NOT_FOUND:
@@ -6043,7 +6044,14 @@ table_opened:
innobase_copy_frm_flags_from_table_share(ib_table, table->s);
ib_table->thd = (void*)thd;
/* No point to init any statistics if tablespace is still encrypted. */
if (!ib_table->is_encrypted) {
dict_stats_init(ib_table);
} else {
ib_table->stat_initialized = 1;
}
MONITOR_INC(MONITOR_TABLE_OPEN);
@@ -6072,6 +6080,11 @@ table_opened:
file, best to play it safe. */
no_tablespace = true;
} else if (ib_table->is_encrypted) {
/* This means that tablespace was found but we could not
decrypt encrypted page. */
no_tablespace = true;
ib_table->ibd_file_missing = true;
} else {
no_tablespace = false;
}
@@ -6083,9 +6096,9 @@ table_opened:
/* If table has no talespace but it has crypt data, check
is tablespace made unaccessible because encryption service
or used key_id is not available. */
if (ib_table && ib_table->crypt_data) {
if (ib_table) {
fil_space_crypt_t* crypt_data = ib_table->crypt_data;
if ((crypt_data->encryption == FIL_SPACE_ENCRYPTION_ON) ||
if ((crypt_data && crypt_data->encryption == FIL_SPACE_ENCRYPTION_ON) ||
(srv_encrypt_tables &&
crypt_data && crypt_data->encryption == FIL_SPACE_ENCRYPTION_DEFAULT)) {
@@ -6097,6 +6110,13 @@ table_opened:
" Can't continue reading table.",
ib_table->name, crypt_data->key_id);
}
} else if (ib_table->is_encrypted) {
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
HA_ERR_NO_SUCH_TABLE,
"Table %s is encrypted but encryption service or"
" used key_id is not available. "
" Can't continue reading table.",
ib_table->name);
}
}
@@ -21402,3 +21422,59 @@ static void innodb_remember_check_sysvar_funcs()
ut_ad((MYSQL_SYSVAR_NAME(checksum_algorithm).flags & 0x1FF) == PLUGIN_VAR_ENUM);
check_sysvar_enum = MYSQL_SYSVAR_NAME(checksum_algorithm).check;
}
/********************************************************************//**
Helper function to push warnings from InnoDB internals to SQL-layer. */
UNIV_INTERN
void
ib_push_warning(
trx_t* trx, /*!< in: trx */
ulint error, /*!< in: error code to push as warning */
const char *format,/*!< in: warning message */
...)
{
va_list args;
THD *thd = (THD *)trx->mysql_thd;
char *buf;
#define MAX_BUF_SIZE 4*1024
va_start(args, format);
buf = (char *)my_malloc(MAX_BUF_SIZE, MYF(MY_WME));
vsprintf(buf,format, args);
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
convert_error_code_to_mysql((dberr_t)error, 0, thd),
buf);
my_free(buf);
va_end(args);
}
/********************************************************************//**
Helper function to push warnings from InnoDB internals to SQL-layer. */
UNIV_INTERN
void
ib_push_warning(
void* ithd, /*!< in: thd */
ulint error, /*!< in: error code to push as warning */
const char *format,/*!< in: warning message */
...)
{
va_list args;
THD *thd = (THD *)ithd;
char *buf;
#define MAX_BUF_SIZE 4*1024
if (ithd == NULL) {
thd = current_thd;
}
va_start(args, format);
buf = (char *)my_malloc(MAX_BUF_SIZE, MYF(MY_WME));
vsprintf(buf,format, args);
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
convert_error_code_to_mysql((dberr_t)error, 0, thd),
buf);
my_free(buf);
va_end(args);
}

View File

@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1994, 2012, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2015, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -59,12 +60,14 @@ btr_block_get_func(
block = buf_page_get_gen(space, zip_size, page_no, mode,
NULL, BUF_GET, file, line, mtr);
if (block) {
if (mode != RW_NO_LATCH) {
buf_block_dbg_add_level(
block, index != NULL && dict_index_is_ibuf(index)
? SYNC_IBUF_TREE_NODE : SYNC_TREE_NODE);
}
}
return(block);
}

View File

@@ -136,7 +136,7 @@ Note that if mode is PAGE_CUR_LE, which is used in inserts, then
cursor->up_match and cursor->low_match both will have sensible values.
If mode is PAGE_CUR_GE, then up_match will a have a sensible value. */
UNIV_INTERN
void
dberr_t
btr_cur_search_to_nth_level(
/*========================*/
dict_index_t* index, /*!< in: index */
@@ -173,7 +173,7 @@ btr_cur_search_to_nth_level(
/*****************************************************************//**
Opens a cursor at either end of an index. */
UNIV_INTERN
void
dberr_t
btr_cur_open_at_index_side_func(
/*============================*/
bool from_left, /*!< in: true if open to the low end,

View File

@@ -114,7 +114,7 @@ btr_pcur_open_low(
Opens an persistent cursor to an index tree without initializing the
cursor. */
UNIV_INLINE
void
dberr_t
btr_pcur_open_with_no_init_func(
/*============================*/
dict_index_t* index, /*!< in: index */
@@ -143,7 +143,7 @@ btr_pcur_open_with_no_init_func(
/*****************************************************************//**
Opens a persistent cursor at either end of an index. */
UNIV_INLINE
void
dberr_t
btr_pcur_open_at_index_side(
/*========================*/
bool from_left, /*!< in: true if open to the low end,

View File

@@ -447,7 +447,7 @@ btr_pcur_open_low(
Opens an persistent cursor to an index tree without initializing the
cursor. */
UNIV_INLINE
void
dberr_t
btr_pcur_open_with_no_init_func(
/*============================*/
dict_index_t* index, /*!< in: index */
@@ -472,6 +472,7 @@ btr_pcur_open_with_no_init_func(
mtr_t* mtr) /*!< in: mtr */
{
btr_cur_t* btr_cursor;
dberr_t err = DB_SUCCESS;
cursor->latch_mode = latch_mode;
cursor->search_mode = mode;
@@ -480,7 +481,7 @@ btr_pcur_open_with_no_init_func(
btr_cursor = btr_pcur_get_btr_cur(cursor);
btr_cur_search_to_nth_level(index, 0, tuple, mode, latch_mode,
err = btr_cur_search_to_nth_level(index, 0, tuple, mode, latch_mode,
btr_cursor, has_search_latch,
file, line, mtr);
cursor->pos_state = BTR_PCUR_IS_POSITIONED;
@@ -488,12 +489,13 @@ btr_pcur_open_with_no_init_func(
cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
cursor->trx_if_known = NULL;
return err;
}
/*****************************************************************//**
Opens a persistent cursor at either end of an index. */
UNIV_INLINE
void
dberr_t
btr_pcur_open_at_index_side(
/*========================*/
bool from_left, /*!< in: true if open to the low end,
@@ -506,6 +508,8 @@ btr_pcur_open_at_index_side(
(0=leaf) */
mtr_t* mtr) /*!< in/out: mini-transaction */
{
dberr_t err = DB_SUCCESS;
pcur->latch_mode = BTR_LATCH_MODE_WITHOUT_FLAGS(latch_mode);
pcur->search_mode = from_left ? PAGE_CUR_G : PAGE_CUR_L;
@@ -514,13 +518,15 @@ btr_pcur_open_at_index_side(
btr_pcur_init(pcur);
}
btr_cur_open_at_index_side(from_left, index, latch_mode,
err = btr_cur_open_at_index_side(from_left, index, latch_mode,
btr_pcur_get_btr_cur(pcur), level, mtr);
pcur->pos_state = BTR_PCUR_IS_POSITIONED;
pcur->old_stored = BTR_PCUR_OLD_NOT_STORED;
pcur->trx_if_known = NULL;
return (err);
}
/**********************************************************************//**

View File

@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1995, 2014, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2013, 2014, SkySQL Ab. All Rights Reserved.
Copyright (c) 2013, 2015, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -428,7 +428,8 @@ buf_page_get_gen(
BUF_GET_IF_IN_POOL_OR_WATCH */
const char* file, /*!< in: file name */
ulint line, /*!< in: line where called */
mtr_t* mtr); /*!< in: mini-transaction */
mtr_t* mtr, /*!< in: mini-transaction */
dberr_t* err = NULL); /*!< out: error code */
/********************************************************************//**
Initializes a page to the buffer buf_pool. The page is usually not read
from a file even if it cannot be found in the buffer buf_pool. This is one
@@ -1611,8 +1612,14 @@ struct buf_page_t{
operation needed. */
unsigned key_version; /*!< key version for this block */
bool page_encrypted; /*!< page is encrypted */
bool page_encrypted; /*!< page is page encrypted */
bool page_compressed;/*!< page is page compressed */
ulint stored_checksum;/*!< stored page checksum if page
encrypted */
bool encrypted; /*!< page is still encrypted */
ulint calculated_checksum;
/*!< calculated checksum if page
encrypted */
ulint real_size; /*!< Real size of the page
Normal pages == UNIV_PAGE_SIZE

View File

@@ -689,6 +689,10 @@ buf_block_get_frame(
/*================*/
const buf_block_t* block) /*!< in: pointer to the control block */
{
if (!block) {
return NULL;
}
SRV_CORRUPT_TABLE_CHECK(block, return(0););
switch (buf_block_get_state(block)) {
@@ -696,6 +700,9 @@ buf_block_get_frame(
case BUF_BLOCK_ZIP_PAGE:
case BUF_BLOCK_ZIP_DIRTY:
case BUF_BLOCK_NOT_USED:
if (block->page.encrypted) {
goto ok;
}
ut_error;
break;
case BUF_BLOCK_FILE_PAGE:

View File

@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2015, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -40,9 +41,11 @@ ibool
buf_read_page(
/*==========*/
ulint space, /*!< in: space id */
ulint zip_size,/*!< in: compressed page size in bytes, or 0 */
ulint zip_size, /*!< in: compressed page size in bytes, or 0 */
ulint offset, /*!< in: page number */
trx_t* trx);
trx_t* trx, /*!< in: trx */
buf_page_t** bpage /*!< out: page */
);
/********************************************************************//**
High-level function which reads a page asynchronously from a file to the
buffer buf_pool if it is not already there. Sets the io_fix flag and sets

View File

@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2014, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2015, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -132,6 +133,11 @@ enum dberr_t {
/*< Too many words in a phrase */
DB_TOO_BIG_FOR_REDO, /* Record length greater than 10%
of redo log */
DB_ENCRYPTED_DECRYPT_FAILED, /* Tablespace encrypted and
decrypt operaton failed because
of missing key management plugin,
or missing or incorrect key or
incorret AES method or algorithm. */
/* The following are partial failure codes */
DB_FAIL = 1000,
DB_OVERFLOW,

View File

@@ -2,7 +2,7 @@
Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2012, Facebook Inc.
Copyright (c) 2013, SkySQL Ab. All Rights Reserved.
Copyright (c) 2013, 2015, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -1033,6 +1033,7 @@ struct dict_table_t{
table_id_t id; /*!< id of the table */
mem_heap_t* heap; /*!< memory heap */
char* name; /*!< table name */
void* thd; /*!< thd */
fil_space_crypt_t *crypt_data; /*!< crypt data if present */
const char* dir_path_of_temp_table;/*!< NULL or the directory path
where a TEMPORARY table that was explicitly
@@ -1346,6 +1347,7 @@ struct dict_table_t{
locks; /*!< list of locks on the table; protected
by lock_sys->mutex */
ibool is_corrupt;
ibool is_encrypted;
#endif /* !UNIV_HOTBACKUP */
#ifdef UNIV_DEBUG

View File

@@ -381,6 +381,17 @@ fil_crypt_set_encrypt_tables(
/*=========================*/
uint val); /*!< in: New srv_encrypt_tables setting */
/******************************************************************
Calculate post encryption checksum
@return page checksum or BUF_NO_CHECKSUM_MAGIC
not needed. */
UNIV_INTERN
ulint
fil_crypt_calculate_checksum(
/*=========================*/
ulint zip_size, /*!< in: zip_size or 0 */
byte* dst_frame); /*!< in: page where to calculate */
#ifndef UNIV_NONINL
#include "fil0crypt.ic"
#endif

View File

@@ -636,5 +636,13 @@ ib_push_warning(
ulint error, /*!< in: error code to push as warning */
const char *format,/*!< in: warning message */
...);
/********************************************************************//**
Helper function to push warnings from InnoDB internals to SQL-layer. */
UNIV_INTERN
void
ib_push_warning(
void* ithd, /*!< in: thd */
ulint error, /*!< in: error code to push as warning */
const char *format,/*!< in: warning message */
...);
#endif /* HA_INNODB_PROTOTYPES_H */

View File

@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1994, 2013, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2015, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -39,7 +40,10 @@ page_cur_get_page(
page_cur_t* cur) /*!< in: page cursor */
{
ut_ad(cur);
if (cur->rec) {
ut_ad(page_align(cur->rec) == cur->block->frame);
}
return(page_align(cur->rec));
}
@@ -54,7 +58,11 @@ page_cur_get_block(
page_cur_t* cur) /*!< in: page cursor */
{
ut_ad(cur);
if (cur->rec) {
ut_ad(page_align(cur->rec) == cur->block->frame);
}
return(cur->block);
}
@@ -80,7 +88,10 @@ page_cur_get_rec(
page_cur_t* cur) /*!< in: page cursor */
{
ut_ad(cur);
if (cur->rec) {
ut_ad(page_align(cur->rec) == cur->block->frame);
}
return(cur->rec);
}

View File

@@ -2350,7 +2350,7 @@ row_ins_clust_index_entry_low(
{
btr_cur_t cursor;
ulint* offsets = NULL;
dberr_t err;
dberr_t err = DB_SUCCESS;
big_rec_t* big_rec = NULL;
mtr_t mtr;
mem_heap_t* offsets_heap = NULL;
@@ -2380,9 +2380,16 @@ row_ins_clust_index_entry_low(
the function will return in both low_match and up_match of the
cursor sensible values */
btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE, mode,
err = btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE, mode,
&cursor, 0, __FILE__, __LINE__, &mtr);
if (err != DB_SUCCESS) {
index->table->is_encrypted = true;
index->table->ibd_file_missing = true;
mtr_commit(&mtr);
goto func_exit;
}
#ifdef UNIV_DEBUG
{
page_t* page = btr_cur_get_page(&cursor);
@@ -2696,10 +2703,23 @@ row_ins_sec_index_entry_low(
search_mode |= BTR_IGNORE_SEC_UNIQUE;
}
btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE,
err = btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE,
search_mode,
&cursor, 0, __FILE__, __LINE__, &mtr);
if (err != DB_SUCCESS) {
if (err == DB_ENCRYPTED_DECRYPT_FAILED) {
ib_push_warning(trx->mysql_thd,
DB_ENCRYPTED_DECRYPT_FAILED,
"Table %s is encrypted but encryption service or"
" used key_id is not available. "
" Can't continue reading table.",
index->table->name);
index->table->is_encrypted = true;
}
goto func_exit;
}
if (cursor.flag == BTR_CUR_INSERT_TO_IBUF) {
/* The insert was buffered during the search: we are done */
goto func_exit;

View File

@@ -622,6 +622,8 @@ handle_new_error:
case DB_FTS_INVALID_DOCID:
case DB_INTERRUPTED:
case DB_DICT_CHANGED:
case DB_TABLE_NOT_FOUND:
case DB_ENCRYPTED_DECRYPT_FAILED:
if (savept) {
/* Roll back the latest, possibly incomplete insertion
or update */
@@ -1314,7 +1316,13 @@ row_insert_for_mysql(
prebuilt->table->name);
return(DB_TABLESPACE_NOT_FOUND);
} else if (prebuilt->table->is_encrypted) {
ib_push_warning(trx, DB_ENCRYPTED_DECRYPT_FAILED,
"Table %s in tablespace %lu encrypted."
"However key management plugin or used key_id is not found or"
" used encryption algorithm or method does not match.",
prebuilt->table->name, prebuilt->table->space);
return(DB_ENCRYPTED_DECRYPT_FAILED);
} else if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) {
fprintf(stderr,
"InnoDB: Error: trying to free a corrupt\n"
@@ -1713,6 +1721,13 @@ row_update_for_mysql(
"InnoDB: how you can resolve the problem.\n",
prebuilt->table->name);
return(DB_ERROR);
} else if (prebuilt->table->is_encrypted) {
ib_push_warning(trx, DB_ENCRYPTED_DECRYPT_FAILED,
"Table %s in tablespace %lu encrypted."
"However key management plugin or used key_id is not found or"
" used encryption algorithm or method does not match.",
prebuilt->table->name, prebuilt->table->space);
return (DB_TABLE_NOT_FOUND);
}
if (UNIV_UNLIKELY(prebuilt->magic_n != ROW_PREBUILT_ALLOCATED)) {
@@ -3932,6 +3947,19 @@ row_drop_table_for_mysql(
goto funct_exit;
}
/* If table is encrypted and table page encryption failed
mark this table read only. */
if (table->is_encrypted) {
if (table->can_be_evicted) {
dict_table_move_from_lru_to_non_lru(table);
}
dict_table_close(table, TRUE, FALSE);
err = DB_READ_ONLY;
goto funct_exit;
}
/* Turn on this drop bit before we could release the dictionary
latch */
table->to_be_dropped = true;

View File

@@ -2,6 +2,7 @@
Copyright (c) 1997, 2013, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
Copyright (c) 2015, MariaDB Corporation.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
@@ -3726,6 +3727,9 @@ row_search_for_mysql(
return(DB_TABLESPACE_NOT_FOUND);
} else if (prebuilt->table->is_encrypted) {
return(DB_ENCRYPTED_DECRYPT_FAILED);
} else if (!prebuilt->index_usable) {
return(DB_MISSING_HISTORY);
@@ -4137,10 +4141,15 @@ wait_table_again:
} else if (dtuple_get_n_fields(search_tuple) > 0) {
btr_pcur_open_with_no_init(index, search_tuple, mode,
err = btr_pcur_open_with_no_init(index, search_tuple, mode,
BTR_SEARCH_LEAF,
pcur, 0, &mtr);
if (err != DB_SUCCESS) {
rec = NULL;
goto lock_wait_or_error;
}
pcur->trx_if_known = trx;
rec = btr_pcur_get_rec(pcur);
@@ -4173,9 +4182,23 @@ wait_table_again:
}
}
} else if (mode == PAGE_CUR_G || mode == PAGE_CUR_L) {
btr_pcur_open_at_index_side(
err = btr_pcur_open_at_index_side(
mode == PAGE_CUR_G, index, BTR_SEARCH_LEAF,
pcur, false, 0, &mtr);
if (err != DB_SUCCESS) {
if (err == DB_ENCRYPTED_DECRYPT_FAILED) {
ib_push_warning(trx->mysql_thd,
DB_ENCRYPTED_DECRYPT_FAILED,
"Table %s is encrypted but encryption service or"
" used key_id is not available. "
" Can't continue reading table.",
prebuilt->table->name);
index->table->is_encrypted = true;
}
rec = NULL;
goto lock_wait_or_error;
}
}
rec_loop:
@@ -4191,6 +4214,11 @@ rec_loop:
rec = btr_pcur_get_rec(pcur);
if (!rec) {
err = DB_ENCRYPTED_DECRYPT_FAILED;
goto lock_wait_or_error;
}
SRV_CORRUPT_TABLE_CHECK(rec,
{
err = DB_CORRUPTION;
@@ -5132,7 +5160,9 @@ lock_wait_or_error:
/*-------------------------------------------------------------*/
if (rec) {
btr_pcur_store_position(pcur, &mtr);
}
lock_table_wait:
mtr_commit(&mtr);