#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/disk.h>
#include <sys/devicestat.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <paths.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <libgeom.h>
static uint npages, spp;
static int pagesize, statsfd = -1;
static u_char *statp;
void
geom_stats_close(void)
{
if (statsfd == -1)
return;
if (statp != NULL) {
if (munmap(statp, npages * pagesize) != 0)
err(1, "munmap");
statp = NULL;
}
close(statsfd);
statsfd = -1;
}
void
geom_stats_resync(void)
{
void *p;
off_t mediasize;
int error;
if (statsfd == -1)
return;
error = ioctl(statsfd, DIOCGMEDIASIZE, &mediasize);
if (error)
err(1, "DIOCGMEDIASIZE(" _PATH_DEV DEVSTAT_DEVICE_NAME ")");
if (statp != NULL && munmap(statp, npages * pagesize) != 0)
err(1, "munmap");
p = mmap(NULL, mediasize, PROT_READ, MAP_SHARED, statsfd, 0);
if (p == MAP_FAILED)
err(1, "mmap(/dev/devstat)");
statp = p;
npages = mediasize / pagesize;
}
int
geom_stats_open(void)
{
if (statsfd != -1)
return (EBUSY);
statsfd = open(_PATH_DEV DEVSTAT_DEVICE_NAME, O_RDONLY);
if (statsfd < 0)
return (errno);
pagesize = getpagesize();
spp = pagesize / sizeof(struct devstat);
npages = 1;
geom_stats_resync();
return (0);
}
struct snapshot {
u_char *ptr;
uint pages;
uint pagesize;
uint perpage;
struct timespec time;
uint u, v;
};
void *
geom_stats_snapshot_get(void)
{
struct snapshot *sp;
sp = malloc(sizeof *sp);
if (sp == NULL)
return (NULL);
memset(sp, 0, sizeof *sp);
sp->ptr = malloc(pagesize * npages);
if (sp->ptr == NULL) {
free(sp);
return (NULL);
}
explicit_bzero(sp->ptr, pagesize * npages);
clock_gettime(CLOCK_REALTIME, &sp->time);
memcpy(sp->ptr, statp, pagesize * npages);
sp->pages = npages;
sp->perpage = spp;
sp->pagesize = pagesize;
return (sp);
}
void
geom_stats_snapshot_free(void *arg)
{
struct snapshot *sp;
sp = arg;
free(sp->ptr);
free(sp);
}
void
geom_stats_snapshot_timestamp(void *arg, struct timespec *tp)
{
struct snapshot *sp;
sp = arg;
*tp = sp->time;
}
void
geom_stats_snapshot_reset(void *arg)
{
struct snapshot *sp;
sp = arg;
sp->u = sp->v = 0;
}
struct devstat *
geom_stats_snapshot_next(void *arg)
{
struct devstat *gsp;
struct snapshot *sp;
sp = arg;
gsp = (struct devstat *)
(sp->ptr + sp->u * pagesize + sp->v * sizeof *gsp);
if (++sp->v >= sp->perpage) {
if (++sp->u >= sp->pages)
return (NULL);
else
sp->v = 0;
}
return (gsp);
}