Fix deadlock related to chunk_record().

Fix chunk_record() to unlock chunks_mtx before deallocating a base node,
in order to avoid potential deadlock.

Reported by Tudor Bosman.
This commit is contained in:
Jason Evans 2013-04-17 09:57:11 -07:00
parent 705328ca46
commit 741fbc6ba4

View File

@ -242,8 +242,6 @@ chunk_record(extent_tree_t *chunks_szad, extent_tree_t *chunks_ad, void *chunk,
node->size += size; node->size += size;
node->zeroed = (node->zeroed && (unzeroed == false)); node->zeroed = (node->zeroed && (unzeroed == false));
extent_tree_szad_insert(chunks_szad, node); extent_tree_szad_insert(chunks_szad, node);
if (xnode != NULL)
base_node_dealloc(xnode);
} else { } else {
/* Coalescing forward failed, so insert a new node. */ /* Coalescing forward failed, so insert a new node. */
if (xnode == NULL) { if (xnode == NULL) {
@ -253,10 +251,10 @@ chunk_record(extent_tree_t *chunks_szad, extent_tree_t *chunks_ad, void *chunk,
* already been purged, so this is only a virtual * already been purged, so this is only a virtual
* memory leak. * memory leak.
*/ */
malloc_mutex_unlock(&chunks_mtx); goto label_return;
return;
} }
node = xnode; node = xnode;
xnode = NULL; /* Prevent deallocation below. */
node->addr = chunk; node->addr = chunk;
node->size = size; node->size = size;
node->zeroed = (unzeroed == false); node->zeroed = (unzeroed == false);
@ -284,7 +282,16 @@ chunk_record(extent_tree_t *chunks_szad, extent_tree_t *chunks_ad, void *chunk,
base_node_dealloc(prev); base_node_dealloc(prev);
} }
label_return:
malloc_mutex_unlock(&chunks_mtx); malloc_mutex_unlock(&chunks_mtx);
if (xnode != NULL) {
/*
* Deallocate xnode after unlocking chunks_mtx in order to
* avoid potential deadlock.
*/
base_node_dealloc(xnode);
}
} }
void void