Commit 870b2e0a authored by unknown's avatar unknown
Browse files

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)
parent 671d863c
Loading
Loading
Loading
Loading
+31 −13
Original line number Diff line number Diff line
@@ -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)) {

			space->n_pending_flushes--;
		if (space->purpose == purpose && !space->is_being_deleted) {

			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);
}

/**********************************************************************