summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/suite/encryption/r/debug_key_management.result1
-rw-r--r--mysql-test/suite/encryption/r/innodb-key-rotation-disable.result59
-rw-r--r--mysql-test/suite/encryption/r/innodb_encryption.result2
-rw-r--r--mysql-test/suite/encryption/t/innodb-key-rotation-disable.opt6
-rw-r--r--mysql-test/suite/encryption/t/innodb-key-rotation-disable.test95
-rw-r--r--mysql-test/suite/sys_vars/r/sysvars_innodb.result14
-rw-r--r--storage/innobase/fil/fil0crypt.cc124
-rw-r--r--storage/innobase/fil/fil0fil.cc9
-rw-r--r--storage/innobase/handler/ha_innodb.cc40
-rw-r--r--storage/innobase/include/fil0crypt.h15
-rw-r--r--storage/innobase/include/srv0srv.h7
-rw-r--r--storage/innobase/srv/srv0srv.cc2
-rw-r--r--storage/xtradb/fil/fil0crypt.cc124
-rw-r--r--storage/xtradb/fil/fil0fil.cc9
-rw-r--r--storage/xtradb/handler/ha_innodb.cc40
-rw-r--r--storage/xtradb/include/fil0crypt.h15
-rw-r--r--storage/xtradb/include/srv0srv.h7
-rw-r--r--storage/xtradb/srv/srv0srv.cc2
18 files changed, 553 insertions, 18 deletions
diff --git a/mysql-test/suite/encryption/r/debug_key_management.result b/mysql-test/suite/encryption/r/debug_key_management.result
index 8793e6ba363..c8cca4067c3 100644
--- a/mysql-test/suite/encryption/r/debug_key_management.result
+++ b/mysql-test/suite/encryption/r/debug_key_management.result
@@ -3,6 +3,7 @@ show variables like 'innodb_encrypt%';
Variable_name Value
innodb_encrypt_log ON
innodb_encrypt_tables ON
+innodb_encryption_keyrotation ON
innodb_encryption_rotate_key_age 2
innodb_encryption_rotation_iops 100
innodb_encryption_threads 4
diff --git a/mysql-test/suite/encryption/r/innodb-key-rotation-disable.result b/mysql-test/suite/encryption/r/innodb-key-rotation-disable.result
new file mode 100644
index 00000000000..2d8e6d3f73c
--- /dev/null
+++ b/mysql-test/suite/encryption/r/innodb-key-rotation-disable.result
@@ -0,0 +1,59 @@
+SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0;
+COUNT(*) = 0
+1
+SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0;
+COUNT(*) = 0
+0
+create database enctests;
+use enctests;
+create table t1(a int not null primary key, b char(200)) engine=innodb;
+create table t2(a int not null primary key, b char(200)) engine=innodb row_format=compressed;
+create table t3(a int not null primary key, b char(200)) engine=innodb page_compressed=yes;
+create table t4(a int not null primary key, b char(200)) engine=innodb encrypted=yes;
+create table t5(a int not null primary key, b char(200)) engine=innodb encrypted=yes row_format=compressed;
+create table t6(a int not null primary key, b char(200)) engine=innodb encrypted=yes page_compressed=yes;
+create table t7(a int not null primary key, b char(200)) engine=innodb encrypted=no;
+create table t8(a int not null primary key, b char(200)) engine=innodb encrypted=no row_format=compressed;
+create table t9(a int not null primary key, b char(200)) engine=innodb encrypted=no page_compressed=yes;
+insert into t1 values (1, 'secredmessage');
+insert into t2 values (1, 'secredmessage');
+insert into t3 values (1, 'secredmessagecompressedaaaaaaaaabbbbbbbbbbbbbbccccccccccccccc');
+insert into t4 values (1, 'secredmessage');
+insert into t5 values (1, 'secredmessage');
+insert into t6 values (1, 'secredmessagecompressedaaaaaaaaabbbbbbbbbbbbbbccccccccccccccc');
+insert into t7 values (1, 'publicmessage');
+insert into t8 values (1, 'publicmessage');
+insert into t9 values (1, 'pugliccompressedaaaaaaaaabbbbbbbbbbbbbbccccccccccccccc');
+# should list tables t1-t6
+SELECT NAME,ENCRYPTION_SCHEME,CURRENT_KEY_ID FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0 AND NAME LIKE 'enctests%';
+NAME ENCRYPTION_SCHEME CURRENT_KEY_ID
+enctests/t1 1 1
+enctests/t2 1 1
+enctests/t3 1 1
+enctests/t4 1 1
+enctests/t5 1 1
+enctests/t6 1 1
+# should list tables t7-t9
+SELECT NAME,ENCRYPTION_SCHEME,CURRENT_KEY_ID FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0 and NAME LIKE 'enctests%';
+NAME ENCRYPTION_SCHEME CURRENT_KEY_ID
+enctests/t7 0 1
+enctests/t8 0 1
+enctests/t9 0 1
+SET GLOBAL innodb_encrypt_tables=OFF;
+ERROR 42000: Variable 'innodb_encrypt_tables' can't be set to the value of 'OFF'
+SET GLOBAL innodb_encrypt_tables=ON;
+ERROR 42000: Variable 'innodb_encrypt_tables' can't be set to the value of 'ON'
+# t1 default on expecting NOT FOUND
+NOT FOUND /secred/ in t1.ibd
+# t2 default on expecting NOT FOUND
+NOT FOUND /secred/ in t2.ibd
+# t3 default on expecting NOT FOUND
+NOT FOUND /secred/ in t3.ibd
+# t4 on expecting NOT FOUND
+NOT FOUND /secred/ in t4.ibd
+# t5 on expecting NOT FOUND
+NOT FOUND /secred/ in t5.ibd
+# t6 on expecting NOT FOUND
+NOT FOUND /secred/ in t6.ibd
+use test;
+drop database enctests;
diff --git a/mysql-test/suite/encryption/r/innodb_encryption.result b/mysql-test/suite/encryption/r/innodb_encryption.result
index 9b762bbba11..3b12316b2b6 100644
--- a/mysql-test/suite/encryption/r/innodb_encryption.result
+++ b/mysql-test/suite/encryption/r/innodb_encryption.result
@@ -3,6 +3,7 @@ SHOW VARIABLES LIKE 'innodb_encrypt%';
Variable_name Value
innodb_encrypt_log ON
innodb_encrypt_tables ON
+innodb_encryption_keyrotation ON
innodb_encryption_rotate_key_age 15
innodb_encryption_rotation_iops 100
innodb_encryption_threads 4
@@ -47,6 +48,7 @@ SHOW VARIABLES LIKE 'innodb_encrypt%';
Variable_name Value
innodb_encrypt_log ON
innodb_encrypt_tables OFF
+innodb_encryption_keyrotation ON
innodb_encryption_rotate_key_age 15
innodb_encryption_rotation_iops 100
innodb_encryption_threads 0
diff --git a/mysql-test/suite/encryption/t/innodb-key-rotation-disable.opt b/mysql-test/suite/encryption/t/innodb-key-rotation-disable.opt
new file mode 100644
index 00000000000..5bac7b8701f
--- /dev/null
+++ b/mysql-test/suite/encryption/t/innodb-key-rotation-disable.opt
@@ -0,0 +1,6 @@
+--innodb-encryption-keyrotation=OFF
+--innodb-encrypt-tables
+--innodb-encrypt-log
+--innodb-encryption-rotate-key-age=15
+--innodb-encryption-threads=4
+--innodb-tablespaces-encryption
diff --git a/mysql-test/suite/encryption/t/innodb-key-rotation-disable.test b/mysql-test/suite/encryption/t/innodb-key-rotation-disable.test
new file mode 100644
index 00000000000..3ad80c8f87d
--- /dev/null
+++ b/mysql-test/suite/encryption/t/innodb-key-rotation-disable.test
@@ -0,0 +1,95 @@
+-- source include/have_innodb.inc
+-- source include/have_file_key_management_plugin.inc
+
+SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0;
+SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0;
+
+--disable_query_log
+--disable_warnings
+let $innodb_compression_algorithm_orig=`SELECT @@innodb_compression_algorithm`;
+let $innodb_file_format_orig = `SELECT @@innodb_file_format`;
+let $innodb_file_per_table_orig = `SELECT @@innodb_file_per_table`;
+let $encryption = `SELECT @@innodb_encrypt_tables`;
+SET GLOBAL innodb_file_format = `Barracuda`;
+SET GLOBAL innodb_file_per_table = ON;
+# zlib
+set global innodb_compression_algorithm = 1;
+--enable_warnings
+--enable_query_log
+
+create database enctests;
+use enctests;
+create table t1(a int not null primary key, b char(200)) engine=innodb;
+create table t2(a int not null primary key, b char(200)) engine=innodb row_format=compressed;
+create table t3(a int not null primary key, b char(200)) engine=innodb page_compressed=yes;
+create table t4(a int not null primary key, b char(200)) engine=innodb encrypted=yes;
+create table t5(a int not null primary key, b char(200)) engine=innodb encrypted=yes row_format=compressed;
+create table t6(a int not null primary key, b char(200)) engine=innodb encrypted=yes page_compressed=yes;
+create table t7(a int not null primary key, b char(200)) engine=innodb encrypted=no;
+create table t8(a int not null primary key, b char(200)) engine=innodb encrypted=no row_format=compressed;
+create table t9(a int not null primary key, b char(200)) engine=innodb encrypted=no page_compressed=yes;
+
+insert into t1 values (1, 'secredmessage');
+insert into t2 values (1, 'secredmessage');
+insert into t3 values (1, 'secredmessagecompressedaaaaaaaaabbbbbbbbbbbbbbccccccccccccccc');
+insert into t4 values (1, 'secredmessage');
+insert into t5 values (1, 'secredmessage');
+insert into t6 values (1, 'secredmessagecompressedaaaaaaaaabbbbbbbbbbbbbbccccccccccccccc');
+insert into t7 values (1, 'publicmessage');
+insert into t8 values (1, 'publicmessage');
+insert into t9 values (1, 'pugliccompressedaaaaaaaaabbbbbbbbbbbbbbccccccccccccccc');
+
+--echo # should list tables t1-t6
+SELECT NAME,ENCRYPTION_SCHEME,CURRENT_KEY_ID FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0 AND NAME LIKE 'enctests%';
+--echo # should list tables t7-t9
+SELECT NAME,ENCRYPTION_SCHEME,CURRENT_KEY_ID FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0 and NAME LIKE 'enctests%';
+
+--error 1231
+SET GLOBAL innodb_encrypt_tables=OFF;
+--error 1231
+SET GLOBAL innodb_encrypt_tables=ON;
+
+--let $MYSQLD_DATADIR=`select @@datadir`
+--let t1_IBD = $MYSQLD_DATADIR/enctests/t1.ibd
+--let t2_IBD = $MYSQLD_DATADIR/enctests/t2.ibd
+--let t3_IBD = $MYSQLD_DATADIR/enctests/t3.ibd
+--let t4_IBD = $MYSQLD_DATADIR/enctests/t4.ibd
+--let t5_IBD = $MYSQLD_DATADIR/enctests/t5.ibd
+--let t6_IBD = $MYSQLD_DATADIR/enctests/t6.ibd
+--let t7_IBD = $MYSQLD_DATADIR/enctests/t7.ibd
+--let t8_IBD = $MYSQLD_DATADIR/enctests/t8.ibd
+--let t9_IBD = $MYSQLD_DATADIR/enctests/t9.ibd
+--let SEARCH_RANGE = 10000000
+--let SEARCH_PATTERN=secred
+--echo # t1 default on expecting NOT FOUND
+-- let SEARCH_FILE=$t1_IBD
+-- source include/search_pattern_in_file.inc
+--echo # t2 default on expecting NOT FOUND
+-- let SEARCH_FILE=$t2_IBD
+-- source include/search_pattern_in_file.inc
+--echo # t3 default on expecting NOT FOUND
+-- let SEARCH_FILE=$t3_IBD
+-- source include/search_pattern_in_file.inc
+--echo # t4 on expecting NOT FOUND
+-- let SEARCH_FILE=$t4_IBD
+-- source include/search_pattern_in_file.inc
+--echo # t5 on expecting NOT FOUND
+-- let SEARCH_FILE=$t5_IBD
+-- source include/search_pattern_in_file.inc
+--echo # t6 on expecting NOT FOUND
+-- let SEARCH_FILE=$t6_IBD
+-- source include/search_pattern_in_file.inc
+--let SEARCH_PATTERN=public
+
+use test;
+drop database enctests;
+# reset system
+
+--disable_query_log
+--disable_warnings
+EVAL SET GLOBAL innodb_compression_algorithm = $innodb_compression_algorithm_orig;
+EVAL SET GLOBAL innodb_file_per_table = $innodb_file_per_table_orig;
+EVAL SET GLOBAL innodb_file_format = $innodb_file_format_orig;
+set global innodb_compression_algorithm = DEFAULT;
+--enable_warnings
+--enable_query_log
diff --git a/mysql-test/suite/sys_vars/r/sysvars_innodb.result b/mysql-test/suite/sys_vars/r/sysvars_innodb.result
index afa152b0c7b..3306fd2bb8f 100644
--- a/mysql-test/suite/sys_vars/r/sysvars_innodb.result
+++ b/mysql-test/suite/sys_vars/r/sysvars_innodb.result
@@ -775,6 +775,20 @@ NUMERIC_BLOCK_SIZE 0
ENUM_VALUE_LIST NULL
READ_ONLY YES
COMMAND_LINE_ARGUMENT OPTIONAL
+VARIABLE_NAME INNODB_ENCRYPTION_KEYROTATION
+SESSION_VALUE NULL
+GLOBAL_VALUE ON
+GLOBAL_VALUE_ORIGIN COMPILE-TIME
+DEFAULT_VALUE ON
+VARIABLE_SCOPE GLOBAL
+VARIABLE_TYPE BOOLEAN
+VARIABLE_COMMENT Enable encryption key rotation (default ON)
+NUMERIC_MIN_VALUE NULL
+NUMERIC_MAX_VALUE NULL
+NUMERIC_BLOCK_SIZE NULL
+ENUM_VALUE_LIST OFF,ON
+READ_ONLY NO
+COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME INNODB_ENCRYPTION_ROTATE_KEY_AGE
SESSION_VALUE NULL
GLOBAL_VALUE 1
diff --git a/storage/innobase/fil/fil0crypt.cc b/storage/innobase/fil/fil0crypt.cc
index 2999bea2765..321519936d2 100644
--- a/storage/innobase/fil/fil0crypt.cc
+++ b/storage/innobase/fil/fil0crypt.cc
@@ -37,7 +37,7 @@ Modified Jan Lindström jan.lindstrom@mariadb.com
#include "fsp0fsp.h"
#include "fil0pagecompress.h"
#include "ha_prototypes.h" // IB_LOG_
-
+#include <vector>
#include <my_crypt.h>
/** Mutex for keys */
@@ -104,6 +104,28 @@ static mysql_pfs_key_t fil_crypt_stat_mutex_key;
UNIV_INTERN mysql_pfs_key_t fil_crypt_data_mutex_key;
#endif
+/** Mutex protecting vector of space_id's that require
+key rotation. */
+UNIV_INTERN ib_mutex_t fil_crypt_rotate_list_mutex;
+
+/** Key for rotate list mutex */
+#ifdef UNIV_PFS_MUTEX
+static mysql_pfs_key_t fil_crypt_rotate_list_mutex_key;
+#endif
+
+/** Vector type holding space_id's that require key rotation */
+typedef std::vector<ulint> fil_crypt_rotate_spaces_t;
+
+/** Vector holding space_id's that require key rotation */
+UNIV_INTERN fil_crypt_rotate_spaces_t fil_crypt_rotate_list;
+
+/** is keyrotation enabled */
+UNIV_INTERN my_bool innodb_encryption_keyrotation;
+
+/** Is background scrubbing enabled, defined on btr0scrub.cc */
+extern my_bool srv_background_scrub_data_uncompressed;
+extern my_bool srv_background_scrub_data_compressed;
+
static bool
fil_crypt_needs_rotation(
/*=====================*/
@@ -127,6 +149,10 @@ fil_space_crypt_init()
mutex_create(fil_crypt_stat_mutex_key,
&crypt_stat_mutex, SYNC_NO_ORDER_CHECK);
+
+ mutex_create(fil_crypt_rotate_list_mutex_key,
+ &fil_crypt_rotate_list_mutex, SYNC_NO_ORDER_CHECK);
+
memset(&crypt_stat, 0, sizeof(crypt_stat));
}
@@ -140,9 +166,53 @@ fil_space_crypt_cleanup()
os_event_free(fil_crypt_throttle_sleep_event);
mutex_free(&fil_crypt_key_mutex);
mutex_free(&crypt_stat_mutex);
+ fil_crypt_rotate_list.clear();
+ mutex_free(&fil_crypt_rotate_list_mutex);
}
/**
+Add space to key rotation list for encryption.
+@param[in] space_id space to add to rotation */
+UNIV_INTERN
+void
+fil_crypt_add_space_to_keyrotation(
+ ulint space_id)
+{
+ mutex_enter(&fil_crypt_rotate_list_mutex);
+ fil_crypt_rotate_list.push_back(space_id);
+ srv_stats.key_rotation_list_length.inc();
+ mutex_exit(&fil_crypt_rotate_list_mutex);
+ os_event_set(fil_crypt_threads_event);
+
+}
+
+/**
+Get space from key rotation list
+@return space_id or ULINT_UNDEFINED if list is empty */
+static
+ulint
+fil_crypt_get_space_from_keyrotation(void)
+{
+ ulint space_id = ULINT_UNDEFINED;
+
+ mutex_enter(&fil_crypt_rotate_list_mutex);
+
+ /* If key rotation list is empty, there is nothing
+ to do. */
+ if (fil_crypt_rotate_list.empty()) {
+ goto exit;
+ }
+
+ space_id = fil_crypt_rotate_list.back();
+ fil_crypt_rotate_list.pop_back();
+ srv_stats.key_rotation_list_length.dec();
+
+exit:
+ mutex_exit(&fil_crypt_rotate_list_mutex);
+
+ return (space_id);
+}
+/**
Get latest key version from encryption plugin.
@return key version or ENCRYPTION_KEY_VERSION_INVALID */
uint
@@ -1644,11 +1714,18 @@ fil_crypt_find_space_to_rotate(
return false;
}
- if (state->first) {
- state->first = false;
- state->space = fil_get_first_space_safe();
+ /* If key rotation is enabled (default) we iterate all tablespaces.
+ If key rotation is not enabled we iterate only the tablespaces
+ added to keyrotation list. */
+ if (innodb_encryption_keyrotation) {
+ if (state->first) {
+ state->first = false;
+ state->space = fil_get_first_space_safe();
+ } else {
+ state->space = fil_get_next_space_safe(state->space);
+ }
} else {
- state->space = fil_get_next_space_safe(state->space);
+ state->space = fil_crypt_get_space_from_keyrotation();
}
while (!state->should_shutdown() && state->space != ULINT_UNDEFINED) {
@@ -1664,7 +1741,11 @@ fil_crypt_find_space_to_rotate(
}
}
- state->space = fil_get_next_space_safe(state->space);
+ if (innodb_encryption_keyrotation) {
+ state->space = fil_get_next_space_safe(state->space);
+ } else {
+ state->space = fil_crypt_get_space_from_keyrotation();
+ }
}
/* if we didn't find any space return iops */
@@ -2305,7 +2386,13 @@ DECLARE_THREAD(fil_crypt_thread)(
* i.e either new key version of change or
* new rotate_key_age */
os_event_reset(fil_crypt_threads_event);
- if (os_event_wait_time(fil_crypt_threads_event, 1000000) == 0) {
+
+ if(innodb_encryption_keyrotation) {
+ if (os_event_wait_time(fil_crypt_threads_event, 1000000) == 0) {
+ break;
+ }
+ } else {
+ os_event_wait(fil_crypt_threads_event);
break;
}
@@ -2318,7 +2405,11 @@ DECLARE_THREAD(fil_crypt_thread)(
time_t waited = time(0) - wait_start;
- if (waited >= srv_background_scrub_data_check_interval) {
+ /* Break if we have waited the background scrub
+ internal and background scrubbing is enabled */
+ if (waited >= srv_background_scrub_data_check_interval
+ && (srv_background_scrub_data_uncompressed
+ || srv_background_scrub_data_compressed)) {
break;
}
}
@@ -2447,6 +2538,23 @@ fil_crypt_set_encrypt_tables(
os_event_set(fil_crypt_threads_event);
}
+/**
+Adjust keyrotation
+@param val value to be set */
+UNIV_INTERN
+void
+fil_crypt_set_keyrotation(
+ my_bool val)
+{
+ innodb_encryption_keyrotation = val;
+
+ /* If key rotation is enabled inform encryption threads
+ if they exists. */
+ if (innodb_encryption_keyrotation && srv_n_fil_crypt_threads) {
+ os_event_set(fil_crypt_threads_event);
+ }
+}
+
/*********************************************************************
Init threads for key rotation */
UNIV_INTERN
diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc
index fe6a2922b35..5ce11e66b92 100644
--- a/storage/innobase/fil/fil0fil.cc
+++ b/storage/innobase/fil/fil0fil.cc
@@ -3902,6 +3902,15 @@ fil_create_new_single_table_tablespace(
goto error_exit_1;
}
+ if (success) {
+ /* Inform key rotation that there could be something
+ to do */
+ if (mode == FIL_SPACE_ENCRYPTION_ON || mode == FIL_SPACE_ENCRYPTION_OFF ||
+ srv_encrypt_tables) {
+ fil_crypt_add_space_to_keyrotation(space_id);
+ }
+ }
+
#ifndef UNIV_HOTBACKUP
{
mtr_t mtr;
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index 350438e0495..dab7ca9b5c8 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -1084,6 +1084,9 @@ static SHOW_VAR innodb_status_variables[]= {
{"encryption_rotation_estimated_iops",
(char*) &export_vars.innodb_encryption_rotation_estimated_iops,
SHOW_LONG},
+ {"encryption_key_rotation_list_length",
+ (char*)&export_vars.innodb_key_rotation_list_length,
+ SHOW_LONGLONG},
/* scrubing */
{"scrub_background_page_reorganizations",
@@ -18440,6 +18443,22 @@ innodb_encrypt_tables_update(
fil_crypt_set_encrypt_tables(*static_cast<const ulong*>(save));
}
+/******************************************************************
+Update the system variable innodb_encryption_keyrotation */
+static
+void
+innodb_encryption_keyrotation_update(
+ THD* thd, /*!< in: thread handle */
+ struct st_mysql_sys_var* var, /*!< in: pointer to
+ system variable */
+ void* var_ptr,/*!< out: where the
+ formal string goes */
+ const void* save) /*!< in: immediate result
+ from check function */
+{
+ fil_crypt_set_keyrotation(*static_cast<const my_bool*>(save));
+}
+
static SHOW_VAR innodb_status_variables_export[]= {
{"Innodb", (char*) &show_innodb_vars, SHOW_FUNC},
{NullS, NullS, SHOW_LONG}
@@ -19833,6 +19852,13 @@ 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_BOOL(encryption_keyrotation, innodb_encryption_keyrotation,
+ PLUGIN_VAR_RQCMDARG,
+ "Enable encryption key rotation (default ON)",
+ 0,
+ innodb_encryption_keyrotation_update,
+ TRUE);
+
static MYSQL_SYSVAR_BOOL(scrub_log, srv_scrub_log,
PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
"Enable background redo log (ib_logfile0, ib_logfile1...) scrubbing",
@@ -20101,6 +20127,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(scrub_log_speed),
MYSQL_SYSVAR(encrypt_log),
MYSQL_SYSVAR(default_encryption_key_id),
+ MYSQL_SYSVAR(encryption_keyrotation),
/* Scrubing feature */
MYSQL_SYSVAR(immediate_scrub_data_uncompressed),
MYSQL_SYSVAR(background_scrub_data_uncompressed),
@@ -20741,8 +20768,9 @@ innodb_encrypt_tables_validate(
for update function */
struct st_mysql_value* value) /*!< in: incoming string */
{
- if (check_sysvar_enum(thd, var, save, value))
+ if (check_sysvar_enum(thd, var, save, value)) {
return 1;
+ }
ulong encrypt_tables = *(ulong*)save;
@@ -20754,6 +20782,16 @@ innodb_encrypt_tables_validate(
"encryption plugin is not available");
return 1;
}
+
+ if (!innodb_encryption_keyrotation) {
+ const char *msg = (encrypt_tables ? "enable" : "disable");
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ HA_ERR_UNSUPPORTED,
+ "InnoDB: cannot %s encryption, "
+ "innodb-encryption-keyrotation disabled", msg);
+ return 1;
+ }
+
return 0;
}
diff --git a/storage/innobase/include/fil0crypt.h b/storage/innobase/include/fil0crypt.h
index 42cdafde4d0..827d63bc670 100644
--- a/storage/innobase/include/fil0crypt.h
+++ b/storage/innobase/include/fil0crypt.h
@@ -530,6 +530,21 @@ fil_crypt_calculate_checksum(
/*=========================*/
ulint zip_size, /*!< in: zip_size or 0 */
byte* dst_frame); /*!< in: page where to calculate */
+/**
+Add space to key rotation list for encryption.
+@param[in] space_id space to add to rotation */
+UNIV_INTERN
+void
+fil_crypt_add_space_to_keyrotation(
+ ulint space_id);
+
+/**
+Adjust keyrotation
+@param val value to be set */
+UNIV_INTERN
+void
+fil_crypt_set_keyrotation(
+ my_bool val);
#ifndef UNIV_NONINL
#include "fil0crypt.ic"
diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h
index 9dd5b3efa9a..fe8961bbb36 100644
--- a/storage/innobase/include/srv0srv.h
+++ b/storage/innobase/include/srv0srv.h
@@ -185,6 +185,9 @@ struct srv_stats_t {
/** Number of encryption_get_latest_key_version calls */
ulint_ctr_64_t n_key_requests;
+
+ /** Number of spaces in keyrotation list */
+ ulint_ctr_64_t key_rotation_list_length;
};
extern const char* srv_main_thread_op_info;
@@ -561,6 +564,9 @@ extern my_bool srv_cmp_per_index_enabled;
/* is encryption enabled */
extern ulong srv_encrypt_tables;
+/* is keyrotation enabled */
+extern my_bool innodb_encryption_keyrotation;
+
/** Status variables to be passed to MySQL */
extern struct export_var_t export_vars;
@@ -1039,6 +1045,7 @@ struct export_var_t{
ulint innodb_encryption_rotation_pages_flushed;
ulint innodb_encryption_rotation_estimated_iops;
ib_int64_t innodb_encryption_key_requests;
+ ib_int64_t innodb_key_rotation_list_length;
ulint innodb_scrub_page_reorganizations;
ulint innodb_scrub_page_splits;
diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc
index 147279dd0d1..aa086543bc2 100644
--- a/storage/innobase/srv/srv0srv.cc
+++ b/storage/innobase/srv/srv0srv.cc
@@ -1664,6 +1664,8 @@ srv_export_innodb_status(void)
crypt_stat.estimated_iops;
export_vars.innodb_encryption_key_requests =
srv_stats.n_key_requests;
+ export_vars.innodb_key_rotation_list_length =
+ srv_stats.key_rotation_list_length;
export_vars.innodb_scrub_page_reorganizations =
scrub_stat.page_reorganizations;
diff --git a/storage/xtradb/fil/fil0crypt.cc b/storage/xtradb/fil/fil0crypt.cc
index 2999bea2765..321519936d2 100644
--- a/storage/xtradb/fil/fil0crypt.cc
+++ b/storage/xtradb/fil/fil0crypt.cc
@@ -37,7 +37,7 @@ Modified Jan Lindström jan.lindstrom@mariadb.com
#include "fsp0fsp.h"
#include "fil0pagecompress.h"
#include "ha_prototypes.h" // IB_LOG_
-
+#include <vector>
#include <my_crypt.h>
/** Mutex for keys */
@@ -104,6 +104,28 @@ static mysql_pfs_key_t fil_crypt_stat_mutex_key;
UNIV_INTERN mysql_pfs_key_t fil_crypt_data_mutex_key;
#endif
+/** Mutex protecting vector of space_id's that require
+key rotation. */
+UNIV_INTERN ib_mutex_t fil_crypt_rotate_list_mutex;
+
+/** Key for rotate list mutex */
+#ifdef UNIV_PFS_MUTEX
+static mysql_pfs_key_t fil_crypt_rotate_list_mutex_key;
+#endif
+
+/** Vector type holding space_id's that require key rotation */
+typedef std::vector<ulint> fil_crypt_rotate_spaces_t;
+
+/** Vector holding space_id's that require key rotation */
+UNIV_INTERN fil_crypt_rotate_spaces_t fil_crypt_rotate_list;
+
+/** is keyrotation enabled */
+UNIV_INTERN my_bool innodb_encryption_keyrotation;
+
+/** Is background scrubbing enabled, defined on btr0scrub.cc */
+extern my_bool srv_background_scrub_data_uncompressed;
+extern my_bool srv_background_scrub_data_compressed;
+
static bool
fil_crypt_needs_rotation(
/*=====================*/
@@ -127,6 +149,10 @@ fil_space_crypt_init()
mutex_create(fil_crypt_stat_mutex_key,
&crypt_stat_mutex, SYNC_NO_ORDER_CHECK);
+
+ mutex_create(fil_crypt_rotate_list_mutex_key,
+ &fil_crypt_rotate_list_mutex, SYNC_NO_ORDER_CHECK);
+
memset(&crypt_stat, 0, sizeof(crypt_stat));
}
@@ -140,9 +166,53 @@ fil_space_crypt_cleanup()
os_event_free(fil_crypt_throttle_sleep_event);
mutex_free(&fil_crypt_key_mutex);
mutex_free(&crypt_stat_mutex);
+ fil_crypt_rotate_list.clear();
+ mutex_free(&fil_crypt_rotate_list_mutex);
}
/**
+Add space to key rotation list for encryption.
+@param[in] space_id space to add to rotation */
+UNIV_INTERN
+void
+fil_crypt_add_space_to_keyrotation(
+ ulint space_id)
+{
+ mutex_enter(&fil_crypt_rotate_list_mutex);
+ fil_crypt_rotate_list.push_back(space_id);
+ srv_stats.key_rotation_list_length.inc();
+ mutex_exit(&fil_crypt_rotate_list_mutex);
+ os_event_set(fil_crypt_threads_event);
+
+}
+
+/**
+Get space from key rotation list
+@return space_id or ULINT_UNDEFINED if list is empty */
+static
+ulint
+fil_crypt_get_space_from_keyrotation(void)
+{
+ ulint space_id = ULINT_UNDEFINED;
+
+ mutex_enter(&fil_crypt_rotate_list_mutex);
+
+ /* If key rotation list is empty, there is nothing
+ to do. */
+ if (fil_crypt_rotate_list.empty()) {
+ goto exit;
+ }
+
+ space_id = fil_crypt_rotate_list.back();
+ fil_crypt_rotate_list.pop_back();
+ srv_stats.key_rotation_list_length.dec();
+
+exit:
+ mutex_exit(&fil_crypt_rotate_list_mutex);
+
+ return (space_id);
+}
+/**
Get latest key version from encryption plugin.
@return key version or ENCRYPTION_KEY_VERSION_INVALID */
uint
@@ -1644,11 +1714,18 @@ fil_crypt_find_space_to_rotate(
return false;
}
- if (state->first) {
- state->first = false;
- state->space = fil_get_first_space_safe();
+ /* If key rotation is enabled (default) we iterate all tablespaces.
+ If key rotation is not enabled we iterate only the tablespaces
+ added to keyrotation list. */
+ if (innodb_encryption_keyrotation) {
+ if (state->first) {
+ state->first = false;
+ state->space = fil_get_first_space_safe();
+ } else {
+ state->space = fil_get_next_space_safe(state->space);
+ }
} else {
- state->space = fil_get_next_space_safe(state->space);
+ state->space = fil_crypt_get_space_from_keyrotation();
}
while (!state->should_shutdown() && state->space != ULINT_UNDEFINED) {
@@ -1664,7 +1741,11 @@ fil_crypt_find_space_to_rotate(
}
}
- state->space = fil_get_next_space_safe(state->space);
+ if (innodb_encryption_keyrotation) {
+ state->space = fil_get_next_space_safe(state->space);
+ } else {
+ state->space = fil_crypt_get_space_from_keyrotation();
+ }
}
/* if we didn't find any space return iops */
@@ -2305,7 +2386,13 @@ DECLARE_THREAD(fil_crypt_thread)(
* i.e either new key version of change or
* new rotate_key_age */
os_event_reset(fil_crypt_threads_event);
- if (os_event_wait_time(fil_crypt_threads_event, 1000000) == 0) {
+
+ if(innodb_encryption_keyrotation) {
+ if (os_event_wait_time(fil_crypt_threads_event, 1000000) == 0) {
+ break;
+ }
+ } else {
+ os_event_wait(fil_crypt_threads_event);
break;
}
@@ -2318,7 +2405,11 @@ DECLARE_THREAD(fil_crypt_thread)(
time_t waited = time(0) - wait_start;
- if (waited >= srv_background_scrub_data_check_interval) {
+ /* Break if we have waited the background scrub
+ internal and background scrubbing is enabled */
+ if (waited >= srv_background_scrub_data_check_interval
+ && (srv_background_scrub_data_uncompressed
+ || srv_background_scrub_data_compressed)) {
break;
}
}
@@ -2447,6 +2538,23 @@ fil_crypt_set_encrypt_tables(
os_event_set(fil_crypt_threads_event);
}
+/**
+Adjust keyrotation
+@param val value to be set */
+UNIV_INTERN
+void
+fil_crypt_set_keyrotation(
+ my_bool val)
+{
+ innodb_encryption_keyrotation = val;
+
+ /* If key rotation is enabled inform encryption threads
+ if they exists. */
+ if (innodb_encryption_keyrotation && srv_n_fil_crypt_threads) {
+ os_event_set(fil_crypt_threads_event);
+ }
+}
+
/*********************************************************************
Init threads for key rotation */
UNIV_INTERN
diff --git a/storage/xtradb/fil/fil0fil.cc b/storage/xtradb/fil/fil0fil.cc
index f4301d47028..d90232279a3 100644
--- a/storage/xtradb/fil/fil0fil.cc
+++ b/storage/xtradb/fil/fil0fil.cc
@@ -3943,6 +3943,15 @@ fil_create_new_single_table_tablespace(
goto error_exit_1;
}
+ if (success) {
+ /* Inform key rotation that there could be something
+ to do */
+ if (mode == FIL_SPACE_ENCRYPTION_ON || mode == FIL_SPACE_ENCRYPTION_OFF ||
+ srv_encrypt_tables) {
+ fil_crypt_add_space_to_keyrotation(space_id);
+ }
+ }
+
#ifndef UNIV_HOTBACKUP
{
mtr_t mtr;
diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc
index bef54a910e6..59572798bfc 100644
--- a/storage/xtradb/handler/ha_innodb.cc
+++ b/storage/xtradb/handler/ha_innodb.cc
@@ -1290,6 +1290,9 @@ static SHOW_VAR innodb_status_variables[]= {
{"encryption_rotation_estimated_iops",
(char*) &export_vars.innodb_encryption_rotation_estimated_iops,
SHOW_LONG},
+ {"encryption_key_rotation_list_length",
+ (char*)&export_vars.innodb_key_rotation_list_length,
+ SHOW_LONGLONG},
/* Scrubing feature */
{"scrub_background_page_reorganizations",
@@ -19603,6 +19606,22 @@ innodb_encrypt_tables_update(
fil_crypt_set_encrypt_tables(*static_cast<const ulong*>(save));
}
+/******************************************************************
+Update the system variable innodb_encryption_keyrotation */
+static
+void
+innodb_encryption_keyrotation_update(
+ THD* thd, /*!< in: thread handle */
+ struct st_mysql_sys_var* var, /*!< in: pointer to
+ system variable */
+ void* var_ptr,/*!< out: where the
+ formal string goes */
+ const void* save) /*!< in: immediate result
+ from check function */
+{
+ fil_crypt_set_keyrotation(*static_cast<const my_bool*>(save));
+}
+
static SHOW_VAR innodb_status_variables_export[]= {
{"Innodb", (char*) &show_innodb_vars, SHOW_FUNC},
{NullS, NullS, SHOW_LONG}
@@ -21315,6 +21334,13 @@ 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_BOOL(encryption_keyrotation, innodb_encryption_keyrotation,
+ PLUGIN_VAR_RQCMDARG,
+ "Enable encryption key rotation (default ON)",
+ 0,
+ innodb_encryption_keyrotation_update,
+ TRUE);
+
static MYSQL_SYSVAR_BOOL(scrub_log, srv_scrub_log,
PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
"Enable background redo log (ib_logfile0, ib_logfile1...) scrubbing",
@@ -21620,6 +21646,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(scrub_log_speed),
MYSQL_SYSVAR(encrypt_log),
MYSQL_SYSVAR(default_encryption_key_id),
+ MYSQL_SYSVAR(encryption_keyrotation),
/* Scrubing feature */
MYSQL_SYSVAR(immediate_scrub_data_uncompressed),
MYSQL_SYSVAR(background_scrub_data_uncompressed),
@@ -22269,8 +22296,9 @@ innodb_encrypt_tables_validate(
for update function */
struct st_mysql_value* value) /*!< in: incoming string */
{
- if (check_sysvar_enum(thd, var, save, value))
+ if (check_sysvar_enum(thd, var, save, value)) {
return 1;
+ }
ulong encrypt_tables = *(ulong*)save;
@@ -22282,6 +22310,16 @@ innodb_encrypt_tables_validate(
"encryption plugin is not available");
return 1;
}
+
+ if (!innodb_encryption_keyrotation) {
+ const char *msg = (encrypt_tables ? "enable" : "disable");
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ HA_ERR_UNSUPPORTED,
+ "InnoDB: cannot %s encryption, "
+ "innodb-encryption-keyrotation disabled", msg);
+ return 1;
+ }
+
return 0;
}
diff --git a/storage/xtradb/include/fil0crypt.h b/storage/xtradb/include/fil0crypt.h
index 42cdafde4d0..827d63bc670 100644
--- a/storage/xtradb/include/fil0crypt.h
+++ b/storage/xtradb/include/fil0crypt.h
@@ -530,6 +530,21 @@ fil_crypt_calculate_checksum(
/*=========================*/
ulint zip_size, /*!< in: zip_size or 0 */
byte* dst_frame); /*!< in: page where to calculate */
+/**
+Add space to key rotation list for encryption.
+@param[in] space_id space to add to rotation */
+UNIV_INTERN
+void
+fil_crypt_add_space_to_keyrotation(
+ ulint space_id);
+
+/**
+Adjust keyrotation
+@param val value to be set */
+UNIV_INTERN
+void
+fil_crypt_set_keyrotation(
+ my_bool val);
#ifndef UNIV_NONINL
#include "fil0crypt.ic"
diff --git a/storage/xtradb/include/srv0srv.h b/storage/xtradb/include/srv0srv.h
index f65848fdf45..1cbcd4da3bd 100644
--- a/storage/xtradb/include/srv0srv.h
+++ b/storage/xtradb/include/srv0srv.h
@@ -192,6 +192,9 @@ struct srv_stats_t {
/** Number of encryption_get_latest_key_version calls */
ulint_ctr_64_t n_key_requests;
+
+ /** Number of spaces in keyrotation list */
+ ulint_ctr_64_t key_rotation_list_length;
};
extern const char* srv_main_thread_op_info;
@@ -703,6 +706,9 @@ extern my_bool srv_cmp_per_index_enabled;
/* is encryption enabled */
extern ulong srv_encrypt_tables;
+/* is keyrotation enabled */
+extern my_bool innodb_encryption_keyrotation;
+
/** Status variables to be passed to MySQL */
extern struct export_var_t export_vars;
@@ -1271,6 +1277,7 @@ struct export_var_t{
ulint innodb_encryption_rotation_pages_flushed;
ulint innodb_encryption_rotation_estimated_iops;
ib_int64_t innodb_encryption_key_requests;
+ ib_int64_t innodb_key_rotation_list_length;
ulint innodb_scrub_page_reorganizations;
ulint innodb_scrub_page_splits;
diff --git a/storage/xtradb/srv/srv0srv.cc b/storage/xtradb/srv/srv0srv.cc
index bc222b864ef..b63e9db108d 100644
--- a/storage/xtradb/srv/srv0srv.cc
+++ b/storage/xtradb/srv/srv0srv.cc
@@ -2076,6 +2076,8 @@ srv_export_innodb_status(void)
crypt_stat.estimated_iops;
export_vars.innodb_encryption_key_requests =
srv_stats.n_key_requests;
+ export_vars.innodb_key_rotation_list_length =
+ srv_stats.key_rotation_list_length;
export_vars.innodb_scrub_page_reorganizations =
scrub_stat.page_reorganizations;