diff options
author | unknown <tsmith@quadxeon.mysql.com> | 2006-11-09 05:03:35 +0100 |
---|---|---|
committer | unknown <tsmith@quadxeon.mysql.com> | 2006-11-09 05:03:35 +0100 |
commit | 870b2e0a2b4a66c6b4b4f15792d72a7415190650 (patch) | |
tree | f2081688e779268ada8a2feaa56abff234501c7e /innobase/fil | |
parent | 671d863ca559a243cf029641a00a8480bd6ee5fa (diff) | |
download | mariadb-git-870b2e0a2b4a66c6b4b4f15792d72a7415190650.tar.gz |
This ChangeSet must be null-merged to 5.0. Applied innodb-4.1-ss33
Fixes:
- Bug #24089: Race condition in fil_flush_file_spaces()
innobase/fil/fil0fil.c:
Applied innodb-4.1-ss33
Revision r33:
innodb-4.1: Merge r1002 from innodb/trunk:
fil_flush_file_spaces(): Copy the system->unflushed_spaces list to an
array while holding the mutex. This removes the crash-triggering
race condition that was introduced when fixing Bug 15653. (Bug #24089)
Diffstat (limited to 'innobase/fil')
-rw-r--r-- | innobase/fil/fil0fil.c | 44 |
1 files changed, 31 insertions, 13 deletions
diff --git a/innobase/fil/fil0fil.c b/innobase/fil/fil0fil.c index c696c940790..b576e4f5a70 100644 --- a/innobase/fil/fil0fil.c +++ b/innobase/fil/fil0fil.c @@ -4252,29 +4252,47 @@ fil_flush_file_spaces( { fil_system_t* system = fil_system; fil_space_t* space; + ulint* space_ids; + ulint n_space_ids; + ulint i; mutex_enter(&(system->mutex)); - space = UT_LIST_GET_FIRST(system->unflushed_spaces); + n_space_ids = UT_LIST_GET_LEN(system->unflushed_spaces); + if (n_space_ids == 0) { - while (space) { - if (space->purpose == purpose && !space->is_being_deleted) { + mutex_exit(&system->mutex); + return; + } - space->n_pending_flushes++; /* prevent dropping of the - space while we are - flushing */ - mutex_exit(&(system->mutex)); + /* Assemble a list of space ids to flush. Previously, we + traversed system->unflushed_spaces and called UT_LIST_GET_NEXT() + on a space that was just removed from the list by fil_flush(). + Thus, the space could be dropped and the memory overwritten. */ + space_ids = mem_alloc(n_space_ids * sizeof *space_ids); - fil_flush(space->id); + n_space_ids = 0; - mutex_enter(&(system->mutex)); + for (space = UT_LIST_GET_FIRST(system->unflushed_spaces); + space; + space = UT_LIST_GET_NEXT(unflushed_spaces, space)) { + + if (space->purpose == purpose && !space->is_being_deleted) { - space->n_pending_flushes--; + space_ids[n_space_ids++] = space->id; } - space = UT_LIST_GET_NEXT(unflushed_spaces, space); } - - mutex_exit(&(system->mutex)); + + mutex_exit(&system->mutex); + + /* Flush the spaces. It will not hurt to call fil_flush() on + a non-existing space id. */ + for (i = 0; i < n_space_ids; i++) { + + fil_flush(space_ids[i]); + } + + mem_free(space_ids); } /********************************************************************** |