Commit 9505c968 authored by Marko Mäkelä's avatar Marko Mäkelä

MDEV-12428 SIGSEGV in buf_page_decrypt_after_read() during DDL

Also, some MDEV-11738/MDEV-11581 post-push fixes.

In MariaDB 10.1, there is no fil_space_t::is_being_truncated field,
and the predicates fil_space_t::stop_new_ops and fil_space_t::is_stopping()
are interchangeable. I requested the fil_space_t::is_stopping() to be added
in the review, but some added checks for fil_space_t::stop_new_ops were
not replaced with calls to fil_space_t::is_stopping().

buf_page_decrypt_after_read(): In this low-level I/O operation, we must
look up the tablespace if it exists, even though future I/O operations
have been blocked on it due to a pending DDL operation, such as DROP TABLE
or TRUNCATE TABLE or other table-rebuilding operations (ALTER, OPTIMIZE).
Pass a parameter to fil_space_acquire_low() telling that we are performing
a low-level I/O operation and the fil_space_t::is_stopping() status should
be ignored.
parent ac8218a0
...@@ -129,15 +129,15 @@ btr_scrub_lock_dict_func(ulint space_id, bool lock_to_close_table, ...@@ -129,15 +129,15 @@ btr_scrub_lock_dict_func(ulint space_id, bool lock_to_close_table,
* if we don't lock to close a table, we check if space * if we don't lock to close a table, we check if space
* is closing, and then instead give up * is closing, and then instead give up
*/ */
if (lock_to_close_table == false) { if (lock_to_close_table) {
fil_space_t* space = fil_space_acquire(space_id); } else if (fil_space_t* space = fil_space_acquire(space_id)) {
if (!space || space->stop_new_ops) { bool stopping = space->is_stopping();
if (space) {
fil_space_release(space); fil_space_release(space);
} if (stopping) {
return false; return false;
} }
fil_space_release(space); } else {
return false;
} }
os_thread_sleep(250000); os_thread_sleep(250000);
...@@ -197,18 +197,15 @@ btr_scrub_table_close_for_thread( ...@@ -197,18 +197,15 @@ btr_scrub_table_close_for_thread(
return; return;
} }
fil_space_t* space = fil_space_acquire(scrub_data->space); if (fil_space_t* space = fil_space_acquire(scrub_data->space)) {
/* If tablespace is not marked as stopping perform /* If tablespace is not marked as stopping perform
the actual close. */ the actual close. */
if (space && !space->is_stopping()) { if (!space->is_stopping()) {
mutex_enter(&dict_sys->mutex); mutex_enter(&dict_sys->mutex);
/* perform the actual closing */ /* perform the actual closing */
btr_scrub_table_close(scrub_data->current_table); btr_scrub_table_close(scrub_data->current_table);
mutex_exit(&dict_sys->mutex); mutex_exit(&dict_sys->mutex);
} }
if (space) {
fil_space_release(space); fil_space_release(space);
} }
......
...@@ -6250,13 +6250,12 @@ buf_page_decrypt_after_read( ...@@ -6250,13 +6250,12 @@ buf_page_decrypt_after_read(
return (true); return (true);
} }
fil_space_t* space = fil_space_acquire(bpage->space); fil_space_t* space = fil_space_acquire(bpage->space, true);
fil_space_crypt_t* crypt_data = space->crypt_data;
/* Page is encrypted if encryption information is found from /* Page is encrypted if encryption information is found from
tablespace and page contains used key_version. This is true tablespace and page contains used key_version. This is true
also for pages first compressed and then encrypted. */ also for pages first compressed and then encrypted. */
if (!crypt_data) { if (!space || !space->crypt_data) {
key_version = 0; key_version = 0;
} }
...@@ -6340,6 +6339,8 @@ buf_page_decrypt_after_read( ...@@ -6340,6 +6339,8 @@ buf_page_decrypt_after_read(
} }
} }
if (space != NULL) {
fil_space_release(space); fil_space_release(space);
}
return (success); return (success);
} }
...@@ -6325,15 +6325,11 @@ fil_flush( ...@@ -6325,15 +6325,11 @@ fil_flush(
{ {
mutex_enter(&fil_system->mutex); mutex_enter(&fil_system->mutex);
fil_space_t* space = fil_space_get_by_id(space_id); if (fil_space_t* space = fil_space_get_by_id(space_id)) {
if (!space->is_stopping()) {
if (!space || space->stop_new_ops) {
mutex_exit(&fil_system->mutex);
return;
}
fil_flush_low(space); fil_flush_low(space);
}
}
mutex_exit(&fil_system->mutex); mutex_exit(&fil_system->mutex);
} }
...@@ -6374,8 +6370,7 @@ fil_flush_file_spaces( ...@@ -6374,8 +6370,7 @@ fil_flush_file_spaces(
space; space;
space = UT_LIST_GET_NEXT(unflushed_spaces, space)) { space = UT_LIST_GET_NEXT(unflushed_spaces, space)) {
if (space->purpose == purpose && !space->stop_new_ops) { if (space->purpose == purpose && !space->is_stopping()) {
space_ids[n_space_ids++] = space->id; space_ids[n_space_ids++] = space->id;
} }
} }
...@@ -7276,12 +7271,13 @@ Used by background threads that do not necessarily hold proper locks ...@@ -7276,12 +7271,13 @@ Used by background threads that do not necessarily hold proper locks
for concurrency control. for concurrency control.
@param[in] id tablespace ID @param[in] id tablespace ID
@param[in] silent whether to silently ignore missing tablespaces @param[in] silent whether to silently ignore missing tablespaces
@return the tablespace, or NULL if missing or being deleted */ @param[in] for_io whether to look up the tablespace while performing I/O
(possibly executing TRUNCATE)
@return the tablespace
@retval NULL if missing or being deleted or truncated */
inline inline
fil_space_t* fil_space_t*
fil_space_acquire_low( fil_space_acquire_low(ulint id, bool silent, bool for_io = false)
ulint id,
bool silent)
{ {
fil_space_t* space; fil_space_t* space;
...@@ -7294,7 +7290,7 @@ fil_space_acquire_low( ...@@ -7294,7 +7290,7 @@ fil_space_acquire_low(
ib_logf(IB_LOG_LEVEL_WARN, "Trying to access missing" ib_logf(IB_LOG_LEVEL_WARN, "Trying to access missing"
" tablespace " ULINTPF ".", id); " tablespace " ULINTPF ".", id);
} }
} else if (space->stop_new_ops) { } else if (!for_io && space->is_stopping()) {
space = NULL; space = NULL;
} else { } else {
space->n_pending_ops++; space->n_pending_ops++;
...@@ -7309,22 +7305,24 @@ fil_space_acquire_low( ...@@ -7309,22 +7305,24 @@ fil_space_acquire_low(
Used by background threads that do not necessarily hold proper locks Used by background threads that do not necessarily hold proper locks
for concurrency control. for concurrency control.
@param[in] id tablespace ID @param[in] id tablespace ID
@return the tablespace, or NULL if missing or being deleted */ @param[in] for_io whether to look up the tablespace while performing I/O
(possibly executing TRUNCATE)
@return the tablespace
@retval NULL if missing or being deleted or truncated */
fil_space_t* fil_space_t*
fil_space_acquire( fil_space_acquire(ulint id, bool for_io)
ulint id)
{ {
return(fil_space_acquire_low(id, false)); return(fil_space_acquire_low(id, false, for_io));
} }
/** Acquire a tablespace that may not exist. /** Acquire a tablespace that may not exist.
Used by background threads that do not necessarily hold proper locks Used by background threads that do not necessarily hold proper locks
for concurrency control. for concurrency control.
@param[in] id tablespace ID @param[in] id tablespace ID
@return the tablespace, or NULL if missing or being deleted */ @return the tablespace
@retval NULL if missing or being deleted */
fil_space_t* fil_space_t*
fil_space_acquire_silent( fil_space_acquire_silent(ulint id)
ulint id)
{ {
return(fil_space_acquire_low(id, true)); return(fil_space_acquire_low(id, true));
} }
...@@ -7332,8 +7330,7 @@ fil_space_acquire_silent( ...@@ -7332,8 +7330,7 @@ fil_space_acquire_silent(
/** Release a tablespace acquired with fil_space_acquire(). /** Release a tablespace acquired with fil_space_acquire().
@param[in,out] space tablespace to release */ @param[in,out] space tablespace to release */
void void
fil_space_release( fil_space_release(fil_space_t* space)
fil_space_t* space)
{ {
mutex_enter(&fil_system->mutex); mutex_enter(&fil_system->mutex);
ut_ad(space->magic_n == FIL_SPACE_MAGIC_N); ut_ad(space->magic_n == FIL_SPACE_MAGIC_N);
...@@ -7351,8 +7348,7 @@ If NULL, use the first fil_space_t on fil_system->space_list. ...@@ -7351,8 +7348,7 @@ If NULL, use the first fil_space_t on fil_system->space_list.
@return pointer to the next fil_space_t. @return pointer to the next fil_space_t.
@retval NULL if this was the last*/ @retval NULL if this was the last*/
fil_space_t* fil_space_t*
fil_space_next( fil_space_next(fil_space_t* prev_space)
fil_space_t* prev_space)
{ {
fil_space_t* space=prev_space; fil_space_t* space=prev_space;
...@@ -7375,7 +7371,7 @@ fil_space_next( ...@@ -7375,7 +7371,7 @@ fil_space_next(
fil_ibd_create(), or dropped, or !tablespace. */ fil_ibd_create(), or dropped, or !tablespace. */
while (space != NULL while (space != NULL
&& (UT_LIST_GET_LEN(space->chain) == 0 && (UT_LIST_GET_LEN(space->chain) == 0
|| space->stop_new_ops || space->is_stopping()
|| space->purpose != FIL_TABLESPACE)) { || space->purpose != FIL_TABLESPACE)) {
space = UT_LIST_GET_NEXT(space_list, space); space = UT_LIST_GET_NEXT(space_list, space);
} }
......
...@@ -645,27 +645,28 @@ fil_write_flushed_lsn_to_data_files( ...@@ -645,27 +645,28 @@ fil_write_flushed_lsn_to_data_files(
Used by background threads that do not necessarily hold proper locks Used by background threads that do not necessarily hold proper locks
for concurrency control. for concurrency control.
@param[in] id tablespace ID @param[in] id tablespace ID
@return the tablespace, or NULL if missing or being deleted */ @param[in] for_io whether to look up the tablespace while performing I/O
(possibly executing TRUNCATE)
@return the tablespace
@retval NULL if missing or being deleted or truncated */
fil_space_t* fil_space_t*
fil_space_acquire( fil_space_acquire(ulint id, bool for_io = false)
ulint id)
MY_ATTRIBUTE((warn_unused_result)); MY_ATTRIBUTE((warn_unused_result));
/** Acquire a tablespace that may not exist. /** Acquire a tablespace that may not exist.
Used by background threads that do not necessarily hold proper locks Used by background threads that do not necessarily hold proper locks
for concurrency control. for concurrency control.
@param[in] id tablespace ID @param[in] id tablespace ID
@return the tablespace, or NULL if missing or being deleted */ @return the tablespace
@retval NULL if missing or being deleted */
fil_space_t* fil_space_t*
fil_space_acquire_silent( fil_space_acquire_silent(ulint id)
ulint id)
MY_ATTRIBUTE((warn_unused_result)); MY_ATTRIBUTE((warn_unused_result));
/** Release a tablespace acquired with fil_space_acquire(). /** Release a tablespace acquired with fil_space_acquire().
@param[in,out] space tablespace to release */ @param[in,out] space tablespace to release */
void void
fil_space_release( fil_space_release(fil_space_t* space);
fil_space_t* space);
/** Return the next fil_space_t. /** Return the next fil_space_t.
Once started, the caller must keep calling this until it returns NULL. Once started, the caller must keep calling this until it returns NULL.
......
...@@ -129,15 +129,15 @@ btr_scrub_lock_dict_func(ulint space_id, bool lock_to_close_table, ...@@ -129,15 +129,15 @@ btr_scrub_lock_dict_func(ulint space_id, bool lock_to_close_table,
* if we don't lock to close a table, we check if space * if we don't lock to close a table, we check if space
* is closing, and then instead give up * is closing, and then instead give up
*/ */
if (lock_to_close_table == false) { if (lock_to_close_table) {
fil_space_t* space = fil_space_acquire(space_id); } else if (fil_space_t* space = fil_space_acquire(space_id)) {
if (!space || space->stop_new_ops) { bool stopping = space->is_stopping();
if (space) {
fil_space_release(space); fil_space_release(space);
} if (stopping) {
return false; return false;
} }
fil_space_release(space); } else {
return false;
} }
os_thread_sleep(250000); os_thread_sleep(250000);
...@@ -197,18 +197,15 @@ btr_scrub_table_close_for_thread( ...@@ -197,18 +197,15 @@ btr_scrub_table_close_for_thread(
return; return;
} }
fil_space_t* space = fil_space_acquire(scrub_data->space); if (fil_space_t* space = fil_space_acquire(scrub_data->space)) {
/* If tablespace is not marked as stopping perform /* If tablespace is not marked as stopping perform
the actual close. */ the actual close. */
if (space && !space->is_stopping()) { if (!space->is_stopping()) {
mutex_enter(&dict_sys->mutex); mutex_enter(&dict_sys->mutex);
/* perform the actual closing */ /* perform the actual closing */
btr_scrub_table_close(scrub_data->current_table); btr_scrub_table_close(scrub_data->current_table);
mutex_exit(&dict_sys->mutex); mutex_exit(&dict_sys->mutex);
} }
if (space) {
fil_space_release(space); fil_space_release(space);
} }
......
...@@ -6410,14 +6410,12 @@ buf_page_decrypt_after_read( ...@@ -6410,14 +6410,12 @@ buf_page_decrypt_after_read(
return (true); return (true);
} }
fil_space_t* space = fil_space_acquire(bpage->space); fil_space_t* space = fil_space_acquire(bpage->space, true);
fil_space_crypt_t* crypt_data = space->crypt_data;
/* Page is encrypted if encryption information is found from /* Page is encrypted if encryption information is found from
tablespace and page contains used key_version. This is true tablespace and page contains used key_version. This is true
also for pages first compressed and then encrypted. */ also for pages first compressed and then encrypted. */
if (!crypt_data) { if (!space || !space->crypt_data) {
key_version = 0; key_version = 0;
} }
...@@ -6501,6 +6499,8 @@ buf_page_decrypt_after_read( ...@@ -6501,6 +6499,8 @@ buf_page_decrypt_after_read(
} }
} }
if (space != NULL) {
fil_space_release(space); fil_space_release(space);
}
return (success); return (success);
} }
...@@ -6389,15 +6389,11 @@ fil_flush( ...@@ -6389,15 +6389,11 @@ fil_flush(
{ {
mutex_enter(&fil_system->mutex); mutex_enter(&fil_system->mutex);
fil_space_t* space = fil_space_get_by_id(space_id); if (fil_space_t* space = fil_space_get_by_id(space_id)) {
if (!space->is_stopping()) {
if (!space || space->stop_new_ops) {
mutex_exit(&fil_system->mutex);
return;
}
fil_flush_low(space); fil_flush_low(space);
}
}
mutex_exit(&fil_system->mutex); mutex_exit(&fil_system->mutex);
} }
...@@ -6438,8 +6434,7 @@ fil_flush_file_spaces( ...@@ -6438,8 +6434,7 @@ fil_flush_file_spaces(
space; space;
space = UT_LIST_GET_NEXT(unflushed_spaces, space)) { space = UT_LIST_GET_NEXT(unflushed_spaces, space)) {
if (space->purpose == purpose && !space->stop_new_ops) { if (space->purpose == purpose && !space->is_stopping()) {
space_ids[n_space_ids++] = space->id; space_ids[n_space_ids++] = space->id;
} }
} }
...@@ -7388,12 +7383,13 @@ Used by background threads that do not necessarily hold proper locks ...@@ -7388,12 +7383,13 @@ Used by background threads that do not necessarily hold proper locks
for concurrency control. for concurrency control.
@param[in] id tablespace ID @param[in] id tablespace ID
@param[in] silent whether to silently ignore missing tablespaces @param[in] silent whether to silently ignore missing tablespaces
@return the tablespace, or NULL if missing or being deleted */ @param[in] for_io whether to look up the tablespace while performing I/O
(possibly executing TRUNCATE)
@return the tablespace
@retval NULL if missing or being deleted or truncated */
inline inline
fil_space_t* fil_space_t*
fil_space_acquire_low( fil_space_acquire_low(ulint id, bool silent, bool for_io = false)
ulint id,
bool silent)
{ {
fil_space_t* space; fil_space_t* space;
...@@ -7407,7 +7403,7 @@ fil_space_acquire_low( ...@@ -7407,7 +7403,7 @@ fil_space_acquire_low(
" tablespace " ULINTPF ".", id); " tablespace " ULINTPF ".", id);
ut_error; ut_error;
} }
} else if (space->stop_new_ops) { } else if (!for_io && space->is_stopping()) {
space = NULL; space = NULL;
} else { } else {
space->n_pending_ops++; space->n_pending_ops++;
...@@ -7422,22 +7418,24 @@ fil_space_acquire_low( ...@@ -7422,22 +7418,24 @@ fil_space_acquire_low(
Used by background threads that do not necessarily hold proper locks Used by background threads that do not necessarily hold proper locks
for concurrency control. for concurrency control.
@param[in] id tablespace ID @param[in] id tablespace ID
@return the tablespace, or NULL if missing or being deleted */ @param[in] for_io whether to look up the tablespace while performing I/O
(possibly executing TRUNCATE)
@return the tablespace
@retval NULL if missing or being deleted or truncated */
fil_space_t* fil_space_t*
fil_space_acquire( fil_space_acquire(ulint id, bool for_io)
ulint id)
{ {
return(fil_space_acquire_low(id, false)); return(fil_space_acquire_low(id, false, for_io));
} }
/** Acquire a tablespace that may not exist. /** Acquire a tablespace that may not exist.
Used by background threads that do not necessarily hold proper locks Used by background threads that do not necessarily hold proper locks
for concurrency control. for concurrency control.
@param[in] id tablespace ID @param[in] id tablespace ID
@return the tablespace, or NULL if missing or being deleted */ @return the tablespace
@retval NULL if missing or being deleted */
fil_space_t* fil_space_t*
fil_space_acquire_silent( fil_space_acquire_silent(ulint id)
ulint id)
{ {
return(fil_space_acquire_low(id, true)); return(fil_space_acquire_low(id, true));
} }
...@@ -7445,8 +7443,7 @@ fil_space_acquire_silent( ...@@ -7445,8 +7443,7 @@ fil_space_acquire_silent(
/** Release a tablespace acquired with fil_space_acquire(). /** Release a tablespace acquired with fil_space_acquire().
@param[in,out] space tablespace to release */ @param[in,out] space tablespace to release */
void void
fil_space_release( fil_space_release(fil_space_t* space)
fil_space_t* space)
{ {
mutex_enter(&fil_system->mutex); mutex_enter(&fil_system->mutex);
ut_ad(space->magic_n == FIL_SPACE_MAGIC_N); ut_ad(space->magic_n == FIL_SPACE_MAGIC_N);
...@@ -7464,8 +7461,7 @@ If NULL, use the first fil_space_t on fil_system->space_list. ...@@ -7464,8 +7461,7 @@ If NULL, use the first fil_space_t on fil_system->space_list.
@return pointer to the next fil_space_t. @return pointer to the next fil_space_t.
@retval NULL if this was the last*/ @retval NULL if this was the last*/
fil_space_t* fil_space_t*
fil_space_next( fil_space_next(fil_space_t* prev_space)
fil_space_t* prev_space)
{ {
fil_space_t* space=prev_space; fil_space_t* space=prev_space;
...@@ -7488,7 +7484,7 @@ fil_space_next( ...@@ -7488,7 +7484,7 @@ fil_space_next(
fil_ibd_create(), or dropped, or !tablespace. */ fil_ibd_create(), or dropped, or !tablespace. */
while (space != NULL while (space != NULL
&& (UT_LIST_GET_LEN(space->chain) == 0 && (UT_LIST_GET_LEN(space->chain) == 0
|| space->stop_new_ops || space->is_stopping()
|| space->purpose != FIL_TABLESPACE)) { || space->purpose != FIL_TABLESPACE)) {
space = UT_LIST_GET_NEXT(space_list, space); space = UT_LIST_GET_NEXT(space_list, space);
} }
......
...@@ -650,27 +650,28 @@ fil_write_flushed_lsn_to_data_files( ...@@ -650,27 +650,28 @@ fil_write_flushed_lsn_to_data_files(
Used by background threads that do not necessarily hold proper locks Used by background threads that do not necessarily hold proper locks
for concurrency control. for concurrency control.
@param[in] id tablespace ID @param[in] id tablespace ID
@return the tablespace, or NULL if missing or being deleted */ @param[in] for_io whether to look up the tablespace while performing I/O
(possibly executing TRUNCATE)
@return the tablespace
@retval NULL if missing or being deleted or truncated */
fil_space_t* fil_space_t*
fil_space_acquire( fil_space_acquire(ulint id, bool for_io = false)
ulint id)
MY_ATTRIBUTE((warn_unused_result)); MY_ATTRIBUTE((warn_unused_result));
/** Acquire a tablespace that may not exist. /** Acquire a tablespace that may not exist.
Used by background threads that do not necessarily hold proper locks Used by background threads that do not necessarily hold proper locks
for concurrency control. for concurrency control.
@param[in] id tablespace ID @param[in] id tablespace ID
@return the tablespace, or NULL if missing or being deleted */ @return the tablespace
@retval NULL if missing or being deleted */
fil_space_t* fil_space_t*
fil_space_acquire_silent( fil_space_acquire_silent(ulint id)
ulint id)
MY_ATTRIBUTE((warn_unused_result)); MY_ATTRIBUTE((warn_unused_result));
/** Release a tablespace acquired with fil_space_acquire(). /** Release a tablespace acquired with fil_space_acquire().
@param[in,out] space tablespace to release */ @param[in,out] space tablespace to release */
void void
fil_space_release( fil_space_release(fil_space_t* space);
fil_space_t* space);
/** Return the next fil_space_t. /** Return the next fil_space_t.
Once started, the caller must keep calling this until it returns NULL. Once started, the caller must keep calling this until it returns NULL.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment