From 2dca52f047ad2ee18ce4c65ab233be6df5f5c94f Mon Sep 17 00:00:00 2001 From: markj Date: Sun, 6 Dec 2020 22:45:39 +0000 Subject: [PATCH] uma: Enforce the use of uz_bucket_size_max in the free path uz_bucket_size_max is the maximum permitted bucket size. When filling a new bucket to satisfy uma_zalloc(), the bucket is populated with at most uz_bucket_size_max items. The maximum number of entries in the bucket may be larger. When freeing items, however, we will fill per-CPPU buckets up to their maximum number of entries, potentially exceeding uz_bucket_size_max. This makes it difficult to precisely limit the number of items that may be cached in a zone. For example, if one wants to limit buckets to 1 entry for a particular zone, that's not possible since the smallest bucket holds up to 2 entries. Try to solve the problem by using uz_bucket_size_max to limit the number of entries in a bucket. Note that the ub_entries field is initialized upon every bucket allocation. Most zones are not affected since they do not impose any specific limit on the maximum bucket size. While here, remove the UMA_ZONE_MINBUCKET flag. It was unused and we now have uma_zone_set_maxcache() to control the zone's cache size more precisely. Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D27167 --- sys/vm/uma.h | 1 - sys/vm/uma_core.c | 8 +++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/sys/vm/uma.h b/sys/vm/uma.h index 634c1103b0b6..eac55e63f33d 100644 --- a/sys/vm/uma.h +++ b/sys/vm/uma.h @@ -250,7 +250,6 @@ uma_zone_t uma_zcache_create(const char *name, int size, uma_ctor ctor, #define UMA_ZONE_SECONDARY 0x0200 /* Zone is a Secondary Zone */ #define UMA_ZONE_NOBUCKET 0x0400 /* Do not use buckets. */ #define UMA_ZONE_MAXBUCKET 0x0800 /* Use largest buckets. */ -#define UMA_ZONE_MINBUCKET 0x1000 /* Use smallest buckets. */ #define UMA_ZONE_CACHESPREAD 0x2000 /* * Spread memory start locations across * all possible cache lines. May diff --git a/sys/vm/uma_core.c b/sys/vm/uma_core.c index e9df1e5af5d4..080e23ec0ae5 100644 --- a/sys/vm/uma_core.c +++ b/sys/vm/uma_core.c @@ -248,7 +248,6 @@ struct uma_bucket_zone { (((sizeof(void *) * (n)) - sizeof(struct uma_bucket)) / sizeof(void *)) #define BUCKET_MAX BUCKET_SIZE(256) -#define BUCKET_MIN 2 struct uma_bucket_zone bucket_zones[] = { /* Literal bucket sizes. */ @@ -507,7 +506,7 @@ bucket_alloc(uma_zone_t zone, void *udata, int flags) } if (((uintptr_t)udata & UMA_ZONE_VM) != 0) flags |= M_NOVM; - ubz = bucket_zone_lookup(zone->uz_bucket_size); + ubz = bucket_zone_lookup(atomic_load_16(&zone->uz_bucket_size)); if (ubz->ubz_zone == zone && (ubz + 1)->ubz_entries != 0) ubz++; bucket = uma_zalloc_arg(ubz->ubz_zone, udata, flags); @@ -516,7 +515,8 @@ bucket_alloc(uma_zone_t zone, void *udata, int flags) bzero(bucket->ub_bucket, sizeof(void *) * ubz->ubz_entries); #endif bucket->ub_cnt = 0; - bucket->ub_entries = ubz->ubz_entries; + bucket->ub_entries = min(ubz->ubz_entries, + zone->uz_bucket_size_max); bucket->ub_seq = SMR_SEQ_INVALID; CTR3(KTR_UMA, "bucket_alloc: zone %s(%p) allocated bucket %p", zone->uz_name, zone, bucket); @@ -2724,8 +2724,6 @@ zone_ctor(void *mem, int size, void *udata, int flags) zone->uz_bucket_size_max = zone->uz_bucket_size = 0; if ((arg->flags & UMA_ZONE_MAXBUCKET) != 0) zone->uz_bucket_size = BUCKET_MAX; - else if ((arg->flags & UMA_ZONE_MINBUCKET) != 0) - zone->uz_bucket_size_max = zone->uz_bucket_size = BUCKET_MIN; else if ((arg->flags & UMA_ZONE_NOBUCKET) != 0) zone->uz_bucket_size = 0; else