xref: /titanic_41/usr/src/cmd/fs.d/cachefs/common/stats_create.c (revision 2f172c55ef76964744bc62b4500ece87f3089b4d)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  *
31  *			stats_create.c
32  *
33  * Routines for the `clean interface' to cachefs statistics.
34  */
35 
36 #include <stdarg.h>
37 #include <libintl.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <assert.h>
41 #include <sys/fs/cachefs_fs.h>
42 #include <string.h>
43 #include "stats.h"
44 
45 void	*malloc(), *calloc();
46 
47 /* forward declarations of statics */
48 static stats_cookie_t *stats_create(char *);
49 
50 static stats_cookie_t *
51 stats_create(char *progname)
52 {
53 	stats_cookie_t *rc;
54 
55 	if ((rc = (stats_cookie_t *)calloc(1, sizeof (*rc))) == NULL)
56 		goto out;
57 
58 	rc->st_magic = STATS_MAGIC;
59 	if (rc->st_progname = strrchr(progname, '/'))
60 		rc->st_progname++;
61 	else
62 		rc->st_progname = progname;
63 
64 	if ((rc->st_kstat_cookie = kstat_open()) == NULL) {
65 		stats_perror(rc, SE_KERNEL,
66 		    gettext("Cannot initialize kstats"));
67 		goto out;
68 	}
69 
70 out:
71 	return (rc);
72 }
73 
74 stats_cookie_t *
75 stats_create_unbound(char *progname)
76 {
77 	stats_cookie_t *st;
78 
79 	if ((st = stats_create(progname)) == NULL)
80 		goto out;
81 
82 	st->st_flags |= ST_VALID;
83 
84 out:
85 	return (st);
86 }
87 
88 stats_cookie_t *
89 stats_create_mountpath(char *mountpath, char *progname)
90 {
91 	stats_cookie_t *st;
92 	kstat_t *key;
93 	cachefs_kstat_key_t *k;
94 	dev_t dev;
95 	ino64_t ino;
96 	struct stat64 s;
97 	int i, n;
98 
99 	if ((st = stats_create(progname)) == NULL)
100 		goto out;
101 
102 	if ((key = kstat_lookup(st->st_kstat_cookie, "cachefs", 0, "key"))
103 	    == NULL) {
104 		stats_perror(st, SE_KERNEL,
105 		    gettext("Cannot lookup cachefs key kstat"));
106 		goto out;
107 	}
108 	if (kstat_read(st->st_kstat_cookie, key, NULL) < 0) {
109 		stats_perror(st, SE_KERNEL,
110 		    gettext("Cannot read cachefs key kstat"));
111 		goto out;
112 	}
113 	k = (cachefs_kstat_key_t *)key->ks_data;
114 	n = key->ks_ndata;
115 
116 	if (stat64(mountpath, &s) != 0) {
117 		stats_perror(st, SE_FILE,
118 		    gettext("Cannot stat %s"), mountpath);
119 		goto out;
120 	}
121 	ino = s.st_ino;
122 	dev = s.st_dev;
123 
124 	for (i = 0; i < n; i++) {
125 		k[i].ks_mountpoint += (uintptr_t)k;
126 		k[i].ks_backfs += (uintptr_t)k;
127 		k[i].ks_cachedir += (uintptr_t)k;
128 		k[i].ks_cacheid += (uintptr_t)k;
129 
130 		if (! k[i].ks_mounted)
131 			continue;
132 
133 		if ((stat64((char *)(uintptr_t)k[i].ks_mountpoint, &s) == 0) &&
134 		    (s.st_dev == dev) &&
135 		    (s.st_ino == ino))
136 			break;
137 	}
138 
139 	if (i >= n) {
140 		stats_perror(st, SE_FILE,
141 		    gettext("%s: not a cachefs mountpoint"), mountpath);
142 		goto out;
143 	}
144 
145 	st->st_fsid = k[i].ks_id;
146 
147 	st->st_flags |= ST_VALID | ST_BOUND;
148 
149 out:
150 	return (st);
151 }
152 
153 /*
154  * stats_next - bind the cookie to the next valid cachefs mount.
155  *
156  * returns cachefs_kstat_key_t *, which gives all the info you need.
157  * returns NULL if we're out of mounts, or if an error occured.
158  * returns malloc()ed data, which the client has to free() itself.
159  */
160 
161 cachefs_kstat_key_t *
162 stats_next(stats_cookie_t *st)
163 {
164 	kstat_t *key;
165 	cachefs_kstat_key_t *k, *prc = NULL, *rc = NULL;
166 	int i, n;
167 
168 	assert(stats_good(st));
169 
170 	if (((key = kstat_lookup(st->st_kstat_cookie, "cachefs", 0,
171 	    "key")) == NULL) ||
172 	    (kstat_read(st->st_kstat_cookie, key, NULL) < 0)) {
173 		stats_perror(st, SE_KERNEL,
174 		    gettext("Cannot get cachefs key kstat"));
175 		goto out;
176 	}
177 	k = (cachefs_kstat_key_t *)key->ks_data;
178 	n = key->ks_ndata;
179 
180 	if (st->st_flags & ST_BOUND) {
181 		for (i = 0; i < n; i++)
182 			if (st->st_fsid == k[i].ks_id)
183 				break;
184 		++i;
185 		if (i < n) {
186 			prc = k + i;
187 			st->st_fsid = k[i].ks_id;
188 		} else
189 			st->st_flags &= ~ST_BOUND;
190 	} else if (n > 0) {
191 		st->st_fsid = k[0].ks_id;
192 		st->st_flags |= ST_BOUND;
193 		prc = k;
194 	}
195 
196 out:
197 	if (prc != NULL) {
198 		char *s;
199 		int size;
200 
201 		prc->ks_mountpoint += (uintptr_t)k;
202 		prc->ks_backfs += (uintptr_t)k;
203 		prc->ks_cachedir += (uintptr_t)k;
204 		prc->ks_cacheid += (uintptr_t)k;
205 
206 		size = sizeof (*rc);
207 		size += strlen((char *)(uintptr_t)prc->ks_mountpoint) + 1;
208 		size += strlen((char *)(uintptr_t)prc->ks_backfs) + 1;
209 		size += strlen((char *)(uintptr_t)prc->ks_cachedir) + 1;
210 		size += strlen((char *)(uintptr_t)prc->ks_cacheid) + 1;
211 
212 		if ((rc = (cachefs_kstat_key_t *)
213 		    malloc(size)) == NULL) {
214 			stats_perror(st, SE_NOMEM,
215 			    gettext("Cannot malloc return code"));
216 		} else {
217 			memcpy(rc, prc, sizeof (*rc));
218 			s = (char *)((uintptr_t)rc + sizeof (*rc));
219 
220 			(void) strcpy(s, (char *)(uintptr_t)prc->ks_mountpoint);
221 			rc->ks_mountpoint = (uintptr_t)s;
222 			s += strlen(s) + 1;
223 			(void) strcpy(s, (char *)(uintptr_t)prc->ks_backfs);
224 			rc->ks_backfs = (uintptr_t)s;
225 			s += strlen(s) + 1;
226 			(void) strcpy(s, (char *)(uintptr_t)prc->ks_cachedir);
227 			rc->ks_cachedir = (uintptr_t)s;
228 			s += strlen(s) + 1;
229 			(void) strcpy(s, (char *)(uintptr_t)prc->ks_cacheid);
230 			rc->ks_cacheid = (uintptr_t)s;
231 		}
232 	}
233 
234 	return (rc);
235 }
236 
237 cachefs_kstat_key_t *
238 stats_getkey(stats_cookie_t *st)
239 {
240 	kstat_t *ksp;
241 	cachefs_kstat_key_t *k, *key, *rc = NULL;
242 	int size;
243 	char *s;
244 
245 	assert(stats_good(st));
246 	assert(st->st_flags & ST_BOUND);
247 
248 	if (((ksp = kstat_lookup(st->st_kstat_cookie, "cachefs", 0,
249 	    "key")) == NULL) ||
250 	    (kstat_read(st->st_kstat_cookie, ksp, NULL) < 0)) {
251 		stats_perror(st, SE_KERNEL,
252 		    gettext("Cannot get cachefs key kstat"));
253 		goto out;
254 	}
255 	key = (cachefs_kstat_key_t *)ksp->ks_data;
256 	k = key + st->st_fsid - 1;
257 	k->ks_mountpoint += (uintptr_t)key;
258 	k->ks_backfs += (uintptr_t)key;
259 	k->ks_cachedir += (uintptr_t)key;
260 	k->ks_cacheid += (uintptr_t)key;
261 	size = sizeof (*rc);
262 	size += strlen((char *)(uintptr_t)k->ks_mountpoint) + 1;
263 	size += strlen((char *)(uintptr_t)k->ks_backfs) + 1;
264 	size += strlen((char *)(uintptr_t)k->ks_cachedir) + 1;
265 	size += strlen((char *)(uintptr_t)k->ks_cacheid) + 1;
266 
267 	if ((rc = (cachefs_kstat_key_t *)malloc(size)) == NULL)
268 		stats_perror(st, SE_NOMEM,
269 		    gettext("Cannot malloc return code"));
270 	else {
271 		memcpy(rc, k, sizeof (*rc));
272 		s = (char *)((uintptr_t)rc + sizeof (*rc));
273 
274 		(void) strcpy(s, (char *)(uintptr_t)k->ks_mountpoint);
275 		rc->ks_mountpoint = (uintptr_t)s;
276 		s += strlen(s) + 1;
277 		(void) strcpy(s, (char *)(uintptr_t)k->ks_backfs);
278 		rc->ks_backfs = (uintptr_t)s;
279 		s += strlen(s) + 1;
280 		(void) strcpy(s, (char *)(uintptr_t)k->ks_cachedir);
281 		rc->ks_cachedir = (uintptr_t)s;
282 		s += strlen(s) + 1;
283 		(void) strcpy(s, (char *)(uintptr_t)k->ks_cacheid);
284 		rc->ks_cacheid = (uintptr_t)s;
285 		s += strlen(s) + 1;
286 	}
287 
288 	assert(rc->ks_id == st->st_fsid);
289 
290 out:
291 	return (rc);
292 }
293 
294 void
295 stats_destroy(stats_cookie_t *st)
296 {
297 	void free();
298 
299 	if (st == NULL)
300 		return;
301 
302 	if (st->st_kstat_cookie != NULL)
303 		kstat_close(st->st_kstat_cookie);
304 	if (st->st_logxdr.x_ops != NULL)
305 		xdr_destroy(&st->st_logxdr);
306 	if ((st->st_logstream != NULL) && (st->st_flags & ST_LFOPEN))
307 		(void) fclose(st->st_logstream);
308 
309 	/*
310 	 * we don't want to depend on dbm (or stats_dbm), so we don't
311 	 * do a stats_dbm_close.  we do try to require the client to
312 	 * have done it, via an assert(), however.
313 	 */
314 
315 	assert(! (st->st_flags & ST_DBMOPEN));
316 
317 	st->st_magic++;
318 
319 	free(st);
320 }
321 
322 int
323 stats_good(stats_cookie_t *st)
324 {
325 	if (st == NULL)
326 		return (0);
327 	if (st->st_magic != STATS_MAGIC)
328 		return (0);
329 	if (! (st->st_flags & ST_VALID))
330 		return (0);
331 
332 	return (1);
333 }
334 
335 void
336 /*PRINTFLIKE3*/
337 stats_perror(stats_cookie_t *st, int Errno, char *fmt, ...)
338 {
339 
340 	va_list ap;
341 
342 	assert(st != NULL);
343 	assert(st->st_magic == STATS_MAGIC);
344 
345 	va_start(ap, fmt);
346 	(void) vsnprintf(st->st_errorstr, sizeof (st->st_errorstr), fmt, ap);
347 	va_end(ap);
348 
349 	st->st_errno = Errno;
350 
351 	st->st_flags |= ST_ERROR;
352 }
353 
354 char *
355 stats_errorstr(stats_cookie_t *st)
356 {
357 	assert(st != NULL);
358 	assert(st->st_magic == STATS_MAGIC);
359 
360 	return (st->st_errorstr);
361 }
362 
363 int
364 stats_errno(stats_cookie_t *st)
365 {
366 	assert(st != NULL);
367 	assert(st->st_magic == STATS_MAGIC);
368 
369 	return (st->st_errno);
370 }
371 
372 int
373 stats_inerror(stats_cookie_t *st)
374 {
375 	assert(st != NULL);
376 	assert(st->st_magic == STATS_MAGIC);
377 
378 	return (st->st_flags & ST_ERROR);
379 }
380