diff options
author | Monty <monty@mariadb.org> | 2014-12-22 16:53:17 +0200 |
---|---|---|
committer | Sergei Golubchik <serg@mariadb.org> | 2015-02-10 10:21:17 +0100 |
commit | d7d589dc01f6d70d1518b74d46fd3b75e76267f5 (patch) | |
tree | f9df59951453660f0038ed78cf5ceadc852bf74c /storage/xtradb/log/log0log.cc | |
parent | 3a3ec744b5a31318a00821dc0ed6da8af49fda25 (diff) | |
download | mariadb-git-d7d589dc01f6d70d1518b74d46fd3b75e76267f5.tar.gz |
Push for testing of encryption
Diffstat (limited to 'storage/xtradb/log/log0log.cc')
-rw-r--r-- | storage/xtradb/log/log0log.cc | 159 |
1 files changed, 154 insertions, 5 deletions
diff --git a/storage/xtradb/log/log0log.cc b/storage/xtradb/log/log0log.cc index 031926fd91f..9b33c7858bc 100644 --- a/storage/xtradb/log/log0log.cc +++ b/storage/xtradb/log/log0log.cc @@ -90,6 +90,10 @@ UNIV_INTERN log_t* log_sys = NULL; UNIV_INTERN log_checksum_func_t log_checksum_algorithm_ptr = log_block_calc_checksum_innodb; +/* Next log block number to do dummy record filling if no log records written +for a while */ +static ulint next_lbn_to_pad = 0; + #ifdef UNIV_PFS_RWLOCK UNIV_INTERN mysql_pfs_key_t checkpoint_lock_key; # ifdef UNIV_LOG_ARCHIVE @@ -629,10 +633,9 @@ function_exit: return(lsn); } -#ifdef UNIV_LOG_ARCHIVE /******************************************************//** Pads the current log block full with dummy log records. Used in producing -consistent archived log files. */ +consistent archived log files and scrubbing redo log. */ static void log_pad_current_log_block(void) @@ -667,7 +670,6 @@ log_pad_current_log_block(void) ut_a(lsn % OS_FILE_LOG_BLOCK_SIZE == LOG_BLOCK_HDR_SIZE); } -#endif /* UNIV_LOG_ARCHIVE */ /******************************************************//** Calculates the data capacity of a log group, when the log file headers are not @@ -1003,6 +1005,7 @@ log_init(void) /*----------------------------*/ log_sys->next_checkpoint_no = 0; + log_sys->redo_log_crypt_ver = UNENCRYPTED_KEY_VER; log_sys->last_checkpoint_lsn = log_sys->lsn; log_sys->n_pending_checkpoint_writes = 0; @@ -1048,7 +1051,7 @@ log_init(void) log_block_set_first_rec_group(log_sys->buf, LOG_BLOCK_HDR_SIZE); log_sys->buf_free = LOG_BLOCK_HDR_SIZE; - log_sys->lsn = LOG_START_LSN + LOG_BLOCK_HDR_SIZE; + log_sys->lsn = LOG_START_LSN + LOG_BLOCK_HDR_SIZE; // TODO(minliz): ensure various LOG_START_LSN? MONITOR_SET(MONITOR_LSN_CHECKPOINT_AGE, log_sys->lsn - log_sys->last_checkpoint_lsn); @@ -1401,6 +1404,36 @@ log_block_store_checksum( } /******************************************************//** +Encrypt one or more log block before it is flushed to disk +@return true if encryption succeeds. */ +static +bool +log_group_encrypt_before_write( +/*===========================*/ + const log_group_t* group, /*!< in: log group to be flushed */ + byte* block, /*!< in/out: pointer to a log block */ + const ulint size) /*!< in: size of log blocks */ + +{ + Crypt_result result = AES_OK; + + ut_ad(size % OS_FILE_LOG_BLOCK_SIZE == 0); + byte* dst_frame = (byte*)malloc(size); + + //encrypt log blocks content + result = log_blocks_encrypt(block, size, dst_frame); + + if (result == AES_OK) + { + ut_ad(block[0] == dst_frame[0]); + memcpy(block, dst_frame, size); + } + free(dst_frame); + + return (result == AES_OK); +} + +/******************************************************//** Writes a buffer to a log file group. */ UNIV_INTERN void @@ -1506,6 +1539,15 @@ loop: ut_a(next_offset / UNIV_PAGE_SIZE <= ULINT_MAX); + if (srv_encrypt_log && + log_sys->redo_log_crypt_ver != UNENCRYPTED_KEY_VER && + !log_group_encrypt_before_write(group, buf, write_len)) + { + fprintf(stderr, + "\nInnodb redo log encryption failed.\n"); + abort(); + } + fil_io(OS_FILE_WRITE | OS_FILE_LOG, true, group->space_id, 0, (ulint) (next_offset / UNIV_PAGE_SIZE), (ulint) (next_offset % UNIV_PAGE_SIZE), write_len, buf, @@ -2023,6 +2065,8 @@ log_group_checkpoint( mach_write_to_8(buf + LOG_CHECKPOINT_NO, log_sys->next_checkpoint_no); mach_write_to_8(buf + LOG_CHECKPOINT_LSN, log_sys->next_checkpoint_lsn); + log_crypt_write_checkpoint_buf(buf); + lsn_offset = log_group_calc_lsn_offset(log_sys->next_checkpoint_lsn, group); mach_write_to_4(buf + LOG_CHECKPOINT_OFFSET_LOW32, @@ -2141,6 +2185,8 @@ log_reset_first_header_and_checkpoint( mach_write_to_8(buf + LOG_CHECKPOINT_NO, 0); mach_write_to_8(buf + LOG_CHECKPOINT_LSN, lsn); + log_crypt_write_checkpoint_buf(buf); + mach_write_to_4(buf + LOG_CHECKPOINT_OFFSET_LOW32, LOG_FILE_HDR_SIZE + LOG_BLOCK_HDR_SIZE); mach_write_to_4(buf + LOG_CHECKPOINT_OFFSET_HIGH32, 0); @@ -2295,7 +2341,6 @@ log_checkpoint( } log_sys->next_checkpoint_lsn = oldest_lsn; - #ifdef UNIV_DEBUG if (log_debug_writes) { fprintf(stderr, "Making checkpoint no " @@ -2307,6 +2352,10 @@ log_checkpoint( log_groups_write_checkpoint_info(); + /* generate key version and key used to encrypt next log block */ + log_crypt_set_ver_and_key(log_sys->redo_log_crypt_ver, + log_sys->redo_log_crypt_key); + MONITOR_INC(MONITOR_NUM_CHECKPOINT); mutex_exit(&(log_sys->mutex)); @@ -2506,6 +2555,33 @@ loop: } /******************************************************//** +Decrypt a specified log segment after they are read from a log file to a buffer. +@return true if decryption succeeds. */ +static +bool +log_group_decrypt_after_read( +/*==========================*/ + const log_group_t* group, /*!< in: log group to be read from */ + byte* frame, /*!< in/out: log segment */ + const ulint size) /*!< in: log segment size */ +{ + Crypt_result result; + ut_ad(size % OS_FILE_LOG_BLOCK_SIZE == 0); + byte* dst_frame = (byte*)malloc(size); + + // decrypt log blocks content + result = log_blocks_decrypt(frame, size, dst_frame); + + if (result == AES_OK) + { + memcpy(frame, dst_frame, size); + } + free(dst_frame); + + return (result == AES_OK); +} + +/******************************************************//** Reads a specified log segment to a buffer. Optionally releases the log mutex before the I/O. */ UNIV_INTERN @@ -2565,6 +2641,13 @@ loop: (ulint) (source_offset % UNIV_PAGE_SIZE), len, buf, (type == LOG_ARCHIVE) ? &log_archive_io : NULL, 0); + if (recv_sys->recv_log_crypt_ver != UNENCRYPTED_KEY_VER && + !log_group_decrypt_after_read(group, buf, len)) + { + fprintf(stderr, "Innodb redo log decryption failed.\n"); + abort(); + } + start_lsn += len; buf += len; @@ -2857,6 +2940,14 @@ loop: MONITOR_INC(MONITOR_LOG_IO); + if (srv_encrypt_log && + log_sys->redo_log_crypt_ver != UNENCRYPTED_KEY_VER && + !log_group_encrypt_before_write(group, buf, len)) + { + fprintf(stderr, "Innodb redo log encryption failed.\n"); + abort(); + } + fil_io(OS_FILE_WRITE | OS_FILE_LOG, false, group->archive_space_id, 0, (ulint) (next_offset / UNIV_PAGE_SIZE), @@ -4074,4 +4165,62 @@ log_mem_free(void) log_sys = NULL; } } + +/** Event to wake up the log scrub thread */ +UNIV_INTERN os_event_t log_scrub_event = NULL; + +UNIV_INTERN ibool srv_log_scrub_thread_active = FALSE; + +/*****************************************************************//* +If no log record has been written for a while, fill current log +block with dummy records. */ +static +void +log_scrub() +/*=========*/ +{ + ulint cur_lbn = log_block_convert_lsn_to_no(log_sys->lsn); + if (next_lbn_to_pad == cur_lbn) + { + log_pad_current_log_block(); + } + next_lbn_to_pad = log_block_convert_lsn_to_no(log_sys->lsn); +} + +/* log scrubbing interval in ms. */ +UNIV_INTERN ulonglong innodb_scrub_log_interval; + +/*****************************************************************//** +This is the main thread for log scrub. It waits for an event and +when waked up fills current log block with dummy records and +sleeps again. +@return this function does not return, it calls os_thread_exit() */ +extern "C" UNIV_INTERN +os_thread_ret_t +DECLARE_THREAD(log_scrub_thread)( +/*===============================*/ + void* arg __attribute__((unused))) /*!< in: a dummy parameter + required by os_thread_create */ +{ + ut_ad(!srv_read_only_mode); + + srv_log_scrub_thread_active = TRUE; + + while(srv_shutdown_state == SRV_SHUTDOWN_NONE) + { + os_event_wait_time(log_scrub_event, innodb_scrub_log_interval * 1000); + + log_scrub(); + + os_event_reset(log_scrub_event); + } + + srv_log_scrub_thread_active = FALSE; + + /* We count the number of threads in os_thread_exit(). A created + thread should always use that to exit and not use return() to exit. */ + os_thread_exit(NULL); + + OS_THREAD_DUMMY_RETURN; +} #endif /* !UNIV_HOTBACKUP */ |