summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/vm/uma_core.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/vm/uma_core.c')
-rw-r--r--freebsd/sys/vm/uma_core.c58
1 files changed, 35 insertions, 23 deletions
diff --git a/freebsd/sys/vm/uma_core.c b/freebsd/sys/vm/uma_core.c
index effc64ad..bad12385 100644
--- a/freebsd/sys/vm/uma_core.c
+++ b/freebsd/sys/vm/uma_core.c
@@ -286,7 +286,7 @@ static void page_free(void *, vm_size_t, uint8_t);
#ifndef __rtems__
static void pcpu_page_free(void *, vm_size_t, uint8_t);
#endif /* __rtems__ */
-static uma_slab_t keg_alloc_slab(uma_keg_t, uma_zone_t, int, int);
+static uma_slab_t keg_alloc_slab(uma_keg_t, uma_zone_t, int, int, int);
static void cache_drain(uma_zone_t);
static void bucket_drain(uma_zone_t, uma_bucket_t);
static void bucket_cache_drain(uma_zone_t zone);
@@ -1120,20 +1120,22 @@ zone_drain(uma_zone_t zone)
* otherwise the keg will be left unlocked.
*
* Arguments:
- * wait Shall we wait?
+ * flags Wait flags for the item initialization routine
+ * aflags Wait flags for the slab allocation
*
* Returns:
* The slab that was allocated or NULL if there is no memory and the
* caller specified M_NOWAIT.
*/
static uma_slab_t
-keg_alloc_slab(uma_keg_t keg, uma_zone_t zone, int domain, int wait)
+keg_alloc_slab(uma_keg_t keg, uma_zone_t zone, int domain, int flags,
+ int aflags)
{
uma_alloc allocf;
uma_slab_t slab;
unsigned long size;
uint8_t *mem;
- uint8_t flags;
+ uint8_t sflags;
int i;
KASSERT(domain >= 0 && domain < vm_ndomains,
@@ -1146,7 +1148,7 @@ keg_alloc_slab(uma_keg_t keg, uma_zone_t zone, int domain, int wait)
slab = NULL;
mem = NULL;
if (keg->uk_flags & UMA_ZONE_OFFPAGE) {
- slab = zone_alloc_item(keg->uk_slabzone, NULL, domain, wait);
+ slab = zone_alloc_item(keg->uk_slabzone, NULL, domain, aflags);
if (slab == NULL)
goto out;
}
@@ -1159,16 +1161,16 @@ keg_alloc_slab(uma_keg_t keg, uma_zone_t zone, int domain, int wait)
*/
if ((keg->uk_flags & UMA_ZONE_MALLOC) == 0)
- wait |= M_ZERO;
+ aflags |= M_ZERO;
else
- wait &= ~M_ZERO;
+ aflags &= ~M_ZERO;
if (keg->uk_flags & UMA_ZONE_NODUMP)
- wait |= M_NODUMP;
+ aflags |= M_NODUMP;
/* zone is passed for legacy reasons. */
size = keg->uk_ppera * PAGE_SIZE;
- mem = allocf(zone, size, domain, &flags, wait);
+ mem = allocf(zone, size, domain, &sflags, aflags);
if (mem == NULL) {
if (keg->uk_flags & UMA_ZONE_OFFPAGE)
zone_free_item(keg->uk_slabzone, slab, NULL, SKIP_NONE);
@@ -1188,7 +1190,7 @@ keg_alloc_slab(uma_keg_t keg, uma_zone_t zone, int domain, int wait)
slab->us_keg = keg;
slab->us_data = mem;
slab->us_freecount = keg->uk_ipers;
- slab->us_flags = flags;
+ slab->us_flags = sflags;
slab->us_domain = domain;
BIT_FILL(SLAB_SETSIZE, &slab->us_free);
#ifdef INVARIANTS
@@ -1198,7 +1200,7 @@ keg_alloc_slab(uma_keg_t keg, uma_zone_t zone, int domain, int wait)
if (keg->uk_init != NULL) {
for (i = 0; i < keg->uk_ipers; i++)
if (keg->uk_init(slab->us_data + (keg->uk_rsize * i),
- keg->uk_size, wait) != 0)
+ keg->uk_size, flags) != 0)
break;
if (i != keg->uk_ipers) {
keg_free_slab(keg, slab, i);
@@ -2939,7 +2941,7 @@ restart:
msleep(keg, &keg->uk_lock, PVM, "keglimit", 0);
continue;
}
- slab = keg_alloc_slab(keg, zone, domain, aflags);
+ slab = keg_alloc_slab(keg, zone, domain, flags, aflags);
/*
* If we got a slab here it's safe to mark it partially used
* and return. We assume that the caller is going to remove
@@ -3866,7 +3868,7 @@ uma_prealloc(uma_zone_t zone, int items)
uma_domain_t dom;
uma_slab_t slab;
uma_keg_t keg;
- int domain, flags, slabs;
+ int aflags, domain, slabs;
keg = zone_first_keg(zone);
if (keg == NULL)
@@ -3875,17 +3877,27 @@ uma_prealloc(uma_zone_t zone, int items)
slabs = items / keg->uk_ipers;
if (slabs * keg->uk_ipers < items)
slabs++;
- flags = M_WAITOK;
- vm_domainset_iter_policy_ref_init(&di, &keg->uk_dr, &domain, &flags);
while (slabs-- > 0) {
- slab = keg_alloc_slab(keg, zone, domain, flags);
- if (slab == NULL)
- return;
- MPASS(slab->us_keg == keg);
- dom = &keg->uk_domain[slab->us_domain];
- LIST_INSERT_HEAD(&dom->ud_free_slab, slab, us_link);
- if (vm_domainset_iter_policy(&di, &domain) != 0)
- break;
+ aflags = M_NOWAIT;
+ vm_domainset_iter_policy_ref_init(&di, &keg->uk_dr, &domain,
+ &aflags);
+ for (;;) {
+ slab = keg_alloc_slab(keg, zone, domain, M_WAITOK,
+ aflags);
+ if (slab != NULL) {
+ MPASS(slab->us_keg == keg);
+ dom = &keg->uk_domain[slab->us_domain];
+ LIST_INSERT_HEAD(&dom->ud_free_slab, slab,
+ us_link);
+ break;
+ }
+ KEG_LOCK(keg);
+ if (vm_domainset_iter_policy(&di, &domain) != 0) {
+ KEG_UNLOCK(keg);
+ vm_wait_doms(&keg->uk_dr.dr_policy->ds_mask);
+ KEG_LOCK(keg);
+ }
+ }
}
KEG_UNLOCK(keg);
}