Ensure a minimum of one slab is reclaimed

To minimize the chance of triggering an OOM during direct reclaim.
The kmem caches have been improved to make a best effort to reclaim
at least one slab when a reclaim function is registered.  This helps
avoid the case where objects are released but they are spread over
multiple slabs so no memory gets reclaimed.

Care has been taken to avoid deadlocking if the reclaim function
is unable to make forward progress.  Additionally, the reclaim
function may be skipped entirely if there are already free slabs
which can be safely reaped.

Signed-off-by: Prakash Surya <surya1@llnl.gov>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #107
This commit is contained in:
Brian Behlendorf 2012-05-01 14:27:29 -07:00
parent 06089b9e19
commit b78d4b9d98

View File

@ -1923,9 +1923,39 @@ spl_kmem_cache_reap_now(spl_kmem_cache_t *skc, int count)
atomic_inc(&skc->skc_ref); atomic_inc(&skc->skc_ref);
if (skc->skc_reclaim) /*
* When a reclaim function is available it may be invoked repeatedly
* until at least a single slab can be freed. This ensures that we
* do free memory back to the system. This helps minimize the chance
* of an OOM event when the bulk of memory is used by the slab.
*
* When free slabs are already available the reclaim callback will be
* skipped. Additionally, if no forward progress is detected despite
* a reclaim function the cache will be skipped to avoid deadlock.
*
* Longer term this would be the correct place to add the code which
* repacks the slabs in order minimize fragmentation.
*/
if (skc->skc_reclaim) {
uint64_t objects = UINT64_MAX;
int do_reclaim;
do {
spin_lock(&skc->skc_lock);
do_reclaim =
(skc->skc_slab_total > 0) &&
((skc->skc_slab_total - skc->skc_slab_alloc) == 0) &&
(skc->skc_obj_alloc < objects);
objects = skc->skc_obj_alloc;
spin_unlock(&skc->skc_lock);
if (do_reclaim)
skc->skc_reclaim(skc->skc_private); skc->skc_reclaim(skc->skc_private);
} while (do_reclaim);
}
/* Reclaim from the cache, ignoring it's age and delay. */ /* Reclaim from the cache, ignoring it's age and delay. */
spl_slab_reclaim(skc, count, 1); spl_slab_reclaim(skc, count, 1);
clear_bit(KMC_BIT_REAPING, &skc->skc_flags); clear_bit(KMC_BIT_REAPING, &skc->skc_flags);