Project

General

Profile

Bug #923 ยป zdestroy.patch

nthery, 01/20/2008 10:19 AM

View differences:

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>
    (1-1/1)