1110545Sphk/*-
2110545Sphk * Copyright (c) 2003 Poul-Henning Kamp
3110545Sphk * All rights reserved.
4110545Sphk *
5110545Sphk * Redistribution and use in source and binary forms, with or without
6110545Sphk * modification, are permitted provided that the following conditions
7110545Sphk * are met:
8110545Sphk * 1. Redistributions of source code must retain the above copyright
9110545Sphk *    notice, this list of conditions and the following disclaimer.
10110545Sphk * 2. Redistributions in binary form must reproduce the above copyright
11110545Sphk *    notice, this list of conditions and the following disclaimer in the
12110545Sphk *    documentation and/or other materials provided with the distribution.
13110545Sphk * 3. The names of the authors may not be used to endorse or promote
14110545Sphk *    products derived from this software without specific prior written
15110545Sphk *    permission.
16110545Sphk *
17110545Sphk * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18110545Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19110545Sphk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20110545Sphk * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21110545Sphk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22110545Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23110545Sphk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24110545Sphk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25110545Sphk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26110545Sphk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27110545Sphk * SUCH DAMAGE.
28110545Sphk *
29110545Sphk * $FreeBSD$
30110545Sphk */
31110545Sphk
32110545Sphk#include <paths.h>
33110545Sphk#include <errno.h>
34110545Sphk#include <fcntl.h>
35110545Sphk#include <stdlib.h>
36110545Sphk#include <string.h>
37110545Sphk#include <unistd.h>
38110545Sphk#include <libgeom.h>
39110545Sphk
40110545Sphk#include <sys/mman.h>
41110545Sphk#include <sys/time.h>
42110545Sphk#include <sys/types.h>
43112372Sphk#include <sys/devicestat.h>
44110545Sphk
45110545Sphk
46110545Sphk/************************************************************/
47110545Sphkstatic uint npages, pagesize, spp;
48110545Sphkstatic int statsfd = -1;
49110545Sphkstatic u_char *statp;
50110545Sphk
51110545Sphkvoid
52110545Sphkgeom_stats_close(void)
53110545Sphk{
54110545Sphk	if (statsfd == -1)
55110545Sphk		return;
56110545Sphk	munmap(statp, npages *pagesize);
57110545Sphk	statp = NULL;
58110545Sphk	close (statsfd);
59110545Sphk	statsfd = -1;
60110545Sphk}
61110545Sphk
62110545Sphkvoid
63110545Sphkgeom_stats_resync(void)
64110545Sphk{
65110545Sphk	void *p;
66110545Sphk
67110545Sphk	if (statsfd == -1)
68110545Sphk		return;
69110545Sphk	for (;;) {
70110545Sphk		p = mmap(statp, (npages + 1) * pagesize,
71110545Sphk		    PROT_READ, 0, statsfd, 0);
72110545Sphk		if (p == MAP_FAILED)
73110545Sphk			break;
74110545Sphk		else
75110545Sphk			statp = p;
76110545Sphk		npages++;
77110545Sphk	}
78110545Sphk}
79110545Sphk
80110545Sphkint
81110545Sphkgeom_stats_open(void)
82110545Sphk{
83110545Sphk	int error;
84110545Sphk	void *p;
85110545Sphk
86110545Sphk	if (statsfd != -1)
87110545Sphk		return (EBUSY);
88112372Sphk	statsfd = open(_PATH_DEV DEVSTAT_DEVICE_NAME, O_RDONLY);
89110545Sphk	if (statsfd < 0)
90110545Sphk		return (errno);
91110545Sphk	pagesize = getpagesize();
92112372Sphk	spp = pagesize / sizeof(struct devstat);
93110545Sphk	p = mmap(NULL, pagesize, PROT_READ, 0, statsfd, 0);
94110545Sphk	if (p == MAP_FAILED) {
95110545Sphk		error = errno;
96110545Sphk		close(statsfd);
97110545Sphk		statsfd = -1;
98110545Sphk		errno = error;
99110545Sphk		return (error);
100110545Sphk	}
101110545Sphk	statp = p;
102110545Sphk	npages = 1;
103110545Sphk	geom_stats_resync();
104110545Sphk	return (0);
105110545Sphk}
106110545Sphk
107110545Sphkstruct snapshot {
108110545Sphk	u_char		*ptr;
109110545Sphk	uint		pages;
110110545Sphk	uint		pagesize;
111110545Sphk	uint		perpage;
112110545Sphk	struct timespec	time;
113110545Sphk	/* used by getnext: */
114110545Sphk	uint		u, v;
115110545Sphk};
116110545Sphk
117110545Sphkvoid *
118110545Sphkgeom_stats_snapshot_get(void)
119110545Sphk{
120110545Sphk	struct snapshot *sp;
121110545Sphk
122110545Sphk	sp = malloc(sizeof *sp);
123110545Sphk	if (sp == NULL)
124110545Sphk		return (NULL);
125110545Sphk	memset(sp, 0, sizeof *sp);
126110545Sphk	sp->ptr = malloc(pagesize * npages);
127110545Sphk	if (sp->ptr == NULL) {
128110545Sphk		free(sp);
129110545Sphk		return (NULL);
130110545Sphk	}
131110545Sphk	memset(sp->ptr, 0, pagesize * npages); 	/* page in, cache */
132110545Sphk	clock_gettime(CLOCK_REALTIME, &sp->time);
133110545Sphk	memset(sp->ptr, 0, pagesize * npages); 	/* page in, cache */
134110545Sphk	memcpy(sp->ptr, statp, pagesize * npages);
135110545Sphk	sp->pages = npages;
136110545Sphk	sp->perpage = spp;
137110545Sphk	sp->pagesize = pagesize;
138110545Sphk	return (sp);
139110545Sphk}
140110545Sphk
141110545Sphkvoid
142110545Sphkgeom_stats_snapshot_free(void *arg)
143110545Sphk{
144110545Sphk	struct snapshot *sp;
145110545Sphk
146110545Sphk	sp = arg;
147110545Sphk	free(sp->ptr);
148110545Sphk	free(sp);
149110545Sphk}
150110545Sphk
151110545Sphkvoid
152110545Sphkgeom_stats_snapshot_timestamp(void *arg, struct timespec *tp)
153110545Sphk{
154110545Sphk	struct snapshot *sp;
155110545Sphk
156110545Sphk	sp = arg;
157110545Sphk	*tp = sp->time;
158110545Sphk}
159110545Sphk
160110545Sphkvoid
161110545Sphkgeom_stats_snapshot_reset(void *arg)
162110545Sphk{
163110545Sphk	struct snapshot *sp;
164110545Sphk
165110545Sphk	sp = arg;
166110545Sphk	sp->u = sp->v = 0;
167110545Sphk}
168110545Sphk
169112372Sphkstruct devstat *
170110545Sphkgeom_stats_snapshot_next(void *arg)
171110545Sphk{
172112372Sphk	struct devstat *gsp;
173110545Sphk	struct snapshot *sp;
174110545Sphk
175110545Sphk	sp = arg;
176112372Sphk	gsp = (struct devstat *)
177110545Sphk	    (sp->ptr + sp->u * pagesize + sp->v * sizeof *gsp);
178110545Sphk	if (++sp->v >= sp->perpage) {
179110545Sphk		if (++sp->u >= sp->pages)
180110545Sphk			return (NULL);
181110545Sphk		else
182110545Sphk			sp->v = 0;
183110545Sphk	}
184110545Sphk	return (gsp);
185110545Sphk}
186