1
0
mirror of https://github.com/MariaDB/server.git synced 2026-10-23 18:49:29 +03:00

InnoDB/XtraDB Encryption cleanup

Step 2:

-- Introduce temporal memory array to buffer pool where to allocate
temporary memory for encryption/compression
-- Rename PAGE_ENCRYPTION -> ENCRYPTION
-- Rename PAGE_ENCRYPTION_KEY -> ENCRYPTION_KEY
-- Rename innodb_default_page_encryption_key -> innodb_default_encryption_key
-- Allow enable/disable encryption for tables by changing
 ENCRYPTION to enum having values DEFAULT, ON, OFF
-- In create table store crypt_data if ENCRYPTION is ON or OFF
-- Do not crypt tablespaces having ENCRYPTION=OFF
-- Store encryption mode to crypt_data and redo-log
This commit is contained in:
Jan Lindström
2015-04-01 19:37:00 +03:00
committed by Sergei Golubchik
parent b4a4d82396
commit 0ba9fa35bc
31 changed files with 822 additions and 568 deletions

View File

@@ -59,6 +59,14 @@ Created 11/5/1995 Heikki Tuuri
#include "ut0byte.h"
#include <new>
#ifdef HAVE_LZO
#include "lzo/lzo1x.h"
#endif
/* Number of temporary slots used for encryption/compression
memory allocation before/after I/O operations */
#define BUF_MAX_TMP_SLOTS 200
/*
IMPLEMENTATION OF THE BUFFER POOL
=================================
@@ -1001,14 +1009,11 @@ buf_block_init(
block->page.state = BUF_BLOCK_NOT_USED;
block->page.buf_fix_count = 0;
block->page.io_fix = BUF_IO_NONE;
block->page.crypt_buf = NULL;
block->page.crypt_buf_free = NULL;
block->page.comp_buf = NULL;
block->page.comp_buf_free = NULL;
block->page.key_version = 0;
block->page.encrypt_later = false;
block->page.real_size = 0;
block->page.write_size = 0;
block->modify_clock = 0;
block->page.slot = NULL;
#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
block->page.file_page_was_freed = FALSE;
@@ -1361,6 +1366,11 @@ buf_pool_init_instance(
/* Initialize the iterator for single page scan search */
new(&buf_pool->single_scan_itr) LRUItr(buf_pool, &buf_pool->mutex);
/* Initialize the temporal memory array and slots */
buf_pool->tmp_arr = (buf_tmp_array_t *)mem_zalloc(sizeof(buf_tmp_array_t));
buf_pool->tmp_arr->n_slots = BUF_MAX_TMP_SLOTS;
buf_pool->tmp_arr->slots = (buf_tmp_buffer_t*)mem_zalloc(sizeof(buf_tmp_buffer_t) * BUF_MAX_TMP_SLOTS);
buf_pool_mutex_exit(buf_pool);
return(DB_SUCCESS);
@@ -1412,6 +1422,25 @@ buf_pool_free_instance(
ha_clear(buf_pool->page_hash);
hash_table_free(buf_pool->page_hash);
hash_table_free(buf_pool->zip_hash);
/* Free all used temporary slots */
for(ulint i = 0; i < buf_pool->tmp_arr->n_slots; i++) {
buf_tmp_buffer_t* slot = &buf_pool->tmp_arr->slots[i];
#ifdef HAVE_LZO
if (slot->lzo_mem) {
ut_free(slot->lzo_mem);
}
#endif
if (slot->crypt_buf_free) {
ut_free(slot->crypt_buf_free);
}
if (slot->comp_buf_free) {
ut_free(slot->comp_buf_free);
}
}
mem_free(buf_pool->tmp_arr->slots);
mem_free(buf_pool->tmp_arr);
}
/********************************************************************//**
@@ -3494,12 +3523,9 @@ buf_page_init_low(
bpage->newest_modification = 0;
bpage->oldest_modification = 0;
bpage->write_size = 0;
bpage->crypt_buf = NULL;
bpage->crypt_buf_free = NULL;
bpage->comp_buf = NULL;
bpage->comp_buf_free = NULL;
bpage->key_version = 0;
bpage->encrypt_later = false;
bpage->real_size = 0;
bpage->slot = NULL;
HASH_INVALIDATE(bpage, hash);
#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
@@ -4366,7 +4392,11 @@ corrupt:
}
} else {
/* io_type == BUF_IO_WRITE */
buf_page_encrypt_after_write(bpage);
if (bpage->slot) {
/* Mark slot free */
bpage->slot->reserved = false;
bpage->slot = NULL;
}
}
buf_pool_mutex_enter(buf_pool);
@@ -5602,6 +5632,60 @@ buf_page_init_for_backup_restore(
}
#endif /* !UNIV_HOTBACKUP */
/********************************************************************//**
Reserve unused slot from temporary memory array and allocate necessary
temporary memory if not yet allocated.
@return reserved slot */
buf_tmp_buffer_t*
buf_pool_reserve_tmp_slot(
/*======================*/
buf_pool_t* buf_pool, /*!< in: buffer pool where to
reserve */
bool compressed) /*!< in: is file space compressed */
{
buf_tmp_buffer_t *free_slot=NULL;
/* Array is protected by buf_pool mutex */
buf_pool_mutex_enter(buf_pool);
for(ulint i = 0; i < buf_pool->tmp_arr->n_slots; i++) {
buf_tmp_buffer_t *slot = &buf_pool->tmp_arr->slots[i];
if(slot->reserved == false) {
free_slot = slot;
break;
}
}
/* We assume that free slot is found */
ut_a(free_slot != NULL);
free_slot->reserved = true;
/* Now that we have reserved this slot we can release
buf_pool mutex */
buf_pool_mutex_exit(buf_pool);
/* Allocate temporary memory for encryption/decryption */
if (free_slot->crypt_buf_free == NULL) {
free_slot->crypt_buf_free = static_cast<byte *>(ut_malloc(UNIV_PAGE_SIZE*2));
free_slot->crypt_buf = static_cast<byte *>(ut_align(free_slot->crypt_buf_free, UNIV_PAGE_SIZE));
memset(free_slot->crypt_buf_free, 0, UNIV_PAGE_SIZE *2);
}
/* For page compressed tables allocate temporary memory for
compression/decompression */
if (compressed && free_slot->comp_buf_free == NULL) {
free_slot->comp_buf_free = static_cast<byte *>(ut_malloc(UNIV_PAGE_SIZE*2));
free_slot->comp_buf = static_cast<byte *>(ut_align(free_slot->comp_buf_free, UNIV_PAGE_SIZE));
memset(free_slot->comp_buf_free, 0, UNIV_PAGE_SIZE *2);
#ifdef HAVE_LZO
free_slot->lzo_mem = static_cast<byte *>(ut_malloc(LZO1X_1_15_MEM_COMPRESS));
memset(free_slot->lzo_mem, 0, LZO1X_1_15_MEM_COMPRESS);
#endif
}
return (free_slot);
}
/********************************************************************//**
Encrypts a buffer page right before it's flushed to disk
*/
@@ -5609,11 +5693,17 @@ byte*
buf_page_encrypt_before_write(
/*==========================*/
buf_page_t* bpage, /*!< in/out: buffer page to be flushed */
const byte* src_frame) /*!< in: src frame */
const byte* src_frame, /*!< in: src frame */
ulint space_id) /*!< in: space id */
{
bpage->encrypt_later = false;
fil_space_crypt_t* crypt_data = fil_space_get_crypt_data(space_id);
if (srv_encrypt_tables == FALSE) {
if (crypt_data != NULL && crypt_data->encryption == FIL_SPACE_ENCRYPTION_OFF) {
/* Encryption is disabled */
return const_cast<byte*>(src_frame);
}
if (!srv_encrypt_tables && (crypt_data == NULL || crypt_data->encryption == FIL_SPACE_ENCRYPTION_DEFAULT)) {
/* Encryption is disabled */
return const_cast<byte*>(src_frame);
}
@@ -5638,103 +5728,63 @@ buf_page_encrypt_before_write(
ulint zip_size = buf_page_get_zip_size(bpage);
ulint page_size = (zip_size) ? zip_size : UNIV_PAGE_SIZE;
buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
bool page_compressed = fil_space_is_page_compressed(bpage->space);
/**
* TODO(jonaso): figure out more clever malloc strategy
*
* This implementation does a malloc/free per iop for encrypted
* tablespaces. Alternative strategies that have been considered are
*
* 1) use buf_block_alloc (i.e alloc from buffer pool)
* this does not work as buf_block_alloc will then be called
* when needing to flush a page, which might be triggered
* due to shortage of memory in buffer pool
* 2) allocate a buffer per fil_node_t
* this would break abstraction layers and has therfore not been
* considered a lot.
*/
/* Find free slot from temporary memory array */
buf_tmp_buffer_t* slot = buf_pool_reserve_tmp_slot(buf_pool, page_compressed);
bpage->slot = slot;
if (bpage->crypt_buf_free == NULL) {
bpage->crypt_buf_free = (byte*)malloc(page_size*2);
// TODO: Is 4k aligment enough ?
bpage->crypt_buf = (byte *)ut_align(bpage->crypt_buf_free, page_size);
}
byte *dst_frame = slot->crypt_buf;
byte *dst_frame = bpage->crypt_buf;
if (!fil_space_is_page_compressed(bpage->space)) {
// encrypt page content
fil_space_encrypt(bpage->space, bpage->offset,
bpage->newest_modification,
src_frame, zip_size, dst_frame, 0);
if (!page_compressed) {
/* Encrypt page content */
fil_space_encrypt(bpage->space,
bpage->offset,
bpage->newest_modification,
src_frame,
zip_size,
dst_frame);
unsigned key_version =
mach_read_from_4(dst_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION);
ut_ad(key_version == 0 || key_version >= bpage->key_version);
bpage->key_version = key_version;
bpage->real_size = zip_size;
} else {
/** Compression and encryption is done later at os0file.cc */
bpage->encrypt_later = true;
dst_frame = (byte *)src_frame;
/* First we compress the page content */
ulint out_len = 0;
ulint block_size = fil_space_get_block_size(bpage->space, bpage->offset, page_size);
byte *tmp = fil_compress_page(bpage->space,
(byte *)src_frame,
slot->comp_buf,
page_size,
fil_space_get_page_compression_level(bpage->space),
block_size,
&out_len,
#ifdef HAVE_LZO
slot->lzo_mem
#else
NULL
#endif
);
bpage->real_size = out_len;
/* And then we encrypt the page content */
fil_space_encrypt(bpage->space,
bpage->offset,
bpage->newest_modification,
tmp,
zip_size,
dst_frame);
}
// return dst_frame which will be written
return dst_frame;
}
/********************************************************************//**
Release memory after encrypted page has been written to disk
*/
ibool
buf_page_encrypt_after_write(
/*=========================*/
buf_page_t* bpage) /*!< in/out: buffer page flushed */
{
if (bpage->crypt_buf_free != NULL) {
free(bpage->crypt_buf_free);
bpage->crypt_buf_free = NULL;
bpage->crypt_buf = NULL;
}
if (bpage->comp_buf_free != NULL) {
free(bpage->comp_buf_free);
bpage->comp_buf_free = NULL;
bpage->comp_buf = NULL;
}
return (TRUE);
}
/********************************************************************//**
Allocates memory to read in an encrypted page
*/
byte*
buf_page_decrypt_before_read(
/*=========================*/
buf_page_t* bpage, /*!< in/out: buffer page to be read */
ulint zip_size) /*!< in: compressed page size, or 0 */
{
ulint size = (zip_size) ? zip_size : UNIV_PAGE_SIZE;
/*
Here we only need to allocate space for not header pages
in case of file space encryption. Table encryption is handled
later.
*/
if (!srv_encrypt_tables || bpage->offset == 0 ||
fil_space_check_encryption_read(bpage->space) == false)
return zip_size ? bpage->zip.data : ((buf_block_t*) bpage)->frame;
if (bpage->crypt_buf_free == NULL)
{
// allocate buffer to read data into
bpage->crypt_buf_free = (byte*)malloc(size*2);
// TODO: Is 4K aligment enough ?
bpage->crypt_buf = (byte*)ut_align(bpage->crypt_buf_free, size);
}
return bpage->crypt_buf;
}
/********************************************************************//**
Decrypt page after it has been read from disk
*/
@@ -5752,96 +5802,58 @@ buf_page_decrypt_after_read(
if (bpage->offset == 0) {
/* File header pages are not encrypted */
ut_a(bpage->crypt_buf == NULL);
return (TRUE);
}
const byte* src_frame = bpage->crypt_buf != NULL ?
bpage->crypt_buf : dst_frame;
unsigned key_version =
mach_read_from_4(src_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION);
mach_read_from_4(dst_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION);
bool page_compressed = fil_page_is_compressed(dst_frame);
buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
if (key_version == 0) {
/* the page we read is unencrypted */
if (fil_page_is_compressed(dst_frame)) {
if (bpage->comp_buf_free == NULL) {
bpage->comp_buf_free = (byte *)malloc(UNIV_PAGE_SIZE*2);
// TODO: is 4k aligment enough ?
bpage->comp_buf = (byte*)ut_align(bpage->comp_buf_free, UNIV_PAGE_SIZE);
}
if (page_compressed) {
/* Find free slot from temporary memory array */
buf_tmp_buffer_t* slot = buf_pool_reserve_tmp_slot(buf_pool, page_compressed);
fil_decompress_page(bpage->comp_buf, dst_frame, size, NULL);
} else {
if (dst_frame != src_frame) {
/* but we had allocated a crypt_buf */
// TODO: Can this be avoided ?
memcpy(dst_frame, src_frame, size);
}
fil_decompress_page(slot->comp_buf,
dst_frame,
size,
&bpage->write_size);
/* Mark this slot as free */
slot->reserved = false;
}
} else {
/* the page we read is encrypted */
if (dst_frame == src_frame) {
/* but we had NOT allocated a crypt buf
* malloc a buffer, copy page to it
* and then decrypt from that into real page*/
bpage->crypt_buf_free = (byte *)malloc(UNIV_PAGE_SIZE*2);
// TODO: is 4k aligment enough ?
src_frame = bpage->crypt_buf = (byte*)ut_align(bpage->crypt_buf_free, UNIV_PAGE_SIZE);
memcpy(bpage->crypt_buf, dst_frame, size);
}
/* Find free slot from temporary memory array */
buf_tmp_buffer_t* slot = buf_pool_reserve_tmp_slot(buf_pool, page_compressed);
/* decrypt from src_frame to dst_frame */
memcpy(slot->crypt_buf, dst_frame, size);
/* decrypt from crypt_buf to dst_frame */
fil_space_decrypt(bpage->space,
src_frame, size, dst_frame);
slot->crypt_buf,
size,
dst_frame);
/* decompress from dst_frame to comp_buf and then copy to
buffer pool */
if (page_compressed) {
if (bpage->comp_buf_free == NULL) {
bpage->comp_buf_free = (byte *)malloc(UNIV_PAGE_SIZE*2);
// TODO: is 4k aligment enough ?
bpage->comp_buf = (byte*)ut_align(bpage->comp_buf_free, UNIV_PAGE_SIZE);
}
fil_decompress_page(bpage->comp_buf, dst_frame, size, NULL);
fil_decompress_page(slot->comp_buf,
dst_frame,
size,
&bpage->write_size);
}
/* Mark this slot as free */
slot->reserved = false;
}
bpage->key_version = key_version;
if (bpage->crypt_buf_free != NULL) {
// free temp page
free(bpage->crypt_buf_free);
bpage->crypt_buf = NULL;
bpage->crypt_buf_free = NULL;
}
if (bpage->comp_buf_free != NULL) {
// free temp page
free(bpage->comp_buf_free);
bpage->comp_buf = NULL;
bpage->comp_buf_free = NULL;
}
return (TRUE);
}
/********************************************************************//**
Release memory allocated for decryption
*/
void
buf_page_decrypt_cleanup(
/*=====================*/
buf_page_t* bpage) /*!< in/out: buffer page */
{
if (bpage->crypt_buf != NULL) {
free(bpage->crypt_buf_free);
bpage->crypt_buf = NULL;
bpage->crypt_buf_free = NULL;
}
}

View File

@@ -872,7 +872,7 @@ buf_dblwr_write_block_to_datafile(
0,
buf_block_get_page_no(block),
0,
UNIV_PAGE_SIZE,
bpage->real_size,
frame,
(void*) block,
(ulint *)&bpage->write_size);
@@ -1231,7 +1231,7 @@ retry:
TRX_SYS_SPACE, 0,
offset,
0,
UNIV_PAGE_SIZE,
bpage->real_size,
frame,
NULL,
0);

View File

@@ -909,7 +909,7 @@ buf_flush_write_block_low(
break;
}
frame = buf_page_encrypt_before_write(bpage, frame);
frame = buf_page_encrypt_before_write(bpage, frame, space_id);
if (!srv_use_doublewrite_buf || !buf_dblwr) {
fil_io(OS_FILE_WRITE | OS_AIO_SIMULATED_WAKE_LATER,
@@ -918,7 +918,7 @@ buf_flush_write_block_low(
zip_size,
buf_page_get_page_no(bpage),
0,
zip_size ? zip_size : UNIV_PAGE_SIZE,
zip_size ? zip_size : bpage->real_size,
frame,
bpage,
&bpage->write_size);
@@ -938,7 +938,7 @@ buf_flush_write_block_low(
zip_size,
buf_page_get_page_no(bpage),
0,
zip_size ? zip_size : UNIV_PAGE_SIZE,
zip_size ? zip_size : bpage->real_size,
frame,
bpage,
&bpage->write_size);

View File

@@ -176,7 +176,7 @@ buf_read_page_low(
ut_ad(buf_page_in_file(bpage));
byte* frame = buf_page_decrypt_before_read(bpage, zip_size);
byte* frame = zip_size ? bpage->zip.data : ((buf_block_t*) bpage)->frame;
if (sync) {
thd_wait_begin(NULL, THD_WAIT_DISKIO);
@@ -202,7 +202,6 @@ buf_read_page_low(
}
if (*err != DB_SUCCESS) {
buf_page_decrypt_cleanup(bpage);
if (ignore_nonexistent_pages || *err == DB_TABLESPACE_DELETED) {
buf_read_page_handle_error(bpage);
return(0);

View File

@@ -319,6 +319,7 @@ fil_space_create_crypt_data()
&crypt_data->mutex, SYNC_NO_ORDER_CHECK);
crypt_data->iv_length = iv_length;
my_random_bytes(crypt_data->iv, iv_length);
crypt_data->encryption = FIL_SPACE_ENCRYPTION_DEFAULT;
return crypt_data;
}
@@ -421,6 +422,9 @@ fil_space_read_crypt_data(
uint min_key_version = mach_read_from_4
(page + offset + MAGIC_SZ + 2 + iv_length);
fil_encryption_t encryption = (fil_encryption_t)mach_read_from_1(
page + offset + MAGIC_SZ + 2 + iv_length + 4);
const uint sz = sizeof(fil_space_crypt_t) + iv_length;
fil_space_crypt_t* crypt_data = static_cast<fil_space_crypt_t*>(
malloc(sz));
@@ -429,6 +433,7 @@ fil_space_read_crypt_data(
crypt_data->type = type;
crypt_data->min_key_version = min_key_version;
crypt_data->page0_offset = offset;
crypt_data->encryption = encryption;
mutex_create(fil_crypt_data_mutex_key,
&crypt_data->mutex, SYNC_NO_ORDER_CHECK);
crypt_data->iv_length = iv_length;
@@ -474,8 +479,9 @@ fil_space_write_crypt_data_low(
page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
const uint len = crypt_data->iv_length;
const uint min_key_version = crypt_data->min_key_version;
const fil_encryption_t encryption = crypt_data->encryption;
crypt_data->page0_offset = offset;
ut_a(2 + len + 4 + MAGIC_SZ < maxsize);
ut_a(2 + len + 4 + 1 + MAGIC_SZ < maxsize);
/*
redo log this as bytewise updates to page 0
@@ -489,8 +495,10 @@ fil_space_write_crypt_data_low(
mtr);
mlog_write_ulint(page + offset + MAGIC_SZ + 2 + len, min_key_version,
MLOG_4BYTES, mtr);
mlog_write_ulint(page + offset + MAGIC_SZ + 2 + len + 4, encryption,
MLOG_1BYTE, mtr);
byte* log_ptr = mlog_open(mtr, 11 + 12 + len);
byte* log_ptr = mlog_open(mtr, 11 + 13 + len);
if (log_ptr != NULL) {
log_ptr = mlog_write_initial_log_record_fast(
@@ -507,6 +515,8 @@ fil_space_write_crypt_data_low(
log_ptr += 1;
mach_write_to_4(log_ptr, min_key_version);
log_ptr += 4;
mach_write_to_1(log_ptr, encryption);
log_ptr += 1;
mlog_close(mtr, log_ptr);
mlog_catenate_string(mtr, crypt_data->iv, len);
@@ -555,7 +565,8 @@ fil_parse_write_crypt_data(
2 + // size of offset
1 + // size of type
1 + // size of iv-len
4; // size of min_key_version
4 + // size of min_key_version
1; // fil_encryption_t
if (end_ptr - ptr < entry_size){
return NULL;
@@ -582,9 +593,17 @@ fil_parse_write_crypt_data(
return NULL;
}
fil_encryption_t encryption = (fil_encryption_t)mach_read_from_1(ptr);
ptr +=1;
if (end_ptr - ptr < len) {
return NULL;
}
fil_space_crypt_t* crypt_data = fil_space_create_crypt_data();
crypt_data->page0_offset = offset;
crypt_data->min_key_version = min_key_version;
crypt_data->encryption = encryption;
memcpy(crypt_data->iv, ptr, len);
ptr += len;
@@ -610,7 +629,8 @@ fil_space_clear_crypt_data(
1 + // type
1 + // len
len + // iv
4; // min key version
4 + // min key version
1; // fil_encryption_t
memset(page + offset, 0, size);
}
@@ -674,13 +694,11 @@ fil_space_encrypt(
const byte* src_frame, /*!< in: Source page to be encrypted */
ulint zip_size, /*!< in: compressed size if
row_format compressed */
byte* dst_frame, /*!< in: outbut buffer */
ulint encryption_key) /*!< in: encryption key id if page
encrypted */
byte* dst_frame) /*!< in: outbut buffer */
{
fil_space_crypt_t* crypt_data=NULL;
ulint page_size = (zip_size) ? zip_size : UNIV_PAGE_SIZE;
uint key_version = (uint)encryption_key;
uint key_version;
unsigned char key[MY_AES_MAX_KEY_LENGTH];
uint key_length=MY_AES_MAX_KEY_LENGTH;
uint aes_method;
@@ -699,6 +717,7 @@ fil_space_encrypt(
/* Get crypt data from file space */
crypt_data = fil_space_get_crypt_data(space);
key_version = crypt_data->keys[0].key_id;
if (crypt_data == NULL) {
//TODO: Is this really needed ?
@@ -808,6 +827,10 @@ fil_space_check_encryption_read(
return false;
}
if (crypt_data->encryption == FIL_SPACE_ENCRYPTION_OFF) {
return false;
}
return true;
}
@@ -1352,6 +1375,11 @@ fil_crypt_space_needs_rotation(
mutex_enter(&crypt_data->mutex);
do {
if (crypt_data->encryption == FIL_SPACE_ENCRYPTION_OFF) {
/* This space is unencrypted by user request */
break;
}
/* prevent threads from starting to rotate space */
if (crypt_data->rotate_state.starting) {
/* recheck this space later */

View File

@@ -5543,6 +5543,74 @@ fil_report_invalid_page_access(
(ulong) byte_offset, (ulong) len, (ulong) type);
}
/********************************************************************//**
Find correct node from file space
@return node */
static
fil_node_t*
fil_space_get_node(
fil_space_t* space, /*!< in: file spage */
ulint space_id, /*!< in: space id */
ulint* block_offset, /*!< in/out: offset in number of blocks */
ulint byte_offset, /*!< in: remainder of offset in bytes; in
aio this must be divisible by the OS block
size */
ulint len) /*!< in: how many bytes to read or write; this
must not cross a file boundary; in aio this
must be a block size multiple */
{
fil_node_t* node;
ut_ad(mutex_own(&fil_system->mutex));
node = UT_LIST_GET_FIRST(space->chain);
for (;;) {
if (node == NULL) {
return(NULL);
} else if (fil_is_user_tablespace_id(space->id)
&& node->size == 0) {
/* We do not know the size of a single-table tablespace
before we open the file */
break;
} else if (node->size > *block_offset) {
/* Found! */
break;
} else {
*block_offset -= node->size;
node = UT_LIST_GET_NEXT(chain, node);
}
}
return (node);
}
/********************************************************************//**
Return block size of node in file space
@return file block size */
UNIV_INTERN
ulint
fil_space_get_block_size(
/*=====================*/
ulint space_id,
ulint block_offset,
ulint len)
{
ulint block_size = 512;
fil_space_t* space = fil_space_get_space(space_id);
if (space) {
mutex_enter(&fil_system->mutex);
fil_node_t* node = fil_space_get_node(space, space_id, &block_offset, 0, len);
mutex_exit(&fil_system->mutex);
if (node) {
block_size = node->file_block_size;
}
}
return block_size;
}
/********************************************************************//**
Reads or writes data. This operation is asynchronous (aio).
@return DB_SUCCESS, or DB_TABLESPACE_DELETED if we are trying to do
@@ -5589,7 +5657,7 @@ fil_io(
ulint is_log;
ulint wake_later;
os_offset_t offset;
ibool ignore_nonexistent_pages;
bool ignore_nonexistent_pages;
is_log = type & OS_FILE_LOG;
type = type & ~OS_FILE_LOG;
@@ -5674,34 +5742,18 @@ fil_io(
ut_ad(mode != OS_AIO_IBUF || space->purpose == FIL_TABLESPACE);
node = UT_LIST_GET_FIRST(space->chain);
node = fil_space_get_node(space, space_id, &block_offset, byte_offset, len);
for (;;) {
if (node == NULL) {
if (ignore_nonexistent_pages) {
mutex_exit(&fil_system->mutex);
return(DB_ERROR);
}
fil_report_invalid_page_access(
if (!node) {
if (ignore_nonexistent_pages) {
mutex_exit(&fil_system->mutex);
return(DB_ERROR);
}
fil_report_invalid_page_access(
block_offset, space_id, space->name,
byte_offset, len, type);
ut_error;
} else if (fil_is_user_tablespace_id(space->id)
&& node->size == 0) {
/* We do not know the size of a single-table tablespace
before we open the file */
break;
} else if (node->size > block_offset) {
/* Found! */
break;
} else {
block_offset -= node->size;
node = UT_LIST_GET_NEXT(chain, node);
}
ut_error;
}
/* Open file if closed */

View File

@@ -566,10 +566,10 @@ ha_create_table_option innodb_table_option_list[]=
HA_TOPTION_NUMBER("PAGE_COMPRESSION_LEVEL", page_compression_level, 0, 1, 9, 1),
/* With this option user can enable atomic writes feature for this table */
HA_TOPTION_ENUM("ATOMIC_WRITES", atomic_writes, "DEFAULT,ON,OFF", 0),
/* With this option the user can enable page encryption for the table */
HA_TOPTION_BOOL("PAGE_ENCRYPTION", page_encryption, 0),
/* With this option the user can enable encryption for the table */
HA_TOPTION_ENUM("ENCRYPTION", encryption, "DEFAULT, ON, OFF", 0),
/* With this option the user defines the key identifier using for the encryption */
HA_TOPTION_NUMBER("PAGE_ENCRYPTION_KEY", page_encryption_key, 0, 1, 255, 1),
HA_TOPTION_NUMBER("ENCRYPTION_KEY", encryption_key, 0, 1, UINT_MAX32, 1),
HA_TOPTION_END
};
@@ -11285,20 +11285,21 @@ ha_innobase::check_table_options(
enum row_type row_format = table->s->row_type;
ha_table_option_struct *options= table->s->option_struct;
atomic_writes_t awrites = (atomic_writes_t)options->atomic_writes;
fil_encryption_t encrypt = (fil_encryption_t)options->encryption;
if (options->page_encryption) {
if (encrypt == FIL_SPACE_ENCRYPTION_ON) {
if (srv_encrypt_tables) {
push_warning(
thd, Sql_condition::WARN_LEVEL_WARN,
HA_WRONG_CREATE_OPTION,
"InnoDB: PAGE_ENCRYPTION not available if innodb_encrypt_tables=ON");
"InnoDB: ENCRYPTION not available if innodb_encrypt_tables=ON");
return "INNODB_ENCRYPT_TABLES";
}
if (!use_tablespace) {
push_warning(
thd, Sql_condition::WARN_LEVEL_WARN,
HA_WRONG_CREATE_OPTION,
"InnoDB: PAGE_ENCRYPTION requires"
"InnoDB: ENCRYPTION requires"
" innodb_file_per_table.");
return "PAGE_ENCRYPTION";
}
@@ -11307,14 +11308,6 @@ ha_innobase::check_table_options(
/* Check page compression requirements */
if (options->page_compressed) {
if (srv_encrypt_tables) {
push_warning(
thd, Sql_condition::WARN_LEVEL_WARN,
HA_WRONG_CREATE_OPTION,
"InnoDB: PAGE_COMPRESSION not available if innodb_encrypt_tables=ON");
return "PAGE_COMPRESSED";
}
if (row_format == ROW_TYPE_COMPRESSED) {
push_warning(
thd, Sql_condition::WARN_LEVEL_WARN,
@@ -11384,29 +11377,29 @@ ha_innobase::check_table_options(
}
}
if (options->page_encryption_key != 0) {
if (options->page_encryption == false) {
if (options->encryption_key != 0) {
if (options->encryption == FIL_SPACE_ENCRYPTION_OFF) {
/* ignore this to allow alter table without changing page_encryption_key ...*/
}
if (options->page_encryption_key < 1 || options->page_encryption_key > 255) {
if (options->encryption_key < 1) {
push_warning_printf(
thd, Sql_condition::WARN_LEVEL_WARN,
HA_WRONG_CREATE_OPTION,
"InnoDB: invalid PAGE_ENCRYPTION_KEY = %lu."
" Valid values are [1..255]",
options->page_encryption_key);
return "PAGE_ENCRYPTION_KEY";
"InnoDB: invalid ENCRYPTION_KEY = %lu."
" Valid values are [1..INT32_MAX]",
options->encryption_key);
return "ENCRYPTION_KEY";
}
if (!has_encryption_key(options->page_encryption_key)) {
if (!has_encryption_key(options->encryption_key)) {
push_warning_printf(
thd, Sql_condition::WARN_LEVEL_WARN,
HA_WRONG_CREATE_OPTION,
"InnoDB: PAGE_ENCRYPTION_KEY encryption key %lu not available",
options->page_encryption_key
"InnoDB: ENCRYPTION_KEY encryption key %lu not available",
options->encryption_key
);
return "PAGE_ENCRYPTION_KEY";
return "ENCRYPTION_KEY";
}
}
@@ -11467,6 +11460,11 @@ ha_innobase::create(
const char* stmt;
size_t stmt_len;
/* Cache table options */
ha_table_option_struct *options= table->s->option_struct;
fil_encryption_t encrypt = (fil_encryption_t)options->encryption;
ulint key_id = (options->encryption_key == 0) ? srv_default_encryption_key :
options->encryption_key;
DBUG_ENTER("ha_innobase::create");
@@ -11706,6 +11704,18 @@ ha_innobase::create(
innobase_commit_low(trx);
/* If user has requested that table should be encrypted or table
should remain as unencrypted store crypt data */
if (encrypt == FIL_SPACE_ENCRYPTION_ON || encrypt == FIL_SPACE_ENCRYPTION_OFF) {
ulint maxsize;
ulint zip_size = fil_space_get_zip_size(innobase_table->space);
fil_space_crypt_t* crypt_data = fil_space_create_crypt_data();
crypt_data->page0_offset = fsp_header_get_crypt_offset(zip_size, &maxsize);
crypt_data->keys[0].key_id = key_id;
crypt_data->encryption = encrypt;
fil_space_set_crypt_data(innobase_table->space, crypt_data);
}
row_mysql_unlock_data_dictionary(trx);
/* Flush the log to reduce probability that the .frm files and
@@ -19146,12 +19156,12 @@ static MYSQL_SYSVAR_UINT(encryption_rotation_iops, srv_n_fil_crypt_iops,
innodb_encryption_rotation_iops_update,
srv_n_fil_crypt_iops, 0, UINT_MAX32, 0);
static MYSQL_SYSVAR_UINT(default_page_encryption_key, srv_default_page_encryption_key,
static MYSQL_SYSVAR_UINT(default_encryption_key, srv_default_encryption_key,
PLUGIN_VAR_RQCMDARG,
"Encryption key used for page encryption.",
"Default encryption key used for table encryption.",
NULL,
NULL,
FIL_DEFAULT_ENCRYPTION_KEY, 1, 255, 0);
FIL_DEFAULT_ENCRYPTION_KEY, 1, UINT_MAX32, 0);
static MYSQL_SYSVAR_BOOL(scrub_log, srv_scrub_log,
PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
@@ -19420,7 +19430,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(scrub_log),
MYSQL_SYSVAR(scrub_log_interval),
MYSQL_SYSVAR(encrypt_log),
MYSQL_SYSVAR(default_page_encryption_key),
MYSQL_SYSVAR(default_encryption_key),
/* Scrubing feature */
MYSQL_SYSVAR(immediate_scrub_data_uncompressed),

View File

@@ -70,8 +70,8 @@ struct ha_table_option_struct
srv_use_atomic_writes=1.
Atomic writes are not used if
value OFF.*/
bool page_encryption; /*!< Flag for an encrypted table */
int page_encryption_key; /*!< ID of the encryption key */
uint encryption; /*!< DEFAULT, ON, OFF */
int encryption_key; /*!< encryption key id*/
};

View File

@@ -278,8 +278,8 @@ ha_innobase::check_if_supported_inplace_alter(
DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
}
if (new_options->page_encryption != old_options->page_encryption ||
new_options->page_encryption_key != old_options->page_encryption_key) {
if (new_options->encryption != old_options->encryption ||
new_options->encryption_key != old_options->encryption_key) {
ha_alter_info->unsupported_reason = innobase_get_err_msg(
ER_ALTER_OPERATION_NOT_SUPPORTED_REASON);
DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);

View File

@@ -1445,16 +1445,19 @@ buf_flush_update_zip_checksum(
The hook that is called just before a page is written to disk.
The function encrypts the content of the page and returns a pointer
to a frame that will be written instead of the real frame. */
UNIV_INTERN
byte*
buf_page_encrypt_before_write(
/*==========================*/
buf_page_t* page, /*!< in/out: buffer page to be flushed */
const byte* frame);
const byte* frame,
ulint space_id);
/**********************************************************************
The hook that is called after page is written to disk.
The function releases any resources needed for encryption that was allocated
in buf_page_encrypt_before_write */
UNIV_INTERN
ibool
buf_page_encrypt_after_write(
/*=========================*/
@@ -1464,6 +1467,7 @@ buf_page_encrypt_after_write(
The hook that is called just before a page is read from disk.
The function allocates memory that is used to temporarily store disk content
before getting decrypted */
UNIV_INTERN
byte*
buf_page_decrypt_before_read(
/*=========================*/
@@ -1474,19 +1478,35 @@ buf_page_decrypt_before_read(
The hook that is called just after a page is read from disk.
The function decrypt disk content into buf_page_t and releases the
temporary buffer that was allocated in buf_page_decrypt_before_read */
UNIV_INTERN
ibool
buf_page_decrypt_after_read(
/*========================*/
buf_page_t* page); /*!< in/out: buffer page read from disk */
/********************************************************************//**
Release memory allocated for page decryption.
Only used in scenarios where read fails, e.g due to tablespace being dropped */
void
buf_page_decrypt_cleanup(
/*=====================*/
buf_page_t* page); /*!< in/out: buffer page read from disk */
/** @brief The temporary memory structure.
NOTE! The definition appears here only for other modules of this
directory (buf) to see it. Do not use from outside! */
typedef struct {
bool reserved; /*!< true if this slot is reserved
*/
#ifdef HAVE_LZO
byte* lzo_mem; /*!< Temporal memory used by LZO */
#endif
byte* crypt_buf; /*!< for encryption the data needs to be
copied to a separate buffer before it's
encrypted&written. this as a page can be
read while it's being flushed */
byte* crypt_buf_free; /*!< for encryption, allocated buffer
that is then alligned */
byte* comp_buf; /*!< for compression we need
temporal buffer because page
can be read while it's being flushed */
byte* comp_buf_free; /*!< for compression, allocated
buffer that is then alligned */
} buf_tmp_buffer_t;
/** The common buffer control block structure
for compressed and uncompressed frames */
@@ -1559,20 +1579,15 @@ struct buf_page_t{
operation needed. */
unsigned key_version; /*!< key version for this block */
byte* crypt_buf; /*!< for encryption the data needs to be
copied to a separate buffer before it's
encrypted&written. this as a page can be
read while it's being flushed */
byte* crypt_buf_free; /*!< for encryption, allocated buffer
that is then alligned */
byte* comp_buf; /*!< for compression we need
temporal buffer because page
can be read while it's being flushed */
byte* comp_buf_free; /*!< for compression, allocated
buffer that is then alligned */
bool encrypt_later; /*!< should we encrypt the page
at os0file.cc ? */
ulint real_size; /*!< Real size of the page
Normal pages == UNIV_PAGE_SIZE
page compressed pages, payload
size alligned to sector boundary.
*/
buf_tmp_buffer_t* slot; /*!< Slot for temporary memory
used for encryption/compression
or NULL */
#ifndef UNIV_HOTBACKUP
buf_page_t* hash; /*!< node used in chaining to
buf_pool->page_hash or
@@ -2017,6 +2032,17 @@ struct buf_buddy_stat_t {
ib_uint64_t relocated_usec;
};
/** @brief The temporary memory array structure.
NOTE! The definition appears here only for other modules of this
directory (buf) to see it. Do not use from outside! */
typedef struct {
ulint n_slots; /*!< Total number of slots */
buf_tmp_buffer_t *slots; /*!< Pointer to the slots in the
array */
} buf_tmp_array_t;
/** @brief The buffer pool structure.
NOTE! The definition appears here only for other modules of this
@@ -2200,6 +2226,10 @@ struct buf_pool_t{
pool watches. Protected by
buf_pool->mutex. */
buf_tmp_array_t* tmp_arr;
/*!< Array for temporal memory
used in compression and encryption */
#if BUF_BUDDY_LOW > UNIV_ZIP_SIZE_MIN
# error "BUF_BUDDY_LOW > UNIV_ZIP_SIZE_MIN"
#endif

View File

@@ -1464,28 +1464,15 @@ buf_get_nth_chunk_block(
return(chunk->blocks);
}
/********************************************************************//**
Get crypt buffer. */
UNIV_INLINE
byte*
buf_page_get_crypt_buffer(
/*=========================*/
const buf_page_t* bpage) /*!< in: buffer pool page */
{
return bpage->crypt_buf;
}
/********************************************************************//**
Get buf frame. */
UNIV_INLINE
void *
buf_page_get_frame(
/*=========================*/
/*===============*/
const buf_page_t* bpage) /*!< in: buffer pool page */
{
if (bpage->crypt_buf) {
return buf_page_get_crypt_buffer(bpage);
} else if (bpage->zip.data) {
if (bpage->zip.data) {
return bpage->zip.data;
} else {
return ((buf_block_t*) bpage)->frame;

View File

@@ -37,6 +37,14 @@ Created 04/01/2015 Jan Lindström
/* This key will be used if nothing else is given */
#define FIL_DEFAULT_ENCRYPTION_KEY 1
/** Enum values for encryption table option */
typedef enum {
FIL_SPACE_ENCRYPTION_DEFAULT = 0, /* Tablespace encrypted if
srv_encrypt_tables = ON */
FIL_SPACE_ENCRYPTION_ON = 1, /* Tablespace is encrypted always */
FIL_SPACE_ENCRYPTION_OFF = 2 /* Tablespace is not encrypted */
} fil_encryption_t;
/**
* CRYPT_SCHEME_UNENCRYPTED
*
@@ -67,6 +75,8 @@ struct key_struct
{
uint key_version; /*!< Key version used as
identifier */
uint key_id; /*1< Key id used as
identifier */
byte key[MY_AES_MAX_KEY_LENGTH]; /*!< Cached L or key */
uint key_length; /*!< Key length */
};
@@ -95,6 +105,7 @@ struct fil_space_crypt_struct
key_struct keys[3]; // cached L = AES_ECB(KEY, IV)
uint min_key_version; // min key version for this space
ulint page0_offset; // byte offset on page 0 for crypt data
fil_encryption_t encryption; // Encryption setup
ib_mutex_t mutex; // mutex protecting following variables
bool closing; // is tablespace being closed
@@ -227,9 +238,7 @@ fil_space_encrypt(
lsn_t lsn, /*!< in: page lsn */
const byte* src_frame,/*!< in: page frame */
ulint size, /*!< in: size of data to encrypt */
byte* dst_frame, /*!< in: where to encrypt to */
ulint page_encryption_key); /*!< in: page encryption key id if page
encrypted */
byte* dst_frame); /*!< in: where to encrypt to */
/*********************************************************************
Decrypt buffer page */

View File

@@ -1272,6 +1272,16 @@ ulint
fil_get_next_space(
ulint id); /*!< in: space id */
/*******************************************************************//**
Returns the block size of the file space
@return block size */
UNIV_INTERN
ulint
fil_space_get_block_size(
/*=====================*/
ulint id, /*!< in: space id */
ulint offset, /*!< in: page offset */
ulint len); /*!< in: page len */
#endif

View File

@@ -562,8 +562,8 @@ that semaphore times out in InnoDB */
#define DEFAULT_SRV_FATAL_SEMAPHORE_TIMEOUT 600
extern ulong srv_fatal_semaphore_wait_threshold;
/** Default encryption key used for page encryption */
extern uint srv_default_page_encryption_key;
/** Default encryption key used for tablespace encryption */
extern uint srv_default_encryption_key;
/** Enable semaphore request instrumentation */
extern my_bool srv_instrument_semaphores;

View File

@@ -242,7 +242,6 @@ struct os_aio_slot_t{
int n_bytes; /* bytes written/read. */
int ret; /* AIO return code */
#endif /* WIN_ASYNC_IO */
byte *lzo_mem; /* Temporal memory used by LZO */
};
/** The asynchronous i/o array structure */

View File

@@ -523,8 +523,8 @@ thread ensures that we flush the log files at least once per
second. */
static time_t srv_last_log_flush_time;
/** Default encryption key used for page encryption */
UNIV_INTERN uint srv_default_page_encryption_key = FIL_DEFAULT_ENCRYPTION_KEY;
/** Default encryption key used for tablespace encryption */
UNIV_INTERN uint srv_default_encryption_key = FIL_DEFAULT_ENCRYPTION_KEY;
/** Enable semaphore request instrumentation */
UNIV_INTERN my_bool srv_instrument_semaphores = FALSE;

View File

@@ -95,6 +95,14 @@ _increment_page_get_statistics(buf_block_t* block, trx_t* trx)
return;
}
#ifdef HAVE_LZO
#include "lzo/lzo1x.h"
#endif
/* Number of temporary slots used for encryption/compression
memory allocation before/after I/O operations */
#define BUF_MAX_TMP_SLOTS 200
/*
IMPLEMENTATION OF THE BUFFER POOL
=================================
@@ -1077,15 +1085,11 @@ buf_block_init(
block->page.state = BUF_BLOCK_NOT_USED;
block->page.buf_fix_count = 0;
block->page.io_fix = BUF_IO_NONE;
block->page.crypt_buf = NULL;
block->page.crypt_buf_free = NULL;
block->page.comp_buf = NULL;
block->page.comp_buf_free = NULL;
block->page.key_version = 0;
block->page.encrypt_later = false;
block->page.real_size = 0;
block->page.write_size = 0;
block->modify_clock = 0;
block->page.slot = NULL;
#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
block->page.file_page_was_freed = FALSE;
@@ -1438,6 +1442,11 @@ buf_pool_init_instance(
/* All fields are initialized by mem_zalloc(). */
/* Initialize the temporal memory array and slots */
buf_pool->tmp_arr = (buf_tmp_array_t *)mem_zalloc(sizeof(buf_tmp_array_t));
buf_pool->tmp_arr->n_slots = BUF_MAX_TMP_SLOTS;
buf_pool->tmp_arr->slots = (buf_tmp_buffer_t*)mem_zalloc(sizeof(buf_tmp_buffer_t) * BUF_MAX_TMP_SLOTS);
buf_pool->try_LRU_scan = TRUE;
return(DB_SUCCESS);
@@ -1489,6 +1498,9 @@ buf_pool_free_instance(
ha_clear(buf_pool->page_hash);
hash_table_free(buf_pool->page_hash);
hash_table_free(buf_pool->zip_hash);
mem_free(buf_pool->tmp_arr->slots);
mem_free(buf_pool->tmp_arr);
}
/********************************************************************//**
@@ -3574,12 +3586,8 @@ buf_page_init_low(
bpage->newest_modification = 0;
bpage->oldest_modification = 0;
bpage->write_size = 0;
bpage->crypt_buf = NULL;
bpage->crypt_buf_free = NULL;
bpage->comp_buf = NULL;
bpage->comp_buf_free = NULL;
bpage->key_version = 0;
bpage->encrypt_later = false;
bpage->real_size = 0;
HASH_INVALIDATE(bpage, hash);
bpage->is_corrupt = FALSE;
@@ -4498,7 +4506,11 @@ corrupt:
}
} else {
/* io_type == BUF_IO_WRITE */
buf_page_encrypt_after_write(bpage);
if (bpage->slot) {
/* Mark slot free */
bpage->slot->reserved = false;
bpage->slot = NULL;
}
}
if (io_type == BUF_IO_WRITE
@@ -5778,6 +5790,60 @@ buf_pool_mutex_exit(
mutex_exit(&buf_pool->LRU_list_mutex);
}
/********************************************************************//**
Reserve unused slot from temporary memory array and allocate necessary
temporary memory if not yet allocated.
@return reserved slot */
buf_tmp_buffer_t*
buf_pool_reserve_tmp_slot(
/*======================*/
buf_pool_t* buf_pool, /*!< in: buffer pool where to
reserve */
bool compressed) /*!< in: is file space compressed */
{
buf_tmp_buffer_t *free_slot=NULL;
/* Array is protected by buf_pool mutex */
buf_pool_mutex_enter(buf_pool);
for(ulint i = 0; i < buf_pool->tmp_arr->n_slots; i++) {
buf_tmp_buffer_t *slot = &buf_pool->tmp_arr->slots[i];
if(slot->reserved == false) {
free_slot = slot;
break;
}
}
/* We assume that free slot is found */
ut_a(free_slot != NULL);
free_slot->reserved = true;
/* Now that we have reserved this slot we can release
buf_pool mutex */
buf_pool_mutex_exit(buf_pool);
/* Allocate temporary memory for encryption/decryption */
if (free_slot->crypt_buf_free == NULL) {
free_slot->crypt_buf_free = static_cast<byte *>(ut_malloc(UNIV_PAGE_SIZE*2));
free_slot->crypt_buf = static_cast<byte *>(ut_align(free_slot->crypt_buf_free, UNIV_PAGE_SIZE));
memset(free_slot->crypt_buf_free, 0, UNIV_PAGE_SIZE *2);
}
/* For page compressed tables allocate temporary memory for
compression/decompression */
if (compressed && free_slot->comp_buf_free == NULL) {
free_slot->comp_buf_free = static_cast<byte *>(ut_malloc(UNIV_PAGE_SIZE*2));
free_slot->comp_buf = static_cast<byte *>(ut_align(free_slot->comp_buf_free, UNIV_PAGE_SIZE));
memset(free_slot->comp_buf_free, 0, UNIV_PAGE_SIZE *2);
#ifdef HAVE_LZO
free_slot->lzo_mem = static_cast<byte *>(ut_malloc(LZO1X_1_15_MEM_COMPRESS));
memset(free_slot->lzo_mem, 0, LZO1X_1_15_MEM_COMPRESS);
#endif
}
return (free_slot);
}
/********************************************************************//**
Encrypts a buffer page right before it's flushed to disk
*/
@@ -5785,11 +5851,17 @@ byte*
buf_page_encrypt_before_write(
/*==========================*/
buf_page_t* bpage, /*!< in/out: buffer page to be flushed */
const byte* src_frame) /*!< in: src frame */
const byte* src_frame, /*!< in: src frame */
ulint space_id) /*!< in: space id */
{
bpage->encrypt_later = false;
fil_space_crypt_t* crypt_data = fil_space_get_crypt_data(space_id);
if (srv_encrypt_tables == FALSE) {
if (crypt_data != NULL && crypt_data->encryption == FIL_SPACE_ENCRYPTION_OFF) {
/* Encryption is disabled */
return const_cast<byte*>(src_frame);
}
if (!srv_encrypt_tables && (crypt_data == NULL || crypt_data->encryption == FIL_SPACE_ENCRYPTION_DEFAULT)) {
/* Encryption is disabled */
return const_cast<byte*>(src_frame);
}
@@ -5814,103 +5886,63 @@ buf_page_encrypt_before_write(
ulint zip_size = buf_page_get_zip_size(bpage);
ulint page_size = (zip_size) ? zip_size : UNIV_PAGE_SIZE;
buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
bool page_compressed = fil_space_is_page_compressed(bpage->space);
/**
* TODO(jonaso): figure out more clever malloc strategy
*
* This implementation does a malloc/free per iop for encrypted
* tablespaces. Alternative strategies that have been considered are
*
* 1) use buf_block_alloc (i.e alloc from buffer pool)
* this does not work as buf_block_alloc will then be called
* when needing to flush a page, which might be triggered
* due to shortage of memory in buffer pool
* 2) allocate a buffer per fil_node_t
* this would break abstraction layers and has therfore not been
* considered a lot.
*/
/* Find free slot from temporary memory array */
buf_tmp_buffer_t* slot = buf_pool_reserve_tmp_slot(buf_pool, page_compressed);
bpage->slot = slot;
if (bpage->crypt_buf_free == NULL) {
bpage->crypt_buf_free = (byte*)malloc(page_size*2);
// TODO: Is 4k aligment enough ?
bpage->crypt_buf = (byte *)ut_align(bpage->crypt_buf_free, page_size);
}
byte *dst_frame = slot->crypt_buf;
byte *dst_frame = bpage->crypt_buf;
if (!fil_space_is_page_compressed(bpage->space)) {
// encrypt page content
fil_space_encrypt(bpage->space, bpage->offset,
bpage->newest_modification,
src_frame, zip_size, dst_frame, 0);
if (!page_compressed) {
/* Encrypt page content */
fil_space_encrypt(bpage->space,
bpage->offset,
bpage->newest_modification,
src_frame,
zip_size,
dst_frame);
unsigned key_version =
mach_read_from_4(dst_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION);
ut_ad(key_version == 0 || key_version >= bpage->key_version);
bpage->key_version = key_version;
bpage->real_size = zip_size;
} else {
/** Compression and encryption is done later at os0file.cc */
bpage->encrypt_later = true;
dst_frame = (byte *)src_frame;
/* First we compress the page content */
ulint out_len = 0;
ulint block_size = fil_space_get_block_size(bpage->space, bpage->offset, page_size);
byte *tmp = fil_compress_page(bpage->space,
(byte *)src_frame,
slot->comp_buf,
page_size,
fil_space_get_page_compression_level(bpage->space),
block_size,
&out_len,
#ifdef HAVE_LZO
slot->lzo_mem
#else
NULL
#endif
);
bpage->real_size = out_len;
/* And then we encrypt the page content */
fil_space_encrypt(bpage->space,
bpage->offset,
bpage->newest_modification,
tmp,
zip_size,
dst_frame);
}
// return dst_frame which will be written
return dst_frame;
}
/********************************************************************//**
Release memory after encrypted page has been written to disk
*/
ibool
buf_page_encrypt_after_write(
/*=========================*/
buf_page_t* bpage) /*!< in/out: buffer page flushed */
{
if (bpage->crypt_buf_free != NULL) {
free(bpage->crypt_buf_free);
bpage->crypt_buf_free = NULL;
bpage->crypt_buf = NULL;
}
if (bpage->comp_buf_free != NULL) {
free(bpage->comp_buf_free);
bpage->comp_buf_free = NULL;
bpage->comp_buf = NULL;
}
return (TRUE);
}
/********************************************************************//**
Allocates memory to read in an encrypted page
*/
byte*
buf_page_decrypt_before_read(
/*=========================*/
buf_page_t* bpage, /*!< in/out: buffer page to be read */
ulint zip_size) /*!< in: compressed page size, or 0 */
{
ulint size = (zip_size) ? zip_size : UNIV_PAGE_SIZE;
/*
Here we only need to allocate space for not header pages
in case of file space encryption. Table encryption is handled
later.
*/
if (!srv_encrypt_tables || bpage->offset == 0 ||
fil_space_check_encryption_read(bpage->space) == false)
return zip_size ? bpage->zip.data : ((buf_block_t*) bpage)->frame;
if (bpage->crypt_buf_free == NULL)
{
// allocate buffer to read data into
bpage->crypt_buf_free = (byte*)malloc(size*2);
// TODO: Is 4K aligment enough ?
bpage->crypt_buf = (byte*)ut_align(bpage->crypt_buf_free, size);
}
return bpage->crypt_buf;
}
/********************************************************************//**
Decrypt page after it has been read from disk
*/
@@ -5928,92 +5960,51 @@ buf_page_decrypt_after_read(
if (bpage->offset == 0) {
/* File header pages are not encrypted */
ut_a(bpage->crypt_buf == NULL);
return (TRUE);
}
const byte* src_frame = bpage->crypt_buf != NULL ?
bpage->crypt_buf : dst_frame;
unsigned key_version =
mach_read_from_4(src_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION);
mach_read_from_4(dst_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION);
bool page_compressed = fil_page_is_compressed(dst_frame);
buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
if (key_version == 0) {
/* the page we read is unencrypted */
if (fil_page_is_compressed(dst_frame)) {
if (bpage->comp_buf_free == NULL) {
bpage->comp_buf_free = (byte *)malloc(UNIV_PAGE_SIZE*2);
// TODO: is 4k aligment enough ?
bpage->comp_buf = (byte*)ut_align(bpage->comp_buf_free, UNIV_PAGE_SIZE);
}
fil_decompress_page(bpage->comp_buf, dst_frame, size, NULL);
} else {
if (dst_frame != src_frame) {
/* but we had allocated a crypt_buf */
// TODO: Can this be avoided ?
memcpy(dst_frame, src_frame, size);
}
}
} else {
/* the page we read is encrypted */
if (dst_frame == src_frame) {
/* but we had NOT allocated a crypt buf
* malloc a buffer, copy page to it
* and then decrypt from that into real page*/
bpage->crypt_buf_free = (byte *)malloc(UNIV_PAGE_SIZE*2);
// TODO: is 4k aligment enough ?
src_frame = bpage->crypt_buf = (byte*)ut_align(bpage->crypt_buf_free, UNIV_PAGE_SIZE);
memcpy(bpage->crypt_buf, dst_frame, size);
}
/* decrypt from src_frame to dst_frame */
fil_space_decrypt(bpage->space,
src_frame, size, dst_frame);
/* decompress from dst_frame to comp_buf and then copy to
buffer pool */
if (page_compressed) {
if (bpage->comp_buf_free == NULL) {
bpage->comp_buf_free = (byte *)malloc(UNIV_PAGE_SIZE*2);
// TODO: is 4k aligment enough ?
bpage->comp_buf = (byte*)ut_align(bpage->comp_buf_free, UNIV_PAGE_SIZE);
}
/* Find free slot from temporary memory array */
buf_tmp_buffer_t* slot = buf_pool_reserve_tmp_slot(buf_pool, page_compressed);
fil_decompress_page(bpage->comp_buf, dst_frame, size, NULL);
}
fil_decompress_page(slot->comp_buf,
dst_frame,
size,
&bpage->write_size);
/* Mark this slot as free */
slot->reserved = false;
}
} else {
/* Find free slot from temporary memory array */
buf_tmp_buffer_t* slot = buf_pool_reserve_tmp_slot(buf_pool, page_compressed);
memcpy(slot->crypt_buf, dst_frame, size);
/* decrypt from crypt_buf to dst_frame */
fil_space_decrypt(bpage->space,
slot->crypt_buf,
size,
dst_frame);
if (page_compressed) {
fil_decompress_page(slot->comp_buf,
dst_frame,
size,
&bpage->write_size);
}
/* Mark this slot as free */
slot->reserved = false;
}
bpage->key_version = key_version;
if (bpage->crypt_buf_free != NULL) {
// free temp page
free(bpage->crypt_buf_free);
bpage->crypt_buf = NULL;
bpage->crypt_buf_free = NULL;
}
if (bpage->comp_buf_free != NULL) {
// free temp page
free(bpage->comp_buf_free);
bpage->comp_buf = NULL;
bpage->comp_buf_free = NULL;
}
return (TRUE);
}
/********************************************************************//**
Release memory allocated for decryption
*/
void
buf_page_decrypt_cleanup(
/*=====================*/
buf_page_t* bpage) /*!< in/out: buffer page */
{
if (bpage->crypt_buf != NULL) {
free(bpage->crypt_buf_free);
bpage->crypt_buf = NULL;
bpage->crypt_buf_free = NULL;
}
}

View File

@@ -871,7 +871,7 @@ buf_dblwr_write_block_to_datafile(
0,
buf_block_get_page_no(block),
0,
UNIV_PAGE_SIZE,
bpage->real_size,
frame,
(void*) block,
(ulint *)&bpage->write_size);
@@ -1247,7 +1247,8 @@ retry:
TRX_SYS_SPACE,
0,
offset,
0, UNIV_PAGE_SIZE,
0,
bpage->real_size,
frame,
NULL,
0);

View File

@@ -951,7 +951,7 @@ buf_flush_write_block_low(
break;
}
frame = buf_page_encrypt_before_write(bpage, frame);
frame = buf_page_encrypt_before_write(bpage, frame, space_id);
if (!srv_use_doublewrite_buf || !buf_dblwr) {
fil_io(OS_FILE_WRITE | OS_AIO_SIMULATED_WAKE_LATER,
@@ -960,7 +960,7 @@ buf_flush_write_block_low(
zip_size,
buf_page_get_page_no(bpage),
0,
zip_size ? zip_size : UNIV_PAGE_SIZE,
zip_size ? zip_size : bpage->real_size,
frame,
bpage,
&bpage->write_size);
@@ -979,7 +979,7 @@ buf_flush_write_block_low(
zip_size,
buf_page_get_page_no(bpage),
0,
zip_size ? zip_size : UNIV_PAGE_SIZE,
zip_size ? zip_size : bpage->real_size,
frame,
bpage,
&bpage->write_size);

View File

@@ -222,7 +222,7 @@ not_to_recover:
ut_ad(buf_page_in_file(bpage));
ut_ad(!mutex_own(&buf_pool_from_bpage(bpage)->LRU_list_mutex));
byte* frame = buf_page_decrypt_before_read(bpage, zip_size);
byte* frame = zip_size ? bpage->zip.data : ((buf_block_t*) bpage)->frame;
if (sync) {
thd_wait_begin(NULL, THD_WAIT_DISKIO);
@@ -247,7 +247,6 @@ not_to_recover:
}
if (*err != DB_SUCCESS) {
buf_page_decrypt_cleanup(bpage);
if (ignore_nonexistent_pages || *err == DB_TABLESPACE_DELETED) {
buf_read_page_handle_error(bpage);
return(0);

View File

@@ -319,6 +319,7 @@ fil_space_create_crypt_data()
&crypt_data->mutex, SYNC_NO_ORDER_CHECK);
crypt_data->iv_length = iv_length;
my_random_bytes(crypt_data->iv, iv_length);
crypt_data->encryption = FIL_SPACE_ENCRYPTION_DEFAULT;
return crypt_data;
}
@@ -421,6 +422,9 @@ fil_space_read_crypt_data(
uint min_key_version = mach_read_from_4
(page + offset + MAGIC_SZ + 2 + iv_length);
fil_encryption_t encryption = (fil_encryption_t)mach_read_from_1(
page + offset + MAGIC_SZ + 2 + iv_length + 4);
const uint sz = sizeof(fil_space_crypt_t) + iv_length;
fil_space_crypt_t* crypt_data = static_cast<fil_space_crypt_t*>(
malloc(sz));
@@ -429,6 +433,7 @@ fil_space_read_crypt_data(
crypt_data->type = type;
crypt_data->min_key_version = min_key_version;
crypt_data->page0_offset = offset;
crypt_data->encryption = encryption;
mutex_create(fil_crypt_data_mutex_key,
&crypt_data->mutex, SYNC_NO_ORDER_CHECK);
crypt_data->iv_length = iv_length;
@@ -474,8 +479,9 @@ fil_space_write_crypt_data_low(
page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
const uint len = crypt_data->iv_length;
const uint min_key_version = crypt_data->min_key_version;
const fil_encryption_t encryption = crypt_data->encryption;
crypt_data->page0_offset = offset;
ut_a(2 + len + 4 + MAGIC_SZ < maxsize);
ut_a(2 + len + 4 + 1 + MAGIC_SZ < maxsize);
/*
redo log this as bytewise updates to page 0
@@ -489,8 +495,10 @@ fil_space_write_crypt_data_low(
mtr);
mlog_write_ulint(page + offset + MAGIC_SZ + 2 + len, min_key_version,
MLOG_4BYTES, mtr);
mlog_write_ulint(page + offset + MAGIC_SZ + 2 + len + 4, encryption,
MLOG_1BYTE, mtr);
byte* log_ptr = mlog_open(mtr, 11 + 12 + len);
byte* log_ptr = mlog_open(mtr, 11 + 13 + len);
if (log_ptr != NULL) {
log_ptr = mlog_write_initial_log_record_fast(
@@ -507,6 +515,8 @@ fil_space_write_crypt_data_low(
log_ptr += 1;
mach_write_to_4(log_ptr, min_key_version);
log_ptr += 4;
mach_write_to_1(log_ptr, encryption);
log_ptr += 1;
mlog_close(mtr, log_ptr);
mlog_catenate_string(mtr, crypt_data->iv, len);
@@ -555,7 +565,8 @@ fil_parse_write_crypt_data(
2 + // size of offset
1 + // size of type
1 + // size of iv-len
4; // size of min_key_version
4 + // size of min_key_version
1; // fil_encryption_t
if (end_ptr - ptr < entry_size){
return NULL;
@@ -582,9 +593,17 @@ fil_parse_write_crypt_data(
return NULL;
}
fil_encryption_t encryption = (fil_encryption_t)mach_read_from_1(ptr);
ptr +=1;
if (end_ptr - ptr < len) {
return NULL;
}
fil_space_crypt_t* crypt_data = fil_space_create_crypt_data();
crypt_data->page0_offset = offset;
crypt_data->min_key_version = min_key_version;
crypt_data->encryption = encryption;
memcpy(crypt_data->iv, ptr, len);
ptr += len;
@@ -610,7 +629,8 @@ fil_space_clear_crypt_data(
1 + // type
1 + // len
len + // iv
4; // min key version
4 + // min key version
1; // fil_encryption_t
memset(page + offset, 0, size);
}
@@ -674,13 +694,11 @@ fil_space_encrypt(
const byte* src_frame, /*!< in: Source page to be encrypted */
ulint zip_size, /*!< in: compressed size if
row_format compressed */
byte* dst_frame, /*!< in: outbut buffer */
ulint encryption_key) /*!< in: encryption key id if page
encrypted */
byte* dst_frame) /*!< in: outbut buffer */
{
fil_space_crypt_t* crypt_data=NULL;
ulint page_size = (zip_size) ? zip_size : UNIV_PAGE_SIZE;
uint key_version = (uint)encryption_key;
uint key_version;
unsigned char key[MY_AES_MAX_KEY_LENGTH];
uint key_length=MY_AES_MAX_KEY_LENGTH;
uint aes_method;
@@ -699,6 +717,7 @@ fil_space_encrypt(
/* Get crypt data from file space */
crypt_data = fil_space_get_crypt_data(space);
key_version = crypt_data->keys[0].key_id;
if (crypt_data == NULL) {
//TODO: Is this really needed ?
@@ -808,6 +827,10 @@ fil_space_check_encryption_read(
return false;
}
if (crypt_data->encryption == FIL_SPACE_ENCRYPTION_OFF) {
return false;
}
return true;
}
@@ -1352,6 +1375,11 @@ fil_crypt_space_needs_rotation(
mutex_enter(&crypt_data->mutex);
do {
if (crypt_data->encryption == FIL_SPACE_ENCRYPTION_OFF) {
/* This space is unencrypted by user request */
break;
}
/* prevent threads from starting to rotate space */
if (crypt_data->rotate_state.starting) {
/* recheck this space later */

View File

@@ -5579,6 +5579,74 @@ fil_report_invalid_page_access(
(ulong) byte_offset, (ulong) len, (ulong) type);
}
/********************************************************************//**
Find correct node from file space
@return node */
static
fil_node_t*
fil_space_get_node(
fil_space_t* space, /*!< in: file spage */
ulint space_id, /*!< in: space id */
ulint* block_offset, /*!< in/out: offset in number of blocks */
ulint byte_offset, /*!< in: remainder of offset in bytes; in
aio this must be divisible by the OS block
size */
ulint len) /*!< in: how many bytes to read or write; this
must not cross a file boundary; in aio this
must be a block size multiple */
{
fil_node_t* node;
ut_ad(mutex_own(&fil_system->mutex));
node = UT_LIST_GET_FIRST(space->chain);
for (;;) {
if (node == NULL) {
return(NULL);
} else if (fil_is_user_tablespace_id(space->id)
&& node->size == 0) {
/* We do not know the size of a single-table tablespace
before we open the file */
break;
} else if (node->size > *block_offset) {
/* Found! */
break;
} else {
*block_offset -= node->size;
node = UT_LIST_GET_NEXT(chain, node);
}
}
return (node);
}
/********************************************************************//**
Return block size of node in file space
@return file block size */
UNIV_INTERN
ulint
fil_space_get_block_size(
/*=====================*/
ulint space_id,
ulint block_offset,
ulint len)
{
ulint block_size = 512;
fil_space_t* space = fil_space_get_space(space_id);
if (space) {
mutex_enter(&fil_system->mutex);
fil_node_t* node = fil_space_get_node(space, space_id, &block_offset, 0, len);
mutex_exit(&fil_system->mutex);
if (node) {
block_size = node->file_block_size;
}
}
return block_size;
}
/********************************************************************//**
Reads or writes data. This operation is asynchronous (aio).
@return DB_SUCCESS, or DB_TABLESPACE_DELETED if we are trying to do
@@ -5626,7 +5694,7 @@ _fil_io(
ulint is_log;
ulint wake_later;
os_offset_t offset;
ibool ignore_nonexistent_pages;
bool ignore_nonexistent_pages;
is_log = type & OS_FILE_LOG;
type = type & ~OS_FILE_LOG;
@@ -5711,34 +5779,18 @@ _fil_io(
ut_ad(mode != OS_AIO_IBUF || space->purpose == FIL_TABLESPACE);
node = UT_LIST_GET_FIRST(space->chain);
node = fil_space_get_node(space, space_id, &block_offset, byte_offset, len);
for (;;) {
if (node == NULL) {
if (ignore_nonexistent_pages) {
mutex_exit(&fil_system->mutex);
return(DB_ERROR);
}
fil_report_invalid_page_access(
if (!node) {
if (ignore_nonexistent_pages) {
mutex_exit(&fil_system->mutex);
return(DB_ERROR);
}
fil_report_invalid_page_access(
block_offset, space_id, space->name,
byte_offset, len, type);
ut_error;
} else if (fil_is_user_tablespace_id(space->id)
&& node->size == 0) {
/* We do not know the size of a single-table tablespace
before we open the file */
break;
} else if (node->size > block_offset) {
/* Found! */
break;
} else {
block_offset -= node->size;
node = UT_LIST_GET_NEXT(chain, node);
}
ut_error;
}
/* Open file if closed */

View File

@@ -631,10 +631,10 @@ ha_create_table_option innodb_table_option_list[]=
HA_TOPTION_NUMBER("PAGE_COMPRESSION_LEVEL", page_compression_level, 0, 1, 9, 1),
/* With this option user can enable atomic writes feature for this table */
HA_TOPTION_ENUM("ATOMIC_WRITES", atomic_writes, "DEFAULT,ON,OFF", 0),
/* With this option the user can enable page encryption for the table */
HA_TOPTION_BOOL("PAGE_ENCRYPTION", page_encryption, 0),
/* With this option the user can enable encryption for the table */
HA_TOPTION_ENUM("ENCRYPTION", encryption, "DEFAULT, ON, OFF", 0),
/* With this option the user defines the key identifier using for the encryption */
HA_TOPTION_NUMBER("PAGE_ENCRYPTION_KEY", page_encryption_key, 0, 1, 255, 1),
HA_TOPTION_NUMBER("ENCRYPTION_KEY", encryption_key, 0, 1, UINT_MAX32, 1),
HA_TOPTION_END
};
@@ -11791,13 +11791,14 @@ ha_innobase::check_table_options(
enum row_type row_format = table->s->row_type;
ha_table_option_struct *options= table->s->option_struct;
atomic_writes_t awrites = (atomic_writes_t)options->atomic_writes;
fil_encryption_t encrypt = (fil_encryption_t)options->encryption;
if (options->page_encryption) {
if (encrypt == FIL_SPACE_ENCRYPTION_ON) {
if (srv_encrypt_tables) {
push_warning(
thd, Sql_condition::WARN_LEVEL_WARN,
HA_WRONG_CREATE_OPTION,
"InnoDB: PAGE_ENCRYPTION not available if innodb_encrypt_tables=ON");
"InnoDB: ENCRYPTION not available if innodb_encrypt_tables=ON");
return "INNODB_ENCRYPT_TABLES";
}
@@ -11805,7 +11806,7 @@ ha_innobase::check_table_options(
push_warning(
thd, Sql_condition::WARN_LEVEL_WARN,
HA_WRONG_CREATE_OPTION,
"InnoDB: PAGE_ENCRYPTION requires"
"InnoDB: ENCRYPTION requires"
" innodb_file_per_table.");
return "PAGE_ENCRYPTION";
}
@@ -11814,14 +11815,6 @@ ha_innobase::check_table_options(
/* Check page compression requirements */
if (options->page_compressed) {
if (srv_encrypt_tables) {
push_warning(
thd, Sql_condition::WARN_LEVEL_WARN,
HA_WRONG_CREATE_OPTION,
"InnoDB: PAGE_COMPRESSION not available if innodb_encrypt_tables=ON");
return "PAGE_COMPRESSED";
}
if (row_format == ROW_TYPE_COMPRESSED) {
push_warning(
thd, Sql_condition::WARN_LEVEL_WARN,
@@ -11891,29 +11884,29 @@ ha_innobase::check_table_options(
}
}
if (options->page_encryption_key != 0) {
if (options->page_encryption == false) {
if (options->encryption_key != 0) {
if (options->encryption == FIL_SPACE_ENCRYPTION_OFF) {
/* ignore this to allow alter table without changing page_encryption_key ...*/
}
if (options->page_encryption_key < 1 || options->page_encryption_key > 255) {
if (options->encryption_key < 1) {
push_warning_printf(
thd, Sql_condition::WARN_LEVEL_WARN,
HA_WRONG_CREATE_OPTION,
"InnoDB: invalid PAGE_ENCRYPTION_KEY = %lu."
" Valid values are [1..255]",
options->page_encryption_key);
return "PAGE_ENCRYPTION_KEY";
"InnoDB: invalid ENCRYPTION_KEY = %lu."
" Valid values are [1..UINTMAX32]",
options->encryption_key);
return "ENCRYPTION_KEY";
}
if (!has_encryption_key(options->page_encryption_key)) {
if (!has_encryption_key(options->encryption_key)) {
push_warning_printf(
thd, Sql_condition::WARN_LEVEL_WARN,
HA_WRONG_CREATE_OPTION,
"InnoDB: PAGE_ENCRYPTION_KEY encryption key %lu not available",
options->page_encryption_key
"InnoDB: ENCRYPTION_KEY %lu not available",
options->encryption_key
);
return "PAGE_ENCRYPTION_KEY";
return "ENCRYPTION_KEY";
}
}
@@ -11975,6 +11968,11 @@ ha_innobase::create(
const char* stmt;
size_t stmt_len;
/* Cache table options */
ha_table_option_struct *options= table->s->option_struct;
fil_encryption_t encrypt = (fil_encryption_t)options->encryption;
ulint key_id = (options->encryption_key == 0) ? srv_default_encryption_key :
options->encryption_key;
DBUG_ENTER("ha_innobase::create");
@@ -12220,6 +12218,18 @@ ha_innobase::create(
innobase_commit_low(trx);
/* If user has requested that table should be encrypted or table
should remain as unencrypted store crypt data */
if (encrypt == FIL_SPACE_ENCRYPTION_ON || encrypt == FIL_SPACE_ENCRYPTION_OFF) {
ulint maxsize;
ulint zip_size = fil_space_get_zip_size(innobase_table->space);
fil_space_crypt_t* crypt_data = fil_space_create_crypt_data();
crypt_data->page0_offset = fsp_header_get_crypt_offset(zip_size, &maxsize);
crypt_data->keys[0].key_id = key_id;
crypt_data->encryption = encrypt;
fil_space_set_crypt_data(innobase_table->space, crypt_data);
}
row_mysql_unlock_data_dictionary(trx);
/* Flush the log to reduce probability that the .frm files and
@@ -20329,12 +20339,12 @@ static MYSQL_SYSVAR_UINT(encryption_rotation_iops, srv_n_fil_crypt_iops,
innodb_encryption_rotation_iops_update,
srv_n_fil_crypt_iops, 0, UINT_MAX32, 0);
static MYSQL_SYSVAR_UINT(default_page_encryption_key, srv_default_page_encryption_key,
static MYSQL_SYSVAR_UINT(default_encryption_key, srv_default_encryption_key,
PLUGIN_VAR_RQCMDARG,
"Encryption key used for page encryption.",
"Default encryption key used for table encryption.",
NULL,
NULL,
FIL_DEFAULT_ENCRYPTION_KEY, 1, 255, 0);
FIL_DEFAULT_ENCRYPTION_KEY, 1, UINT_MAX32, 0);
static MYSQL_SYSVAR_BOOL(scrub_log, srv_scrub_log,
PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
@@ -20641,7 +20651,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(scrub_log),
MYSQL_SYSVAR(scrub_log_interval),
MYSQL_SYSVAR(encrypt_log),
MYSQL_SYSVAR(default_page_encryption_key),
MYSQL_SYSVAR(default_encryption_key),
/* Scrubing feature */
MYSQL_SYSVAR(immediate_scrub_data_uncompressed),
MYSQL_SYSVAR(background_scrub_data_uncompressed),

View File

@@ -71,9 +71,8 @@ struct ha_table_option_struct
srv_use_atomic_writes=1.
Atomic writes are not used if
value OFF.*/
bool page_encryption; /*!< Flag for an encrypted table */
/* Following can't be unsigned as it's compared with ULINT_UNDEFINED */
int page_encryption_key; /*!< ID of the encryption key */
uint encryption; /*!< DEFAULT, ON, OFF */
int encryption_key; /*!< encryption key id */
};
/** The class defining a handle to an Innodb table */

View File

@@ -282,8 +282,8 @@ ha_innobase::check_if_supported_inplace_alter(
DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
}
if (new_options->page_encryption != old_options->page_encryption ||
new_options->page_encryption_key != old_options->page_encryption_key) {
if (new_options->encryption != old_options->encryption ||
new_options->encryption_key != old_options->encryption_key) {
ha_alter_info->unsupported_reason = innobase_get_err_msg(
ER_ALTER_OPERATION_NOT_SUPPORTED_REASON);
DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);

View File

@@ -1469,16 +1469,19 @@ buf_own_zip_mutex_for_page(
The hook that is called just before a page is written to disk.
The function encrypts the content of the page and returns a pointer
to a frame that will be written instead of the real frame. */
UNIV_INTERN
byte*
buf_page_encrypt_before_write(
/*==========================*/
buf_page_t* page, /*!< in/out: buffer page to be flushed */
const byte* frame);
const byte* frame,
ulint space_id);
/**********************************************************************
The hook that is called after page is written to disk.
The function releases any resources needed for encryption that was allocated
in buf_page_encrypt_before_write */
UNIV_INTERN
ibool
buf_page_encrypt_after_write(
/*=========================*/
@@ -1488,6 +1491,7 @@ buf_page_encrypt_after_write(
The hook that is called just before a page is read from disk.
The function allocates memory that is used to temporarily store disk content
before getting decrypted */
UNIV_INTERN
byte*
buf_page_decrypt_before_read(
/*=========================*/
@@ -1498,19 +1502,35 @@ buf_page_decrypt_before_read(
The hook that is called just after a page is read from disk.
The function decrypt disk content into buf_page_t and releases the
temporary buffer that was allocated in buf_page_decrypt_before_read */
UNIV_INTERN
ibool
buf_page_decrypt_after_read(
/*========================*/
buf_page_t* page); /*!< in/out: buffer page read from disk */
/********************************************************************//**
Release memory allocated for page decryption.
Only used in scenarios where read fails, e.g due to tablespace being dropped */
void
buf_page_decrypt_cleanup(
/*=====================*/
buf_page_t* page); /*!< in/out: buffer page read from disk */
/** @brief The temporary memory structure.
NOTE! The definition appears here only for other modules of this
directory (buf) to see it. Do not use from outside! */
typedef struct {
bool reserved; /*!< true if this slot is reserved
*/
#ifdef HAVE_LZO
byte* lzo_mem; /*!< Temporal memory used by LZO */
#endif
byte* crypt_buf; /*!< for encryption the data needs to be
copied to a separate buffer before it's
encrypted&written. this as a page can be
read while it's being flushed */
byte* crypt_buf_free; /*!< for encryption, allocated buffer
that is then alligned */
byte* comp_buf; /*!< for compression we need
temporal buffer because page
can be read while it's being flushed */
byte* comp_buf_free; /*!< for compression, allocated
buffer that is then alligned */
} buf_tmp_buffer_t;
/** The common buffer control block structure
for compressed and uncompressed frames */
@@ -1587,19 +1607,16 @@ struct buf_page_t{
operation needed. */
unsigned key_version; /*!< key version for this block */
byte* crypt_buf; /*!< for encryption the data needs to be
copied to a separate buffer before it's
encrypted&written. this as a page can be
read while it's being flushed */
byte* crypt_buf_free; /*!< for encryption, allocated buffer
that is then alligned */
byte* comp_buf; /*!< for compression we need
temporal buffer because page
can be read while it's being flushed */
byte* comp_buf_free; /*!< for compression, allocated
buffer that is then alligned */
bool encrypt_later; /*!< should we encrypt the page
at os0file.cc ? */
ulint real_size; /*!< Real size of the page
Normal pages == UNIV_PAGE_SIZE
page compressed pages, payload
size alligned to sector boundary.
*/
buf_tmp_buffer_t* slot; /*!< Slot for temporary memory
used for encryption/compression
or NULL */
#ifndef UNIV_HOTBACKUP
buf_page_t* hash; /*!< node used in chaining to
buf_pool->page_hash or
@@ -1918,6 +1935,17 @@ struct buf_buddy_stat_t {
ib_uint64_t relocated_usec;
};
/** @brief The temporary memory array structure.
NOTE! The definition appears here only for other modules of this
directory (buf) to see it. Do not use from outside! */
typedef struct {
ulint n_slots; /*!< Total number of slots */
buf_tmp_buffer_t *slots; /*!< Pointer to the slots in the
array */
} buf_tmp_array_t;
/** @brief The buffer pool structure.
NOTE! The definition appears here only for other modules of this
@@ -2091,6 +2119,10 @@ struct buf_pool_t{
/*!< Sentinel records for buffer
pool watches. */
buf_tmp_array_t* tmp_arr;
/*!< Array for temporal memory
used in compression and encryption */
#if BUF_BUDDY_LOW > UNIV_ZIP_SIZE_MIN
# error "BUF_BUDDY_LOW > UNIV_ZIP_SIZE_MIN"
#endif

View File

@@ -925,28 +925,15 @@ buf_block_free(
mutex_exit(&block->mutex);
}
/********************************************************************//**
Get crypt buffer. */
UNIV_INLINE
byte*
buf_page_get_crypt_buffer(
/*=========================*/
const buf_page_t* bpage) /*!< in: buffer pool page */
{
return bpage->crypt_buf;
}
/********************************************************************//**
Get buf frame. */
UNIV_INLINE
void *
buf_page_get_frame(
/*=========================*/
/*===============*/
const buf_page_t* bpage) /*!< in: buffer pool page */
{
if (bpage->crypt_buf) {
return buf_page_get_crypt_buffer(bpage);
} else if (bpage->zip.data) {
if (bpage->zip.data) {
return bpage->zip.data;
} else {
return ((buf_block_t*) bpage)->frame;

View File

@@ -37,6 +37,14 @@ Created 04/01/2015 Jan Lindström
/* This key will be used if nothing else is given */
#define FIL_DEFAULT_ENCRYPTION_KEY 1
/** Enum values for encryption table option */
typedef enum {
FIL_SPACE_ENCRYPTION_DEFAULT = 0, /* Tablespace encrypted if
srv_encrypt_tables = ON */
FIL_SPACE_ENCRYPTION_ON = 1, /* Tablespace is encrypted always */
FIL_SPACE_ENCRYPTION_OFF = 2 /* Tablespace is not encrypted */
} fil_encryption_t;
/**
* CRYPT_SCHEME_UNENCRYPTED
*
@@ -67,6 +75,8 @@ struct key_struct
{
uint key_version; /*!< Key version used as
identifier */
uint key_id; /*1< Key id used as
identifier */
byte key[MY_AES_MAX_KEY_LENGTH]; /*!< Cached L or key */
uint key_length; /*!< Key length */
};
@@ -95,6 +105,7 @@ struct fil_space_crypt_struct
key_struct keys[3]; // cached L = AES_ECB(KEY, IV)
uint min_key_version; // min key version for this space
ulint page0_offset; // byte offset on page 0 for crypt data
fil_encryption_t encryption; // Encryption setup
ib_mutex_t mutex; // mutex protecting following variables
bool closing; // is tablespace being closed
@@ -227,9 +238,7 @@ fil_space_encrypt(
lsn_t lsn, /*!< in: page lsn */
const byte* src_frame,/*!< in: page frame */
ulint size, /*!< in: size of data to encrypt */
byte* dst_frame, /*!< in: where to encrypt to */
ulint page_encryption_key); /*!< in: page encryption key id if page
encrypted */
byte* dst_frame); /*!< in: where to encrypt to */
/*********************************************************************
Decrypt buffer page */

View File

@@ -982,6 +982,16 @@ _fil_io(
#define fil_io(type, sync, space_id, zip_size, block_offset, byte_offset, len, buf, message, write_size) \
_fil_io(type, sync, space_id, zip_size, block_offset, byte_offset, len, buf, message, write_size, NULL)
/*******************************************************************//**
Returns the block size of the file space
@return block size */
UNIV_INTERN
ulint
fil_space_get_block_size(
/*=====================*/
ulint id, /*!< in: space id */
ulint offset, /*!< in: page offset */
ulint len); /*!< in: page len */
/**********************************************************************//**
Waits for an aio operation to complete. This function is used to write the

View File

@@ -705,8 +705,8 @@ that semaphore times out in InnoDB */
#define DEFAULT_SRV_FATAL_SEMAPHORE_TIMEOUT 600
extern ulong srv_fatal_semaphore_wait_threshold;
/** Default encryption key used for page encryption */
extern uint srv_default_page_encryption_key;
/** Default encryption key used for tablespace encryption */
extern uint srv_default_encryption_key;
/** Enable semaphore request instrumentation */
extern my_bool srv_instrument_semaphores;

View File

@@ -670,8 +670,8 @@ thread ensures that we flush the log files at least once per
second. */
static time_t srv_last_log_flush_time;
/** Default encryption key used for page encryption */
UNIV_INTERN uint srv_default_page_encryption_key = FIL_DEFAULT_ENCRYPTION_KEY;
/** Default encryption key used for tablespace encryption */
UNIV_INTERN uint srv_default_encryption_key = FIL_DEFAULT_ENCRYPTION_KEY;
/** Enable semaphore request instrumentation */
UNIV_INTERN my_bool srv_instrument_semaphores = FALSE;