Never spin in kmem_cache_alloc()

If we are reaping from the cache and a concurrent allocation
occurs then the caller must block until the reaping is complete.
This is signaled by the clearing of the KMC_BIT_REAPING bit.

Otherwise the caller will be in a tight loop which takes and
releases the skc->skc_cache lock.  When there are multiple
concurrent callers the system will thrash on the lock and
appear to lock up.

Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
This commit is contained in:
Brian Behlendorf 2012-11-05 13:54:20 -08:00
parent a1af8fb1ea
commit dc1b30224f

View File

@ -1725,6 +1725,13 @@ spl_cache_grow_wait(spl_kmem_cache_t *skc)
return !test_bit(KMC_BIT_GROWING, &skc->skc_flags); return !test_bit(KMC_BIT_GROWING, &skc->skc_flags);
} }
static int
spl_cache_reclaim_wait(void *word)
{
schedule();
return 0;
}
/* /*
* No available objects on any slabs, create a new slab. * No available objects on any slabs, create a new slab.
*/ */
@ -1739,12 +1746,14 @@ spl_cache_grow(spl_kmem_cache_t *skc, int flags, void **obj)
*obj = NULL; *obj = NULL;
/* /*
* Before allocating a new slab check if the slab is being reaped. * Before allocating a new slab wait for any reaping to complete and
* If it is there is a good chance we can wait until it finishes * then return so the local magazine can be rechecked for new objects.
* and then use one of the newly freed but not aged-out slabs.
*/ */
if (test_bit(KMC_BIT_REAPING, &skc->skc_flags)) if (test_bit(KMC_BIT_REAPING, &skc->skc_flags)) {
SRETURN(-EAGAIN); rc = wait_on_bit(&skc->skc_flags, KMC_BIT_REAPING,
spl_cache_reclaim_wait, TASK_UNINTERRUPTIBLE);
SRETURN(rc ? rc : -EAGAIN);
}
/* /*
* This is handled by dispatching a work request to the global work * This is handled by dispatching a work request to the global work
@ -2156,6 +2165,9 @@ spl_kmem_cache_reap_now(spl_kmem_cache_t *skc, int count)
/* 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);
smp_mb__after_clear_bit();
wake_up_bit(&skc->skc_flags, KMC_BIT_REAPING);
atomic_dec(&skc->skc_ref); atomic_dec(&skc->skc_ref);
SEXIT; SEXIT;