Introduce a device driver for /dev/devstat, this will allow us to mmap

the device statistics structures into userland instead of using sysctl.

Introduce new devstat_new_entry() function which allocates the devstat
structure an calls devstat_add_entry() on it.
This commit is contained in:
Poul-Henning Kamp 2003-03-08 19:58:57 +00:00
parent bfd614b8a5
commit c7e73d59c4

View File

@ -33,6 +33,10 @@
#include <sys/systm.h>
#include <sys/bio.h>
#include <sys/sysctl.h>
#include <sys/malloc.h>
#include <sys/conf.h>
#include <vm/vm.h>
#include <vm/pmap.h>
#include <sys/devicestat.h>
@ -42,6 +46,26 @@ static int devstat_version = DEVSTAT_VERSION;
static int devstat_current_devnumber;
static struct devstatlist device_statq;
static struct devstat *devstat_alloc(void);
static void devstat_free(struct devstat *);
/*
* Allocate a devstat and initialize it
*/
struct devstat *
devstat_new_entry(const char *dev_name,
int unit_number, u_int32_t block_size,
devstat_support_flags flags,
devstat_type_flags device_type,
devstat_priority priority)
{
struct devstat *ds;
ds = devstat_alloc();
devstat_add_entry(ds, dev_name, unit_number, block_size,
flags, device_type, priority);
return (ds);
}
/*
* Take a malloced and zeroed devstat structure given to us, fill it in
@ -148,6 +172,8 @@ devstat_remove_entry(struct devstat *ds)
/* Remove this entry from the devstat queue */
STAILQ_REMOVE(devstat_head, ds, devstat, dev_links);
if (ds->allocated)
devstat_free(ds);
}
/*
@ -304,3 +330,89 @@ SYSCTL_LONG(_kern_devstat, OID_AUTO, generation, CTLFLAG_RD,
&devstat_generation, 0, "Devstat list generation");
SYSCTL_INT(_kern_devstat, OID_AUTO, version, CTLFLAG_RD,
&devstat_version, 0, "Devstat list version number");
#define statsperpage (PAGE_SIZE / sizeof(struct devstat))
static d_mmap_t devstat_mmap;
static struct cdevsw devstat_cdevsw = {
.d_open = nullopen,
.d_close = nullclose,
.d_mmap = devstat_mmap,
.d_name = "devstat",
.d_maj = MAJOR_AUTO,
};
struct statspage {
TAILQ_ENTRY(statspage) list;
struct devstat *stat;
u_int nfree;
};
static TAILQ_HEAD(, statspage) pagelist = TAILQ_HEAD_INITIALIZER(pagelist);
static MALLOC_DEFINE(M_DEVSTAT, "devstat", "Device statistics");
static int
devstat_mmap(dev_t dev, vm_offset_t offset, vm_offset_t *paddr, int nprot)
{
struct statspage *spp;
if (nprot != VM_PROT_READ)
return (-1);
TAILQ_FOREACH(spp, &pagelist, list) {
if (offset == 0) {
*paddr = vtophys(spp->stat);
return (0);
}
offset -= PAGE_SIZE;
}
return (-1);
}
static struct devstat *
devstat_alloc(void)
{
struct devstat *dsp;
struct statspage *spp;
u_int u;
static int once;
if (!once) {
make_dev(&devstat_cdevsw, 0,
UID_ROOT, GID_WHEEL, 0400, "devstat");
once++;
}
TAILQ_FOREACH(spp, &pagelist, list) {
if (spp->nfree > 0)
break;
}
if (spp == NULL) {
spp = malloc(sizeof *spp, M_DEVSTAT, M_ZERO | M_WAITOK);
TAILQ_INSERT_TAIL(&pagelist, spp, list);
spp->stat = malloc(PAGE_SIZE, M_DEVSTAT, M_ZERO | M_WAITOK);
spp->nfree = statsperpage;
}
dsp = spp->stat;
for (u = 0; u < statsperpage; u++) {
if (dsp->allocated == 0)
break;
dsp++;
}
spp->nfree--;
dsp->allocated = 1;
return (dsp);
}
static void
devstat_free(struct devstat *dsp)
{
struct statspage *spp;
bzero(dsp, sizeof *dsp);
TAILQ_FOREACH(spp, &pagelist, list) {
if (dsp >= spp->stat && dsp < (spp->stat + statsperpage)) {
spp->nfree++;
return;
}
}
}