1/*-
2 * Copyright (c) 2003 Poul-Henning Kamp
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. The names of the authors may not be used to endorse or promote
14 *    products derived from this software without specific prior written
15 *    permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * $FreeBSD: releng/10.3/lib/libgeom/geom_stats.c 273145 2014-10-15 19:27:14Z jhb $
30 */
31
32#include <paths.h>
33#include <errno.h>
34#include <fcntl.h>
35#include <stdlib.h>
36#include <string.h>
37#include <unistd.h>
38#include <libgeom.h>
39
40#include <sys/mman.h>
41#include <sys/time.h>
42#include <sys/types.h>
43#include <sys/devicestat.h>
44
45
46/************************************************************/
47static uint npages, pagesize, spp;
48static int statsfd = -1;
49static u_char *statp;
50
51void
52geom_stats_close(void)
53{
54	if (statsfd == -1)
55		return;
56	munmap(statp, npages *pagesize);
57	statp = NULL;
58	close (statsfd);
59	statsfd = -1;
60}
61
62void
63geom_stats_resync(void)
64{
65	void *p;
66
67	if (statsfd == -1)
68		return;
69	for (;;) {
70		p = mmap(statp, (npages + 1) * pagesize,
71		    PROT_READ, MAP_SHARED, statsfd, 0);
72		if (p == MAP_FAILED)
73			break;
74		else
75			statp = p;
76		npages++;
77	}
78}
79
80int
81geom_stats_open(void)
82{
83	int error;
84	void *p;
85
86	if (statsfd != -1)
87		return (EBUSY);
88	statsfd = open(_PATH_DEV DEVSTAT_DEVICE_NAME, O_RDONLY);
89	if (statsfd < 0)
90		return (errno);
91	pagesize = getpagesize();
92	spp = pagesize / sizeof(struct devstat);
93	p = mmap(NULL, pagesize, PROT_READ, MAP_SHARED, statsfd, 0);
94	if (p == MAP_FAILED) {
95		error = errno;
96		close(statsfd);
97		statsfd = -1;
98		errno = error;
99		return (error);
100	}
101	statp = p;
102	npages = 1;
103	geom_stats_resync();
104	return (0);
105}
106
107struct snapshot {
108	u_char		*ptr;
109	uint		pages;
110	uint		pagesize;
111	uint		perpage;
112	struct timespec	time;
113	/* used by getnext: */
114	uint		u, v;
115};
116
117void *
118geom_stats_snapshot_get(void)
119{
120	struct snapshot *sp;
121
122	sp = malloc(sizeof *sp);
123	if (sp == NULL)
124		return (NULL);
125	memset(sp, 0, sizeof *sp);
126	sp->ptr = malloc(pagesize * npages);
127	if (sp->ptr == NULL) {
128		free(sp);
129		return (NULL);
130	}
131	memset(sp->ptr, 0, pagesize * npages); 	/* page in, cache */
132	clock_gettime(CLOCK_REALTIME, &sp->time);
133	memset(sp->ptr, 0, pagesize * npages); 	/* page in, cache */
134	memcpy(sp->ptr, statp, pagesize * npages);
135	sp->pages = npages;
136	sp->perpage = spp;
137	sp->pagesize = pagesize;
138	return (sp);
139}
140
141void
142geom_stats_snapshot_free(void *arg)
143{
144	struct snapshot *sp;
145
146	sp = arg;
147	free(sp->ptr);
148	free(sp);
149}
150
151void
152geom_stats_snapshot_timestamp(void *arg, struct timespec *tp)
153{
154	struct snapshot *sp;
155
156	sp = arg;
157	*tp = sp->time;
158}
159
160void
161geom_stats_snapshot_reset(void *arg)
162{
163	struct snapshot *sp;
164
165	sp = arg;
166	sp->u = sp->v = 0;
167}
168
169struct devstat *
170geom_stats_snapshot_next(void *arg)
171{
172	struct devstat *gsp;
173	struct snapshot *sp;
174
175	sp = arg;
176	gsp = (struct devstat *)
177	    (sp->ptr + sp->u * pagesize + sp->v * sizeof *gsp);
178	if (++sp->v >= sp->perpage) {
179		if (++sp->u >= sp->pages)
180			return (NULL);
181		else
182			sp->v = 0;
183	}
184	return (gsp);
185}
186