Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F142059237
D22470.id64917.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
12 KB
Referenced Files
None
Subscribers
None
D22470.id64917.diff
View Options
Index: head/sys/vm/uma_core.c
===================================================================
--- head/sys/vm/uma_core.c
+++ head/sys/vm/uma_core.c
@@ -273,7 +273,7 @@
static uma_bucket_t bucket_alloc(uma_zone_t zone, void *, int);
static void bucket_free(uma_zone_t zone, uma_bucket_t, void *);
static void bucket_zone_drain(void);
-static uma_bucket_t zone_alloc_bucket(uma_zone_t, void *, int, int, int);
+static uma_bucket_t zone_alloc_bucket(uma_zone_t, void *, int, int);
static uma_slab_t zone_fetch_slab(uma_zone_t, uma_keg_t, int, int);
static void *slab_alloc_item(uma_keg_t keg, uma_slab_t slab);
static void slab_free_item(uma_zone_t zone, uma_slab_t slab, void *item);
@@ -282,6 +282,7 @@
static int zone_import(uma_zone_t, void **, int, int, int);
static void zone_release(uma_zone_t, void **, int);
static void uma_zero_item(void *, uma_zone_t);
+static bool cache_alloc(uma_zone_t, uma_cache_t, void *, int);
void uma_print_zone(uma_zone_t);
void uma_print_stats(void);
@@ -2441,18 +2442,58 @@
uma_zfree_arg(zone, item, udata);
}
+static inline void *
+bucket_pop(uma_zone_t zone, uma_cache_t cache, uma_bucket_t bucket)
+{
+ void *item;
+
+ bucket->ub_cnt--;
+ item = bucket->ub_bucket[bucket->ub_cnt];
+#ifdef INVARIANTS
+ bucket->ub_bucket[bucket->ub_cnt] = NULL;
+ KASSERT(item != NULL, ("uma_zalloc: Bucket pointer mangled."));
+#endif
+ cache->uc_allocs++;
+
+ return (item);
+}
+
+static void *
+item_ctor(uma_zone_t zone, void *udata, int flags, void *item)
+{
+#ifdef INVARIANTS
+ int skipdbg;
+
+ skipdbg = uma_dbg_zskip(zone, item);
+ if (zone->uz_ctor != NULL &&
+ (!skipdbg || zone->uz_ctor != trash_ctor ||
+ zone->uz_dtor != trash_dtor) &&
+#else
+ if (__predict_false(zone->uz_ctor != NULL) &&
+#endif
+ zone->uz_ctor(item, zone->uz_size, udata, flags) != 0) {
+ counter_u64_add(zone->uz_fails, 1);
+ zone_free_item(zone, item, udata, SKIP_DTOR | SKIP_CNT);
+ return (NULL);
+ }
+#ifdef INVARIANTS
+ if (!skipdbg)
+ uma_dbg_alloc(zone, NULL, item);
+#endif
+ if (flags & M_ZERO)
+ uma_zero_item(item, zone);
+
+ return (item);
+}
+
/* See uma.h */
void *
uma_zalloc_arg(uma_zone_t zone, void *udata, int flags)
{
- uma_zone_domain_t zdom;
uma_bucket_t bucket;
uma_cache_t cache;
void *item;
- int cpu, domain, lockfail, maxbucket;
-#ifdef INVARIANTS
- bool skipdbg;
-#endif
+ int cpu, domain;
/* Enable entropy collection for RANDOM_ENABLE_UMA kernel option */
random_harvest_fast_uma(&zone, sizeof(zone), RANDOM_UMA);
@@ -2501,56 +2542,55 @@
* the current cache; when we re-acquire the critical section, we
* must detect and handle migration if it has occurred.
*/
-zalloc_restart:
critical_enter();
- cpu = curcpu;
- cache = &zone->uz_cpu[cpu];
-
-zalloc_start:
- bucket = cache->uc_allocbucket;
- if (bucket != NULL && bucket->ub_cnt > 0) {
- bucket->ub_cnt--;
- item = bucket->ub_bucket[bucket->ub_cnt];
-#ifdef INVARIANTS
- bucket->ub_bucket[bucket->ub_cnt] = NULL;
-#endif
- KASSERT(item != NULL, ("uma_zalloc: Bucket pointer mangled."));
- cache->uc_allocs++;
- critical_exit();
-#ifdef INVARIANTS
- skipdbg = uma_dbg_zskip(zone, item);
-#endif
- if (zone->uz_ctor != NULL &&
-#ifdef INVARIANTS
- (!skipdbg || zone->uz_ctor != trash_ctor ||
- zone->uz_dtor != trash_dtor) &&
-#endif
- zone->uz_ctor(item, zone->uz_size, udata, flags) != 0) {
- counter_u64_add(zone->uz_fails, 1);
- zone_free_item(zone, item, udata, SKIP_DTOR | SKIP_CNT);
- return (NULL);
+ do {
+ cpu = curcpu;
+ cache = &zone->uz_cpu[cpu];
+ bucket = cache->uc_allocbucket;
+ if (__predict_true(bucket != NULL && bucket->ub_cnt != 0)) {
+ item = bucket_pop(zone, cache, bucket);
+ critical_exit();
+ return (item_ctor(zone, udata, flags, item));
}
-#ifdef INVARIANTS
- if (!skipdbg)
- uma_dbg_alloc(zone, NULL, item);
-#endif
- if (flags & M_ZERO)
- uma_zero_item(item, zone);
- return (item);
- }
+ } while (cache_alloc(zone, cache, udata, flags));
+ critical_exit();
/*
- * We have run out of items in our alloc bucket.
- * See if we can switch with our free bucket.
+ * We can not get a bucket so try to return a single item.
*/
+ if (zone->uz_flags & UMA_ZONE_NUMA)
+ domain = PCPU_GET(domain);
+ else
+ domain = UMA_ANYDOMAIN;
+ return (zone_alloc_item_locked(zone, udata, domain, flags));
+}
+
+/*
+ * Replenish an alloc bucket and possibly restore an old one. Called in
+ * a critical section. Returns in a critical section.
+ *
+ * A false return value indicates failure and returns with the zone lock
+ * held. A true return value indicates success and the caller should retry.
+ */
+static __noinline bool
+cache_alloc(uma_zone_t zone, uma_cache_t cache, void *udata, int flags)
+{
+ uma_zone_domain_t zdom;
+ uma_bucket_t bucket;
+ int cpu, domain;
+ bool lockfail;
+
+ CRITICAL_ASSERT(curthread);
+
+ /*
+ * If we have run out of items in our alloc bucket see
+ * if we can switch with the free bucket.
+ */
bucket = cache->uc_freebucket;
- if (bucket != NULL && bucket->ub_cnt > 0) {
- CTR2(KTR_UMA,
- "uma_zalloc: zone %s(%p) swapping empty with alloc",
- zone->uz_name, zone);
+ if (bucket != NULL && bucket->ub_cnt != 0) {
cache->uc_freebucket = cache->uc_allocbucket;
cache->uc_allocbucket = bucket;
- goto zalloc_start;
+ return (true);
}
/*
@@ -2562,16 +2602,6 @@
if (bucket != NULL)
bucket_free(zone, bucket, udata);
- /* Short-circuit for zones without buckets and low memory. */
- if (zone->uz_count == 0 || bucketdisable) {
- ZONE_LOCK(zone);
- if (zone->uz_flags & UMA_ZONE_NUMA)
- domain = PCPU_GET(domain);
- else
- domain = UMA_ANYDOMAIN;
- goto zalloc_item;
- }
-
/*
* Attempt to retrieve the item from the per-CPU cache has failed, so
* we must go back to the zone. This requires the zone lock, so we
@@ -2587,14 +2617,19 @@
ZONE_LOCK(zone);
lockfail = 1;
}
+
critical_enter();
+ /* Short-circuit for zones without buckets and low memory. */
+ if (zone->uz_count == 0 || bucketdisable)
+ return (false);
+
cpu = curcpu;
cache = &zone->uz_cpu[cpu];
/* See if we lost the race to fill the cache. */
if (cache->uc_allocbucket != NULL) {
ZONE_UNLOCK(zone);
- goto zalloc_start;
+ return (true);
}
/*
@@ -2609,11 +2644,11 @@
}
if ((bucket = zone_fetch_bucket(zone, zdom)) != NULL) {
+ ZONE_UNLOCK(zone);
KASSERT(bucket->ub_cnt != 0,
("uma_zalloc_arg: Returning an empty bucket."));
cache->uc_allocbucket = bucket;
- ZONE_UNLOCK(zone);
- goto zalloc_start;
+ return (true);
}
/* We are no longer associated with this CPU. */
critical_exit();
@@ -2625,71 +2660,39 @@
if (lockfail && zone->uz_count < zone->uz_count_max)
zone->uz_count++;
- if (zone->uz_max_items > 0) {
- if (zone->uz_items >= zone->uz_max_items)
- goto zalloc_item;
- maxbucket = MIN(zone->uz_count,
- zone->uz_max_items - zone->uz_items);
- zone->uz_items += maxbucket;
- } else
- maxbucket = zone->uz_count;
- ZONE_UNLOCK(zone);
-
/*
- * Now lets just fill a bucket and put it on the free list. If that
- * works we'll restart the allocation from the beginning and it
- * will use the just filled bucket.
+ * Fill a bucket and attempt to use it as the alloc bucket.
*/
- bucket = zone_alloc_bucket(zone, udata, domain, flags, maxbucket);
+ bucket = zone_alloc_bucket(zone, udata, domain, flags);
CTR3(KTR_UMA, "uma_zalloc: zone %s(%p) bucket zone returned %p",
zone->uz_name, zone, bucket);
- ZONE_LOCK(zone);
- if (bucket != NULL) {
- if (zone->uz_max_items > 0 && bucket->ub_cnt < maxbucket) {
- MPASS(zone->uz_items >= maxbucket - bucket->ub_cnt);
- zone->uz_items -= maxbucket - bucket->ub_cnt;
- if (zone->uz_sleepers > 0 &&
- zone->uz_items < zone->uz_max_items)
- wakeup_one(zone);
- }
- critical_enter();
- cpu = curcpu;
- cache = &zone->uz_cpu[cpu];
+ critical_enter();
+ if (bucket == NULL)
+ return (false);
- /*
- * See if we lost the race or were migrated. Cache the
- * initialized bucket to make this less likely or claim
- * the memory directly.
- */
- if (cache->uc_allocbucket == NULL &&
- ((zone->uz_flags & UMA_ZONE_NUMA) == 0 ||
- domain == PCPU_GET(domain))) {
- cache->uc_allocbucket = bucket;
- zdom->uzd_imax += bucket->ub_cnt;
- } else if (zone->uz_bkt_count >= zone->uz_bkt_max) {
- critical_exit();
- ZONE_UNLOCK(zone);
- bucket_drain(zone, bucket);
- bucket_free(zone, bucket, udata);
- goto zalloc_restart;
- } else
- zone_put_bucket(zone, zdom, bucket, false);
- ZONE_UNLOCK(zone);
- goto zalloc_start;
- } else if (zone->uz_max_items > 0) {
- zone->uz_items -= maxbucket;
- if (zone->uz_sleepers > 0 &&
- zone->uz_items + 1 < zone->uz_max_items)
- wakeup_one(zone);
- }
-
/*
- * We may not be able to get a bucket so return an actual item.
+ * See if we lost the race or were migrated. Cache the
+ * initialized bucket to make this less likely or claim
+ * the memory directly.
*/
-zalloc_item:
- item = zone_alloc_item_locked(zone, udata, domain, flags);
-
- return (item);
+ cpu = curcpu;
+ cache = &zone->uz_cpu[cpu];
+ if (cache->uc_allocbucket == NULL &&
+ ((zone->uz_flags & UMA_ZONE_NUMA) == 0 ||
+ domain == PCPU_GET(domain))) {
+ cache->uc_allocbucket = bucket;
+ zdom->uzd_imax += bucket->ub_cnt;
+ } else if (zone->uz_bkt_count >= zone->uz_bkt_max) {
+ critical_exit();
+ ZONE_UNLOCK(zone);
+ bucket_drain(zone, bucket);
+ bucket_free(zone, bucket, udata);
+ critical_enter();
+ return (true);
+ } else
+ zone_put_bucket(zone, zdom, bucket, false);
+ ZONE_UNLOCK(zone);
+ return (true);
}
void *
@@ -2943,9 +2946,10 @@
}
static uma_bucket_t
-zone_alloc_bucket(uma_zone_t zone, void *udata, int domain, int flags, int max)
+zone_alloc_bucket(uma_zone_t zone, void *udata, int domain, int flags)
{
uma_bucket_t bucket;
+ int maxbucket, cnt;
CTR1(KTR_UMA, "zone_alloc:_bucket domain %d)", domain);
@@ -2953,13 +2957,25 @@
if (domain != UMA_ANYDOMAIN && VM_DOMAIN_EMPTY(domain))
domain = UMA_ANYDOMAIN;
+ if (zone->uz_max_items > 0) {
+ if (zone->uz_items >= zone->uz_max_items)
+ return (false);
+ maxbucket = MIN(zone->uz_count,
+ zone->uz_max_items - zone->uz_items);
+ zone->uz_items += maxbucket;
+ } else
+ maxbucket = zone->uz_count;
+ ZONE_UNLOCK(zone);
+
/* Don't wait for buckets, preserve caller's NOVM setting. */
bucket = bucket_alloc(zone, udata, M_NOWAIT | (flags & M_NOVM));
- if (bucket == NULL)
- return (NULL);
+ if (bucket == NULL) {
+ cnt = 0;
+ goto out;
+ }
bucket->ub_cnt = zone->uz_import(zone->uz_arg, bucket->ub_bucket,
- MIN(max, bucket->ub_entries), domain, flags);
+ MIN(maxbucket, bucket->ub_entries), domain, flags);
/*
* Initialize the memory if necessary.
@@ -2986,11 +3002,22 @@
}
}
+ cnt = bucket->ub_cnt;
if (bucket->ub_cnt == 0) {
bucket_free(zone, bucket, udata);
counter_u64_add(zone->uz_fails, 1);
- return (NULL);
+ bucket = NULL;
}
+out:
+ ZONE_LOCK(zone);
+ if (zone->uz_max_items > 0 && cnt < maxbucket) {
+ MPASS(zone->uz_items >= maxbucket - cnt);
+ zone->uz_items -= maxbucket - cnt;
+ if (zone->uz_sleepers > 0 &&
+ (cnt == 0 ? zone->uz_items + 1 : zone->uz_items) <
+ zone->uz_max_items)
+ wakeup_one(zone);
+ }
return (bucket);
}
@@ -3024,9 +3051,6 @@
zone_alloc_item_locked(uma_zone_t zone, void *udata, int domain, int flags)
{
void *item;
-#ifdef INVARIANTS
- bool skipdbg;
-#endif
ZONE_LOCK_ASSERT(zone);
@@ -3057,11 +3081,8 @@
domain = UMA_ANYDOMAIN;
if (zone->uz_import(zone->uz_arg, &item, 1, domain, flags) != 1)
- goto fail;
+ goto fail_cnt;
-#ifdef INVARIANTS
- skipdbg = uma_dbg_zskip(zone, item);
-#endif
/*
* We have to call both the zone's init (not the keg's init)
* and the zone's ctor. This is because the item is going from
@@ -3071,24 +3092,12 @@
if (zone->uz_init != NULL) {
if (zone->uz_init(item, zone->uz_size, flags) != 0) {
zone_free_item(zone, item, udata, SKIP_FINI | SKIP_CNT);
- goto fail;
+ goto fail_cnt;
}
}
- if (zone->uz_ctor != NULL &&
-#ifdef INVARIANTS
- (!skipdbg || zone->uz_ctor != trash_ctor ||
- zone->uz_dtor != trash_dtor) &&
-#endif
- zone->uz_ctor(item, zone->uz_size, udata, flags) != 0) {
- zone_free_item(zone, item, udata, SKIP_DTOR | SKIP_CNT);
+ item = item_ctor(zone, udata, flags, item);
+ if (item == NULL)
goto fail;
- }
-#ifdef INVARIANTS
- if (!skipdbg)
- uma_dbg_alloc(zone, NULL, item);
-#endif
- if (flags & M_ZERO)
- uma_zero_item(item, zone);
counter_u64_add(zone->uz_allocs, 1);
CTR3(KTR_UMA, "zone_alloc_item item %p from %s(%p)", item,
@@ -3096,13 +3105,15 @@
return (item);
+fail_cnt:
+ counter_u64_add(zone->uz_fails, 1);
fail:
if (zone->uz_max_items > 0) {
ZONE_LOCK(zone);
+ /* XXX Decrement without wakeup */
zone->uz_items--;
ZONE_UNLOCK(zone);
}
- counter_u64_add(zone->uz_fails, 1);
CTR2(KTR_UMA, "zone_alloc_item failed from %s(%p)",
zone->uz_name, zone);
return (NULL);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Jan 16, 3:08 PM (2 h, 1 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27661647
Default Alt Text
D22470.id64917.diff (12 KB)
Attached To
Mode
D22470: Partial refactoring of uma_zalloc_arg().
Attached
Detach File
Event Timeline
Log In to Comment