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:
committed by
Sergei Golubchik
parent
b4a4d82396
commit
0ba9fa35bc
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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*/
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user