diff options
author | jeff <jeff@FreeBSD.org> | 2002-05-13 05:08:18 +0000 |
---|---|---|
committer | jeff <jeff@FreeBSD.org> | 2002-05-13 05:08:18 +0000 |
commit | 7b96796a72f59117d800cf5406c3de05cad1d43c (patch) | |
tree | 8614ce5746f83b45db2523cc42c33d1732094ed4 /sys | |
parent | 08b1ec116047eb21b3e5e07675847989c2d2ef90 (diff) | |
download | FreeBSD-src-7b96796a72f59117d800cf5406c3de05cad1d43c.zip FreeBSD-src-7b96796a72f59117d800cf5406c3de05cad1d43c.tar.gz |
Don't call the uz free function while the zone lock is held. This can lead
to lock order reversals. uma_reclaim now builds a list of freeable slabs and
then unlocks the zones to do all of the frees.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/vm/uma_core.c | 35 |
1 files changed, 21 insertions, 14 deletions
diff --git a/sys/vm/uma_core.c b/sys/vm/uma_core.c index 0274ccb..df79668 100644 --- a/sys/vm/uma_core.c +++ b/sys/vm/uma_core.c @@ -575,6 +575,7 @@ cache_drain(uma_zone_t zone) static void zone_drain(uma_zone_t zone) { + struct slabhead freeslabs = {}; uma_slab_t slab; uma_slab_t n; u_int64_t extra; @@ -621,6 +622,26 @@ zone_drain(uma_zone_t zone) LIST_REMOVE(slab, us_link); zone->uz_pages -= zone->uz_ppera; zone->uz_free -= zone->uz_ipers; + + if (zone->uz_flags & UMA_ZFLAG_MALLOC) { + mtx_lock(&malloc_mtx); + UMA_HASH_REMOVE(mallochash, slab, slab->us_data); + mtx_unlock(&malloc_mtx); + } + if (zone->uz_flags & UMA_ZFLAG_OFFPAGE && + !(zone->uz_flags & UMA_ZFLAG_MALLOC)) + UMA_HASH_REMOVE(&zone->uz_hash, slab, slab->us_data); + + SLIST_INSERT_HEAD(&freeslabs, slab, us_hlink); + + slab = n; + extra--; + } +finished: + ZONE_UNLOCK(zone); + + while ((slab = SLIST_FIRST(&freeslabs)) != NULL) { + SLIST_REMOVE(&freeslabs, slab, uma_slab, us_hlink); if (zone->uz_fini) for (i = 0; i < zone->uz_ipers; i++) zone->uz_fini( @@ -628,16 +649,7 @@ zone_drain(uma_zone_t zone) zone->uz_size); flags = slab->us_flags; mem = slab->us_data; - if (zone->uz_flags & UMA_ZFLAG_MALLOC) { - mtx_lock(&malloc_mtx); - UMA_HASH_REMOVE(mallochash, slab, slab->us_data); - mtx_unlock(&malloc_mtx); - } if (zone->uz_flags & UMA_ZFLAG_OFFPAGE) { - if (!(zone->uz_flags & UMA_ZFLAG_MALLOC)) { - UMA_HASH_REMOVE(&zone->uz_hash, - slab, slab->us_data); - } uma_zfree_internal(slabzone, slab, NULL, 0); } #ifdef UMA_DEBUG @@ -645,13 +657,8 @@ zone_drain(uma_zone_t zone) zone->uz_name, UMA_SLAB_SIZE * zone->uz_ppera); #endif zone->uz_freef(mem, UMA_SLAB_SIZE * zone->uz_ppera, flags); - - slab = n; - extra--; } -finished: - ZONE_UNLOCK(zone); } /* |