Fix an extent [de]allocation/[de]registration race.

Deregister extents before deallocation, so that subsequent
reallocation/registration doesn't race with deregistration.
This commit is contained in:
Jason Evans 2016-06-05 20:39:25 -07:00
parent 4e910fc958
commit 9a645c612f

View File

@ -298,6 +298,13 @@ extent_register(tsdn_t *tsdn, const extent_t *extent)
return (false); return (false);
} }
static void
extent_reregister(tsdn_t *tsdn, const extent_t *extent)
{
bool err = extent_register(tsdn, extent);
assert(!err);
}
static void static void
extent_interior_deregister(tsdn_t *tsdn, rtree_ctx_t *rtree_ctx, extent_interior_deregister(tsdn_t *tsdn, rtree_ctx_t *rtree_ctx,
const extent_t *extent) const extent_t *extent)
@ -314,7 +321,7 @@ extent_interior_deregister(tsdn_t *tsdn, rtree_ctx_t *rtree_ctx,
} }
static void static void
extent_deregister(tsdn_t *tsdn, const extent_t *extent) extent_deregister(tsdn_t *tsdn, extent_t *extent)
{ {
rtree_ctx_t rtree_ctx_fallback; rtree_ctx_t rtree_ctx_fallback;
rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback);
@ -323,8 +330,10 @@ extent_deregister(tsdn_t *tsdn, const extent_t *extent)
extent_rtree_acquire(tsdn, rtree_ctx, extent, true, false, &elm_a, extent_rtree_acquire(tsdn, rtree_ctx, extent, true, false, &elm_a,
&elm_b); &elm_b);
extent_rtree_write_acquired(tsdn, elm_a, elm_b, NULL); extent_rtree_write_acquired(tsdn, elm_a, elm_b, NULL);
if (extent_slab_get(extent)) if (extent_slab_get(extent)) {
extent_interior_deregister(tsdn, rtree_ctx, extent); extent_interior_deregister(tsdn, rtree_ctx, extent);
extent_slab_set(extent, false);
}
extent_rtree_release(tsdn, elm_a, elm_b); extent_rtree_release(tsdn, elm_a, elm_b);
if (config_prof && opt_prof && extent_active_get(extent)) { if (config_prof && opt_prof && extent_active_get(extent)) {
@ -782,14 +791,18 @@ extent_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena,
extent_addr_set(extent, extent_base_get(extent)); extent_addr_set(extent, extent_base_get(extent));
extent_hooks_assure_initialized(arena, r_extent_hooks); extent_hooks_assure_initialized(arena, r_extent_hooks);
/* Try to deallocate. */ /*
* Try to deallocate. Deregister first to avoid a race with other
* allocating threads, and reregister if deallocation fails.
*/
extent_deregister(tsdn, extent);
if (!(*r_extent_hooks)->dalloc(*r_extent_hooks, extent_base_get(extent), if (!(*r_extent_hooks)->dalloc(*r_extent_hooks, extent_base_get(extent),
extent_size_get(extent), extent_committed_get(extent), extent_size_get(extent), extent_committed_get(extent),
arena->ind)) { arena->ind)) {
extent_deregister(tsdn, extent);
extent_dalloc(tsdn, arena, extent); extent_dalloc(tsdn, arena, extent);
return; return;
} }
extent_reregister(tsdn, extent);
/* Try to decommit; purge if that fails. */ /* Try to decommit; purge if that fails. */
if (extent_committed_get(extent)) { if (extent_committed_get(extent)) {
extent_committed_set(extent, extent_committed_set(extent,