diff options
author | jeff <jeff@FreeBSD.org> | 2002-04-08 04:48:58 +0000 |
---|---|---|
committer | jeff <jeff@FreeBSD.org> | 2002-04-08 04:48:58 +0000 |
commit | 75d2443b7837a96530837f07564dc648e4b59e13 (patch) | |
tree | 4573d64b925be6743a9e6b2c5416827caec76e1c | |
parent | d9992faaf2001cc6dca237e00491cc57a7426909 (diff) | |
download | FreeBSD-src-75d2443b7837a96530837f07564dc648e4b59e13.zip FreeBSD-src-75d2443b7837a96530837f07564dc648e4b59e13.tar.gz |
Implement uma_zdestroy(). It's prototype changed slightly. I decided that I
didn't like the wait argument and that if you were removing a zone it had
better be empty.
Also, I broke out part of hash_expand and made a seperate hash_free() for use
in uma_zdestroy.
-rw-r--r-- | sys/vm/uma.h | 9 | ||||
-rw-r--r-- | sys/vm/uma_core.c | 99 |
2 files changed, 78 insertions, 30 deletions
diff --git a/sys/vm/uma.h b/sys/vm/uma.h index 8a61ee4..57fcf56 100644 --- a/sys/vm/uma.h +++ b/sys/vm/uma.h @@ -182,19 +182,14 @@ uma_zone_t uma_zcreate(char *name, int size, uma_ctor ctor, uma_dtor dtor, #define UMA_ALIGN_CACHE (16 - 1) /* Cache line size align */ /* - * Destroys a uma zone + * Destroys an empty uma zone. If the zone is not empty uma complains loudly. * * Arguments: * zone The zone we want to destroy. - * wait This flag indicates whether or not we should wait for all - * allocations to free, or return an errno on outstanding memory. * - * Returns: - * 0 on successful completion, or EWOULDBLOCK if there are outstanding - * allocations and the wait flag is M_NOWAIT */ -int uma_zdestroy(uma_zone_t zone, int wait); +void uma_zdestroy(uma_zone_t zone); /* * Allocates an item out of a zone diff --git a/sys/vm/uma_core.c b/sys/vm/uma_core.c index 2c45707..26ba0db 100644 --- a/sys/vm/uma_core.c +++ b/sys/vm/uma_core.c @@ -157,12 +157,14 @@ static void cache_drain(uma_zone_t); static void bucket_drain(uma_zone_t, uma_bucket_t); static void zone_drain(uma_zone_t); static void zone_ctor(void *, int, void *); +static void zone_dtor(void *, int, void *); static void zero_init(void *, int); static void zone_small_init(uma_zone_t zone); static void zone_large_init(uma_zone_t zone); static void zone_foreach(void (*zfunc)(uma_zone_t)); static void zone_timeout(uma_zone_t zone); static void hash_expand(struct uma_hash *); +static void hash_free(struct uma_hash *hash); static void uma_timeout(void *); static void uma_startup3(void); static void *uma_zalloc_internal(uma_zone_t, void *, int, uma_bucket_t); @@ -302,8 +304,8 @@ hash_expand(struct uma_hash *hash) struct slabhead *newhash; struct slabhead *oldhash; uma_slab_t slab; - int hzonefree; - int hashsize; + int oldsize; + int newsize; int alloc; int hval; int i; @@ -314,40 +316,34 @@ hash_expand(struct uma_hash *hash) * hash zone, or malloc. The hash zone is used for the initial hash */ - hashsize = hash->uh_hashsize; + oldsize = hash->uh_hashsize; oldhash = hash->uh_slab_hash; - if (hashsize == UMA_HASH_SIZE_INIT) - hzonefree = 1; - else - hzonefree = 0; - - /* We're just going to go to a power of two greater */ if (hash->uh_hashsize) { - alloc = sizeof(hash->uh_slab_hash[0]) * (hash->uh_hashsize * 2); + newsize = oldsize * 2; + alloc = sizeof(hash->uh_slab_hash[0]) * newsize; /* XXX Shouldn't be abusing DEVBUF here */ newhash = (struct slabhead *)malloc(alloc, M_DEVBUF, M_NOWAIT); if (newhash == NULL) { return; } - hash->uh_hashsize *= 2; } else { alloc = sizeof(hash->uh_slab_hash[0]) * UMA_HASH_SIZE_INIT; newhash = uma_zalloc_internal(hashzone, NULL, M_WAITOK, NULL); - hash->uh_hashsize = UMA_HASH_SIZE_INIT; + newsize = UMA_HASH_SIZE_INIT; } bzero(newhash, alloc); - hash->uh_hashmask = hash->uh_hashsize - 1; + hash->uh_hashmask = newsize - 1; /* * I need to investigate hash algorithms for resizing without a * full rehash. */ - for (i = 0; i < hashsize; i++) + for (i = 0; i < oldsize; i++) while (!SLIST_EMPTY(&hash->uh_slab_hash[i])) { slab = SLIST_FIRST(&hash->uh_slab_hash[i]); SLIST_REMOVE_HEAD(&hash->uh_slab_hash[i], us_hlink); @@ -355,18 +351,27 @@ hash_expand(struct uma_hash *hash) SLIST_INSERT_HEAD(&newhash[hval], slab, us_hlink); } - if (hash->uh_slab_hash) { - if (hzonefree) - uma_zfree_internal(hashzone, - hash->uh_slab_hash, NULL, 0); - else - free(hash->uh_slab_hash, M_DEVBUF); - } + if (oldhash) + hash_free(hash); + hash->uh_slab_hash = newhash; + hash->uh_hashsize = newsize; return; } +static void +hash_free(struct uma_hash *hash) +{ + if (hash->uh_hashsize == UMA_HASH_SIZE_INIT) + uma_zfree_internal(hashzone, + hash->uh_slab_hash, NULL, 0); + else + free(hash->uh_slab_hash, M_DEVBUF); + + hash->uh_slab_hash = NULL; +} + /* * Frees all outstanding items in a bucket * @@ -493,6 +498,7 @@ cache_drain(uma_zone_t zone) * * Arguments: * zone The zone to free pages from + * all Should we drain all items? * * Returns: * Nothing. @@ -525,7 +531,7 @@ zone_drain(uma_zone_t zone) printf("%s working set size: %llu free items: %u\n", zone->uz_name, (unsigned long long)zone->uz_wssize, zone->uz_free); #endif - extra = zone->uz_wssize - zone->uz_free; + extra = zone->uz_free - zone->uz_wssize; extra /= zone->uz_ipers; /* extra is now the number of extra slabs that we can free */ @@ -1013,6 +1019,46 @@ zone_ctor(void *mem, int size, void *udata) CPU_LOCK_INIT(zone, cpu); } +/* + * Zone header dtor. This frees all data, destroys locks, frees the hash table + * and removes the zone from the global list. + * + * Arguments/Returns follow uma_dtor specifications + * udata unused + */ + +static void +zone_dtor(void *arg, int size, void *udata) +{ + uma_zone_t zone; + int cpu; + + zone = (uma_zone_t)arg; + + mtx_lock(&uma_mtx); + LIST_REMOVE(zone, uz_link); + mtx_unlock(&uma_mtx); + + ZONE_LOCK(zone); + zone->uz_wssize = 0; + ZONE_UNLOCK(zone); + + zone_drain(zone); + ZONE_LOCK(zone); + if (zone->uz_free != 0) + printf("Zone %s was not empty. Lost %d pages of memory.\n", + zone->uz_name, zone->uz_pages); + + if ((zone->uz_flags & UMA_ZFLAG_INTERNAL) != 0) + for (cpu = 0; cpu < maxcpu; cpu++) + CPU_LOCK_FINI(zone, cpu); + + if ((zone->uz_flags & UMA_ZFLAG_OFFPAGE) != 0) + hash_free(&zone->uz_hash); + + ZONE_UNLOCK(zone); + ZONE_LOCK_FINI(zone); +} /* * Traverses every zone in the system and calls a callback * @@ -1063,7 +1109,7 @@ uma_startup(void *bootmem) args.size = sizeof(struct uma_zone) + (sizeof(struct uma_cache) * (maxcpu - 1)); args.ctor = zone_ctor; - args.dtor = NULL; + args.dtor = zone_dtor; args.uminit = zero_init; args.fini = NULL; args.align = 32 - 1; @@ -1172,6 +1218,13 @@ uma_zcreate(char *name, int size, uma_ctor ctor, uma_dtor dtor, uma_init uminit, } /* See uma.h */ +void +uma_zdestroy(uma_zone_t zone) +{ + uma_zfree_internal(zones, zone, NULL, 0); +} + +/* See uma.h */ void * uma_zalloc_arg(uma_zone_t zone, void *udata, int wait) { |