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
This commit is contained in:
markj 2020-12-06 22:45:39 +00:00
parent 13b815c01a
commit 2dca52f047
2 changed files with 3 additions and 6 deletions

View File

@ -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

View File

@ -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