Bug #923 ยป zdestroy.patch
src2/sys/vm/vm_zone.c 2008-01-19 17:12:28.000000000 +0100 | ||
---|---|---|
*/
|
||
#include <sys/param.h>
|
||
#include <sys/queue.h>
|
||
#include <sys/systm.h>
|
||
#include <sys/kernel.h>
|
||
#include <sys/lock.h>
|
||
... | ... | |
#define ZONE_ERROR_INVALID 0
|
||
#define ZONE_ERROR_NOTFREE 1
|
||
#define ZONE_ERROR_ALREADYFREE 2
|
||
#define ZONE_ERROR_CANT_DESTROY 3
|
||
#define ZONE_ROUNDING 32
|
||
... | ... | |
* zalloc, zfree, are the allocation/free routines.
|
||
*/
|
||
struct vm_zone *zlist; /* exported to vmstat */
|
||
LIST_HEAD(zlist, vm_zone) zlist = LIST_HEAD_INITIALIZER(zlist);
|
||
static int sysctl_vm_zone(SYSCTL_HANDLER_ARGS);
|
||
static int zone_kmem_pages, zone_kern_pages, zone_kmem_kvaspace;
|
||
... | ... | |
{
|
||
int totsize;
|
||
/*
|
||
* Only zones created with zinit() are destroyable.
|
||
*/
|
||
if (z->zflags & ZONE_DESTROYABLE)
|
||
zerror(ZONE_ERROR_CANT_DESTROY);
|
||
if ((z->zflags & ZONE_BOOT) == 0) {
|
||
z->zsize = (size + ZONE_ROUNDING - 1) & ~(ZONE_ROUNDING - 1);
|
||
spin_init(&z->zlock);
|
||
... | ... | |
z->znalloc = 0;
|
||
z->zitems = NULL;
|
||
z->znext = zlist;
|
||
zlist = z;
|
||
LIST_INSERT_HEAD(&zlist, z, zlink);
|
||
}
|
||
z->zkmvec = NULL;
|
||
z->zkmcur = z->zkmmax = 0;
|
||
z->zflags |= flags;
|
||
/*
|
||
... | ... | |
z->zkva = kmem_alloc_pageable(&kernel_map, totsize);
|
||
if (z->zkva == 0) {
|
||
zlist = z->znext;
|
||
LIST_REMOVE(z, zlink);
|
||
return 0;
|
||
}
|
||
... | ... | |
return NULL;
|
||
z->zflags = 0;
|
||
if (zinitna(z, NULL, name, size, nentries, flags, zalloc) == 0) {
|
||
if (zinitna(z, NULL, name, size, nentries,
|
||
flags & ~ZONE_DESTROYABLE, zalloc) == 0) {
|
||
kfree(z, M_ZONE);
|
||
return NULL;
|
||
}
|
||
if (flags & ZONE_DESTROYABLE)
|
||
z->zflags |= ZONE_DESTROYABLE;
|
||
return z;
|
||
}
|
||
... | ... | |
z->zmax = nitems;
|
||
z->ztotal = nitems;
|
||
if (zlist == 0) {
|
||
zlist = z;
|
||
LIST_INSERT_HEAD(&zlist, z, zlink);
|
||
}
|
||
/*
|
||
* Release all resources owned by zone created with zinit().
|
||
*/
|
||
void
|
||
zdestroy(vm_zone_t z)
|
||
{
|
||
int i;
|
||
if (z == NULL)
|
||
zerror(ZONE_ERROR_INVALID);
|
||
if ((z->zflags & ZONE_DESTROYABLE) == 0)
|
||
zerror(ZONE_ERROR_CANT_DESTROY);
|
||
LIST_REMOVE(z, zlink);
|
||
/*
|
||
* Release virtual mappings, physical memory and update sysctl stats.
|
||
*/
|
||
if (z->zflags & ZONE_INTERRUPT) {
|
||
/*
|
||
* Free the mapping.
|
||
*/
|
||
kmem_free(&kernel_map, z->zkva, z->zpagemax*PAGE_SIZE);
|
||
atomic_subtract_int(&zone_kmem_kvaspace, z->zpagemax*PAGE_SIZE);
|
||
/*
|
||
* Free the backing object and physical pages.
|
||
*/
|
||
vm_object_deallocate(z->zobj);
|
||
atomic_subtract_int(&zone_kmem_pages, z->zpagecount);
|
||
} else {
|
||
z->znext = zlist;
|
||
zlist = z;
|
||
for (i=0; i < z->zkmcur; i++) {
|
||
kmem_free(&kernel_map, z->zkmvec[i],
|
||
z->zalloc*PAGE_SIZE);
|
||
atomic_subtract_int(&zone_kern_pages, z->zalloc);
|
||
}
|
||
kfree(z->zkmvec, M_ZONE);
|
||
}
|
||
spin_uninit(&z->zlock);
|
||
kfree(z, M_ZONE);
|
||
}
|
||
/*
|
||
* void *zalloc(vm_zone_t zone) --
|
||
* Returns an item from a specified zone. May not be called from a
|
||
... | ... | |
if (m == NULL)
|
||
break;
|
||
/*
|
||
* Unbusy page so it can freed in zdestroy(). Make
|
||
* sure it is not on any queue and so can not be
|
||
* recycled under our feet.
|
||
*/
|
||
KKASSERT(m->queue == PQ_NONE);
|
||
vm_page_flag_clear(m, PG_BUSY);
|
||
zkva = z->zkva + z->zpagecount * PAGE_SIZE;
|
||
pmap_kenter(zkva, VM_PAGE_TO_PHYS(m)); /* YYY */
|
||
bzero((void *)zkva, PAGE_SIZE);
|
||
... | ... | |
if (item != NULL) {
|
||
zone_kern_pages += z->zalloc; /* not MP-safe XXX */
|
||
bzero(item, nbytes);
|
||
if (z->zflags & ZONE_DESTROYABLE) {
|
||
if (z->zkmcur == z->zkmmax) {
|
||
z->zkmmax =
|
||
z->zkmmax==0 ? 1 : z->zkmmax*2;
|
||
z->zkmvec = krealloc(z->zkmvec,
|
||
z->zkmmax * sizeof(z->zkmvec[0]),
|
||
M_ZONE, M_WAITOK);
|
||
}
|
||
z->zkmvec[z->zkmcur++] = (vm_offset_t)item;
|
||
}
|
||
} else {
|
||
nbytes = 0;
|
||
}
|
||
... | ... | |
sysctl_vm_zone(SYSCTL_HANDLER_ARGS)
|
||
{
|
||
int error=0;
|
||
vm_zone_t curzone, nextzone;
|
||
vm_zone_t curzone;
|
||
char tmpbuf[128];
|
||
char tmpname[14];
|
||
... | ... | |
if (error)
|
||
return (error);
|
||
for (curzone = zlist; curzone; curzone = nextzone) {
|
||
LIST_FOREACH(curzone, &zlist, zlink) {
|
||
int i;
|
||
int len;
|
||
int offset;
|
||
nextzone = curzone->znext;
|
||
len = strlen(curzone->zname);
|
||
if (len >= (sizeof(tmpname) - 1))
|
||
len = (sizeof(tmpname) - 1);
|
||
... | ... | |
memcpy(tmpname, curzone->zname, len);
|
||
tmpname[len] = ':';
|
||
offset = 0;
|
||
if (curzone == zlist) {
|
||
if (curzone == LIST_FIRST(&zlist)) {
|
||
offset = 1;
|
||
tmpbuf[0] = '\n';
|
||
}
|
||
... | ... | |
curzone->zfreecnt, curzone->znalloc);
|
||
len = strlen((char *)tmpbuf);
|
||
if (nextzone == NULL)
|
||
if (LIST_NEXT(curzone, zlink) == NULL)
|
||
tmpbuf[len - 1] = 0;
|
||
error = SYSCTL_OUT(req, tmpbuf, len);
|
||
... | ... | |
case ZONE_ERROR_ALREADYFREE:
|
||
msg = "zone: freeing free entry";
|
||
break;
|
||
case ZONE_ERROR_CANT_DESTROY:
|
||
msg = "zone: cannot destroy zone (not created with zinit()?)";
|
||
break;
|
||
default:
|
||
msg = "zone: invalid error";
|
||
break;
|
src2/sys/vm/vm_zone.h 2008-01-19 16:13:30.000000000 +0100 | ||
---|---|---|
#define ZONE_SPECIAL 0x0004 /* special vm_map_entry zone, see zget() */
|
||
#define ZONE_BOOT 0x0010 /* Internal flag used by zbootinit */
|
||
#define ZONE_USE_RESERVE 0x0020 /* use reserve memory if necessary */
|
||
#define ZONE_DESTROYABLE 0x0040 /* can be zdestroy()'ed */
|
||
#include <sys/spinlock.h>
|
||
#include <sys/thread.h>
|
||
... | ... | |
int zallocflag; /* flag for allocation */
|
||
struct vm_object *zobj; /* object to hold zone */
|
||
char *zname; /* name for diags */
|
||
struct vm_zone *znext; /* list of zones for sysctl */
|
||
LIST_ENTRY(vm_zone) zlink; /* link in zlist */
|
||
/*
|
||
* The following fields track kmem_alloc()'ed blocks when
|
||
* ZONE_DESTROYABLE set and normal zone (i.e. not ZONE_INTERRUPT nor
|
||
* ZONE_SPECIAL).
|
||
*/
|
||
vm_offset_t *zkmvec; /* krealloc()'ed array */
|
||
int zkmcur; /* next free slot in zkmvec */
|
||
int zkmmax; /* # of slots in zkmvec */
|
||
} *vm_zone_t;
|
||
... | ... | |
void zfree (vm_zone_t z, void *item);
|
||
void zbootinit (vm_zone_t z, char *name, int size, void *item,
|
||
int nitems);
|
||
void zdestroy(vm_zone_t z);
|
||
#endif /* _VM_VM_ZONE_H_ */
|
src2/share/man/man9/zone.9 2008-01-19 17:08:48.000000000 +0100 | ||
---|---|---|
.Nm zbootinit ,
|
||
.Nm zinitna ,
|
||
.Nm zinit ,
|
||
.Nm zdestroy ,
|
||
.Nm zalloc ,
|
||
.Nm zfree ,
|
||
.Nd zone allocator
|
||
... | ... | |
.Fn zinitna "vm_zone_t z" "struct vm_object *obj" "char *name" "int size" "int nentries" "int flags" "int zalloc"
|
||
.Ft vm_zone_t
|
||
.Fn zinit "char *name" "int size" "int nentries" "int flags" "int zalloc"
|
||
.Ft void
|
||
.Fn zdestroy "vm_zone_t z"
|
||
.Ft void *
|
||
.Fn zalloc "vm_zone_t z"
|
||
.Ft void
|
||
... | ... | |
items) of the zone, respectively.
|
||
The
|
||
.Fa flags
|
||
argument should be set to
|
||
argument should have the
|
||
.Dv ZONE_INTERRUPT
|
||
if there is a chance that items may be allocated from the zone in
|
||
bit set if there is a chance that items may be allocated from the zone in
|
||
interrupt context; note that in this case, the zone will never grow
|
||
larger than
|
||
.Fa nentries
|
||
items.
|
||
In all other cases,
|
||
The
|
||
.Fa flags
|
||
should be set to 0.
|
||
argument should have the
|
||
.Dv ZONE_DESTROYABLE
|
||
bit set if the zone is to be destroyed with
|
||
.Fn zdestroy .
|
||
The final argument,
|
||
.Fa zalloc ,
|
||
indicates the number of VM pages by which the zone should grow every
|
||
... | ... | |
.Dv ZONE_INTERRUPT
|
||
case.
|
||
.Pp
|
||
To release all the memory allocated for a zone, call
|
||
.Fn zdestroy .
|
||
Only zones created with
|
||
.Fn zinit
|
||
and with the
|
||
.Dv ZONE_DESTROYABLE
|
||
flag can be destroyed.
|
||
.Pp
|
||
To allocate an item from a zone, simply call
|
||
.Fn zalloc
|
||
with a pointer to that zone; it will return a pointer to an item, or
|
src2/share/man/man9/Makefile 2008-01-19 17:35:14.000000000 +0100 | ||
---|---|---|
zone.9 zbootinit.9 \
|
||
zone.9 zfree.9 \
|
||
zone.9 zinit.9 \
|
||
zone.9 zinitna.9
|
||
zone.9 zinitna.9 \
|
||
zone.9 zdestroy.9
|
||
.include <bsd.prog.mk>
|