xref: /titanic_50/usr/src/uts/common/io/kstat.c (revision 711890bc9379ceea66272dc8d4981812224ea86e)
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  * kernel statistics driver
31  */
32 
33 #include <sys/types.h>
34 #include <sys/time.h>
35 #include <sys/param.h>
36 #include <sys/sysmacros.h>
37 #include <sys/file.h>
38 #include <sys/cmn_err.h>
39 #include <sys/t_lock.h>
40 #include <sys/proc.h>
41 #include <sys/fcntl.h>
42 #include <sys/uio.h>
43 #include <sys/kmem.h>
44 #include <sys/cred.h>
45 #include <sys/mman.h>
46 #include <sys/errno.h>
47 #include <sys/ioccom.h>
48 #include <sys/cpuvar.h>
49 #include <sys/stat.h>
50 #include <sys/conf.h>
51 #include <sys/ddi.h>
52 #include <sys/sunddi.h>
53 #include <sys/modctl.h>
54 #include <sys/kobj.h>
55 #include <sys/kstat.h>
56 #include <sys/atomic.h>
57 #include <sys/policy.h>
58 #include <sys/zone.h>
59 
60 static dev_info_t *kstat_devi;
61 
62 static int
63 read_kstat_data(int *rvalp, void *user_ksp, int flag)
64 {
65 	kstat_t user_kstat, *ksp;
66 #ifdef _MULTI_DATAMODEL
67 	kstat32_t user_kstat32;
68 #endif
69 	void *kbuf = NULL;
70 	size_t kbufsize, ubufsize, copysize;
71 	int error = 0;
72 	uint_t model;
73 
74 	switch (model = ddi_model_convert_from(flag & FMODELS)) {
75 #ifdef _MULTI_DATAMODEL
76 	case DDI_MODEL_ILP32:
77 		if (copyin(user_ksp, &user_kstat32, sizeof (kstat32_t)) != 0)
78 			return (EFAULT);
79 		user_kstat.ks_kid = user_kstat32.ks_kid;
80 		user_kstat.ks_data = (void *)(uintptr_t)user_kstat32.ks_data;
81 		user_kstat.ks_data_size = (size_t)user_kstat32.ks_data_size;
82 		break;
83 #endif
84 	default:
85 	case DDI_MODEL_NONE:
86 		if (copyin(user_ksp, &user_kstat, sizeof (kstat_t)) != 0)
87 			return (EFAULT);
88 	}
89 
90 	ksp = kstat_hold_bykid(user_kstat.ks_kid, getzoneid());
91 	if (ksp == NULL) {
92 		/*
93 		 * There is no kstat with the specified KID
94 		 */
95 		return (ENXIO);
96 	}
97 	if (ksp->ks_flags & KSTAT_FLAG_INVALID) {
98 		/*
99 		 * The kstat exists, but is momentarily in some
100 		 * indeterminate state (e.g. the data section is not
101 		 * yet initialized).  Try again in a few milliseconds.
102 		 */
103 		kstat_rele(ksp);
104 		return (EAGAIN);
105 	}
106 
107 	/*
108 	 * If it's a fixed-size kstat, allocate the buffer now, so we
109 	 * don't have to do it under the kstat's data lock.  (If it's a
110 	 * var-size kstat, we don't know the size until after the update
111 	 * routine is called, so we can't do this optimization.)
112 	 * The allocator relies on this behavior to prevent recursive
113 	 * mutex_enter in its (fixed-size) kstat update routine.
114 	 * It's a zalloc to prevent unintentional exposure of random
115 	 * juicy morsels of (old) kernel data.
116 	 */
117 	if (!(ksp->ks_flags & KSTAT_FLAG_VAR_SIZE)) {
118 		kbufsize = ksp->ks_data_size;
119 		kbuf = kmem_zalloc(kbufsize + 1, KM_NOSLEEP);
120 		if (kbuf == NULL) {
121 			kstat_rele(ksp);
122 			return (EAGAIN);
123 		}
124 	}
125 	KSTAT_ENTER(ksp);
126 	if ((error = KSTAT_UPDATE(ksp, KSTAT_READ)) != 0) {
127 		KSTAT_EXIT(ksp);
128 		kstat_rele(ksp);
129 		if (kbuf != NULL)
130 			kmem_free(kbuf, kbufsize + 1);
131 		return (error);
132 	}
133 
134 	kbufsize = ksp->ks_data_size;
135 	ubufsize = user_kstat.ks_data_size;
136 
137 	if (ubufsize < kbufsize) {
138 		error = ENOMEM;
139 	} else {
140 		if (kbuf == NULL)
141 			kbuf = kmem_zalloc(kbufsize + 1, KM_NOSLEEP);
142 		if (kbuf == NULL) {
143 			error = EAGAIN;
144 		} else {
145 			error = KSTAT_SNAPSHOT(ksp, kbuf, KSTAT_READ);
146 		}
147 	}
148 
149 	/*
150 	 * The following info must be returned to user level,
151 	 * even if the the update or snapshot failed.  This allows
152 	 * kstat readers to get a handle on variable-size kstats,
153 	 * detect dormant kstats, etc.
154 	 */
155 	user_kstat.ks_ndata	= ksp->ks_ndata;
156 	user_kstat.ks_data_size	= kbufsize;
157 	user_kstat.ks_flags	= ksp->ks_flags;
158 	user_kstat.ks_snaptime	= ksp->ks_snaptime;
159 
160 	*rvalp = kstat_chain_id;
161 	KSTAT_EXIT(ksp);
162 	kstat_rele(ksp);
163 
164 	/*
165 	 * Copy the buffer containing the kstat back to userland.
166 	 */
167 	copysize = kbufsize;
168 	if (kbuf != NULL) {
169 #ifdef _MULTI_DATAMODEL
170 		kstat32_t *k32;
171 		kstat_t *k;
172 #endif
173 		int i;
174 
175 		switch (model) {
176 #ifdef _MULTI_DATAMODEL
177 		case DDI_MODEL_ILP32:
178 
179 			if (ksp->ks_type == KSTAT_TYPE_NAMED) {
180 				kstat_named_t *kn = kbuf;
181 
182 				for (i = 0; i < user_kstat.ks_ndata; kn++, i++)
183 					switch (kn->data_type) {
184 					/*
185 					 * Named statistics have fields of type
186 					 * 'long'.  For a 32-bit application
187 					 * looking at a 64-bit kernel,
188 					 * forcibly truncate these 64-bit
189 					 * quantities to 32-bit values.
190 					 */
191 					case KSTAT_DATA_LONG:
192 						kn->value.i32 =
193 						    (int32_t)kn->value.l;
194 						kn->data_type =
195 						    KSTAT_DATA_INT32;
196 						break;
197 					case KSTAT_DATA_ULONG:
198 						kn->value.ui32 =
199 						    (uint32_t)kn->value.ul;
200 						kn->data_type =
201 						    KSTAT_DATA_UINT32;
202 						break;
203 					/*
204 					 * Long strings must be massaged before
205 					 * being copied out to userland.  Do
206 					 * that here.
207 					 */
208 					case KSTAT_DATA_STRING:
209 						if (KSTAT_NAMED_STR_PTR(kn)
210 						    == NULL)
211 							break;
212 						/*
213 						 * The offsets within the
214 						 * buffers are the same, so add
215 						 * the offset to the beginning
216 						 * of the new buffer to fix the
217 						 * pointer.
218 						 */
219 						KSTAT_NAMED_STR_PTR(kn) =
220 						    (char *)user_kstat.ks_data +
221 						    (KSTAT_NAMED_STR_PTR(kn) -
222 						    (char *)kbuf);
223 						/*
224 						 * Make sure the string pointer
225 						 * lies within the allocated
226 						 * buffer.
227 						 */
228 						ASSERT(KSTAT_NAMED_STR_PTR(kn) +
229 						    KSTAT_NAMED_STR_BUFLEN(kn)
230 						    <=
231 						    ((char *)
232 						    user_kstat.ks_data +
233 						    ubufsize));
234 						ASSERT(KSTAT_NAMED_STR_PTR(kn)
235 						    >=
236 						    (char *)
237 						    ((kstat_named_t *)
238 						    user_kstat.ks_data +
239 						    user_kstat.ks_ndata));
240 						/*
241 						 * Cast 64-bit ptr to 32-bit.
242 						 */
243 						kn->value.str.addr.ptr32 =
244 						    (caddr32_t)(uintptr_t)
245 						    KSTAT_NAMED_STR_PTR(kn);
246 						break;
247 					default:
248 						break;
249 					}
250 			}
251 
252 			if (user_kstat.ks_kid != 0)
253 				break;
254 
255 			/*
256 			 * This is the special case of the kstat header
257 			 * list for the entire system.  Reshape the
258 			 * array in place, then copy it out.
259 			 */
260 			k32 = kbuf;
261 			k = kbuf;
262 			for (i = 0; i < user_kstat.ks_ndata; k32++, k++, i++) {
263 				k32->ks_crtime		= k->ks_crtime;
264 				k32->ks_next		= 0;
265 				k32->ks_kid		= k->ks_kid;
266 				(void) strcpy(k32->ks_module, k->ks_module);
267 				k32->ks_resv		= k->ks_resv;
268 				k32->ks_instance	= k->ks_instance;
269 				(void) strcpy(k32->ks_name, k->ks_name);
270 				k32->ks_type		= k->ks_type;
271 				(void) strcpy(k32->ks_class, k->ks_class);
272 				k32->ks_flags		= k->ks_flags;
273 				k32->ks_data		= 0;
274 				k32->ks_ndata		= k->ks_ndata;
275 				if (k->ks_data_size > UINT32_MAX) {
276 					error = EOVERFLOW;
277 					break;
278 				}
279 				k32->ks_data_size = (size32_t)k->ks_data_size;
280 				k32->ks_snaptime	= k->ks_snaptime;
281 			}
282 
283 			/*
284 			 * XXX	In this case we copy less data than is
285 			 *	claimed in the header.
286 			 */
287 			copysize = user_kstat.ks_ndata * sizeof (kstat32_t);
288 			break;
289 #endif	/* _MULTI_DATAMODEL */
290 		default:
291 		case DDI_MODEL_NONE:
292 			if (ksp->ks_type == KSTAT_TYPE_NAMED) {
293 				kstat_named_t *kn = kbuf;
294 
295 				for (i = 0; i < user_kstat.ks_ndata; kn++, i++)
296 					switch (kn->data_type) {
297 #ifdef _LP64
298 					case KSTAT_DATA_LONG:
299 						kn->data_type =
300 						    KSTAT_DATA_INT64;
301 						break;
302 					case KSTAT_DATA_ULONG:
303 						kn->data_type =
304 						    KSTAT_DATA_UINT64;
305 						break;
306 #endif	/* _LP64 */
307 					case KSTAT_DATA_STRING:
308 						if (KSTAT_NAMED_STR_PTR(kn)
309 						    == NULL)
310 							break;
311 						KSTAT_NAMED_STR_PTR(kn) =
312 						    (char *)user_kstat.ks_data +
313 						    (KSTAT_NAMED_STR_PTR(kn) -
314 						    (char *)kbuf);
315 						ASSERT(KSTAT_NAMED_STR_PTR(kn) +
316 						    KSTAT_NAMED_STR_BUFLEN(kn)
317 						    <=
318 						    ((char *)
319 						    user_kstat.ks_data +
320 						    ubufsize));
321 						ASSERT(KSTAT_NAMED_STR_PTR(kn)
322 						    >=
323 						    (char *)
324 						    ((kstat_named_t *)
325 						    user_kstat.ks_data +
326 						    user_kstat.ks_ndata));
327 						break;
328 					default:
329 						break;
330 					}
331 			}
332 			break;
333 		}
334 
335 		if (error == 0 &&
336 		    copyout(kbuf, user_kstat.ks_data, copysize))
337 			error = EFAULT;
338 		kmem_free(kbuf, kbufsize + 1);
339 	}
340 
341 	/*
342 	 * We have modified the ks_ndata, ks_data_size, ks_flags, and
343 	 * ks_snaptime fields of the user kstat; now copy it back to userland.
344 	 */
345 	switch (model) {
346 #ifdef _MULTI_DATAMODEL
347 	case DDI_MODEL_ILP32:
348 		if (kbufsize > UINT32_MAX) {
349 			error = EOVERFLOW;
350 			break;
351 		}
352 		user_kstat32.ks_ndata		= user_kstat.ks_ndata;
353 		user_kstat32.ks_data_size	= (size32_t)kbufsize;
354 		user_kstat32.ks_flags		= user_kstat.ks_flags;
355 		user_kstat32.ks_snaptime	= user_kstat.ks_snaptime;
356 		if (copyout(&user_kstat32, user_ksp, sizeof (kstat32_t)) &&
357 		    error == 0)
358 			error = EFAULT;
359 		break;
360 #endif
361 	default:
362 	case DDI_MODEL_NONE:
363 		if (copyout(&user_kstat, user_ksp, sizeof (kstat_t)) &&
364 		    error == 0)
365 			error = EFAULT;
366 		break;
367 	}
368 
369 	return (error);
370 }
371 
372 static int
373 write_kstat_data(int *rvalp, void *user_ksp, int flag, cred_t *cred)
374 {
375 	kstat_t user_kstat, *ksp;
376 	void *buf = NULL;
377 	size_t bufsize;
378 	int error = 0;
379 
380 	if (secpolicy_sys_config(cred, B_FALSE) != 0)
381 		return (EPERM);
382 
383 	switch (ddi_model_convert_from(flag & FMODELS)) {
384 #ifdef _MULTI_DATAMODEL
385 		kstat32_t user_kstat32;
386 
387 	case DDI_MODEL_ILP32:
388 		if (copyin(user_ksp, &user_kstat32, sizeof (kstat32_t)))
389 			return (EFAULT);
390 		/*
391 		 * These are the only fields we actually look at.
392 		 */
393 		user_kstat.ks_kid = user_kstat32.ks_kid;
394 		user_kstat.ks_data = (void *)(uintptr_t)user_kstat32.ks_data;
395 		user_kstat.ks_data_size = (size_t)user_kstat32.ks_data_size;
396 		user_kstat.ks_ndata = user_kstat32.ks_ndata;
397 		break;
398 #endif
399 	default:
400 	case DDI_MODEL_NONE:
401 		if (copyin(user_ksp, &user_kstat, sizeof (kstat_t)))
402 			return (EFAULT);
403 	}
404 
405 	bufsize = user_kstat.ks_data_size;
406 	buf = kmem_alloc(bufsize + 1, KM_NOSLEEP);
407 	if (buf == NULL)
408 		return (EAGAIN);
409 
410 	if (copyin(user_kstat.ks_data, buf, bufsize)) {
411 		kmem_free(buf, bufsize + 1);
412 		return (EFAULT);
413 	}
414 
415 	ksp = kstat_hold_bykid(user_kstat.ks_kid, getzoneid());
416 	if (ksp == NULL) {
417 		kmem_free(buf, bufsize + 1);
418 		return (ENXIO);
419 	}
420 	if (ksp->ks_flags & KSTAT_FLAG_INVALID) {
421 		kstat_rele(ksp);
422 		kmem_free(buf, bufsize + 1);
423 		return (EAGAIN);
424 	}
425 	if (!(ksp->ks_flags & KSTAT_FLAG_WRITABLE)) {
426 		kstat_rele(ksp);
427 		kmem_free(buf, bufsize + 1);
428 		return (EACCES);
429 	}
430 
431 	/*
432 	 * With KSTAT_FLAG_VARIABLE, one must call the kstat's update callback
433 	 * routine to ensure ks_data_size is up to date.
434 	 * In this case it makes sense to do it anyhow, as it will be shortly
435 	 * followed by a KSTAT_SNAPSHOT().
436 	 */
437 	KSTAT_ENTER(ksp);
438 	error = KSTAT_UPDATE(ksp, KSTAT_READ);
439 	if (error || user_kstat.ks_data_size != ksp->ks_data_size ||
440 	    user_kstat.ks_ndata != ksp->ks_ndata) {
441 		KSTAT_EXIT(ksp);
442 		kstat_rele(ksp);
443 		kmem_free(buf, bufsize + 1);
444 		return (error ? error : EINVAL);
445 	}
446 
447 	/*
448 	 * We have to ensure that we don't accidentally change the type of
449 	 * existing kstat_named statistics when writing over them.
450 	 * Since read_kstat_data() modifies some of the types on their way
451 	 * out, we need to be sure to handle these types seperately.
452 	 */
453 	if (ksp->ks_type == KSTAT_TYPE_NAMED) {
454 		void *kbuf;
455 		kstat_named_t *kold;
456 		kstat_named_t *knew = buf;
457 		int i;
458 
459 #ifdef	_MULTI_DATAMODEL
460 		int model = ddi_model_convert_from(flag & FMODELS);
461 #endif
462 
463 		/*
464 		 * Since ksp->ks_data may be NULL, we need to take a snapshot
465 		 * of the published data to look at the types.
466 		 */
467 		kbuf = kmem_alloc(bufsize + 1, KM_NOSLEEP);
468 		if (kbuf == NULL) {
469 			KSTAT_EXIT(ksp);
470 			kstat_rele(ksp);
471 			kmem_free(buf, bufsize + 1);
472 			return (EAGAIN);
473 		}
474 		error = KSTAT_SNAPSHOT(ksp, kbuf, KSTAT_READ);
475 		if (error) {
476 			KSTAT_EXIT(ksp);
477 			kstat_rele(ksp);
478 			kmem_free(kbuf, bufsize + 1);
479 			kmem_free(buf, bufsize + 1);
480 			return (error);
481 		}
482 		kold = kbuf;
483 
484 		/*
485 		 * read_kstat_data() changes the types of
486 		 * KSTAT_DATA_LONG / KSTAT_DATA_ULONG, so we need to
487 		 * make sure that these (modified) types are considered
488 		 * valid.
489 		 */
490 		for (i = 0; i < ksp->ks_ndata; i++, kold++, knew++) {
491 			switch (kold->data_type) {
492 #ifdef	_MULTI_DATAMODEL
493 			case KSTAT_DATA_LONG:
494 				switch (model) {
495 				case DDI_MODEL_ILP32:
496 					if (knew->data_type ==
497 					    KSTAT_DATA_INT32) {
498 						knew->value.l =
499 						    (long)knew->value.i32;
500 						knew->data_type =
501 						    KSTAT_DATA_LONG;
502 					}
503 					break;
504 				default:
505 				case DDI_MODEL_NONE:
506 #ifdef _LP64
507 					if (knew->data_type ==
508 					    KSTAT_DATA_INT64) {
509 						knew->value.l =
510 						    (long)knew->value.i64;
511 						knew->data_type =
512 						    KSTAT_DATA_LONG;
513 					}
514 #endif /* _LP64 */
515 					break;
516 				}
517 				break;
518 			case KSTAT_DATA_ULONG:
519 				switch (model) {
520 				case DDI_MODEL_ILP32:
521 					if (knew->data_type ==
522 					    KSTAT_DATA_UINT32) {
523 						knew->value.ul =
524 						    (ulong_t)knew->value.ui32;
525 						knew->data_type =
526 						    KSTAT_DATA_ULONG;
527 					}
528 					break;
529 				default:
530 				case DDI_MODEL_NONE:
531 #ifdef _LP64
532 					if (knew->data_type ==
533 					    KSTAT_DATA_UINT64) {
534 						knew->value.ul =
535 						    (ulong_t)knew->value.ui64;
536 						knew->data_type =
537 						    KSTAT_DATA_ULONG;
538 					}
539 #endif /* _LP64 */
540 					break;
541 				}
542 				break;
543 #endif /* _MULTI_DATAMODEL */
544 			case KSTAT_DATA_STRING:
545 				if (knew->data_type != KSTAT_DATA_STRING) {
546 					KSTAT_EXIT(ksp);
547 					kstat_rele(ksp);
548 					kmem_free(kbuf, bufsize + 1);
549 					kmem_free(buf, bufsize + 1);
550 					return (EINVAL);
551 				}
552 
553 #ifdef _MULTI_DATAMODEL
554 				if (model == DDI_MODEL_ILP32)
555 					KSTAT_NAMED_STR_PTR(knew) =
556 					    (char *)(uintptr_t)
557 					    knew->value.str.addr.ptr32;
558 #endif
559 				/*
560 				 * Nothing special for NULL
561 				 */
562 				if (KSTAT_NAMED_STR_PTR(knew) == NULL)
563 					break;
564 
565 				/*
566 				 * Check to see that the pointers all point
567 				 * to within the buffer and after the array
568 				 * of kstat_named_t's.
569 				 */
570 				if (KSTAT_NAMED_STR_PTR(knew) <
571 				    (char *)
572 				    ((kstat_named_t *)user_kstat.ks_data +
573 				    ksp->ks_ndata)) {
574 					KSTAT_EXIT(ksp);
575 					kstat_rele(ksp);
576 					kmem_free(kbuf, bufsize + 1);
577 					kmem_free(buf, bufsize + 1);
578 					return (EINVAL);
579 				}
580 				if (KSTAT_NAMED_STR_PTR(knew) +
581 				    KSTAT_NAMED_STR_BUFLEN(knew) >
582 				    ((char *)user_kstat.ks_data +
583 				    ksp->ks_data_size)) {
584 					KSTAT_EXIT(ksp);
585 					kstat_rele(ksp);
586 					kmem_free(kbuf, bufsize + 1);
587 					kmem_free(buf, bufsize + 1);
588 					return (EINVAL);
589 				}
590 
591 				/*
592 				 * Update the pointers within the buffer
593 				 */
594 				KSTAT_NAMED_STR_PTR(knew) =
595 				    (char *)buf +
596 				    (KSTAT_NAMED_STR_PTR(knew) -
597 				    (char *)user_kstat.ks_data);
598 				break;
599 			default:
600 				break;
601 			}
602 		}
603 
604 		kold = kbuf;
605 		knew = buf;
606 
607 		/*
608 		 * Now make sure the types are what we expected them to be.
609 		 */
610 		for (i = 0; i < ksp->ks_ndata; i++, kold++, knew++)
611 			if (kold->data_type != knew->data_type) {
612 				KSTAT_EXIT(ksp);
613 				kstat_rele(ksp);
614 				kmem_free(kbuf, bufsize + 1);
615 				kmem_free(buf, bufsize + 1);
616 				return (EINVAL);
617 			}
618 
619 		kmem_free(kbuf, bufsize + 1);
620 	}
621 
622 	error = KSTAT_SNAPSHOT(ksp, buf, KSTAT_WRITE);
623 	if (!error)
624 		error = KSTAT_UPDATE(ksp, KSTAT_WRITE);
625 	*rvalp = kstat_chain_id;
626 	KSTAT_EXIT(ksp);
627 	kstat_rele(ksp);
628 	kmem_free(buf, bufsize + 1);
629 	return (error);
630 }
631 
632 /*ARGSUSED*/
633 static int
634 kstat_ioctl(dev_t dev, int cmd, intptr_t data, int flag, cred_t *cr, int *rvalp)
635 {
636 	int rc = 0;
637 
638 	switch (cmd) {
639 
640 	case KSTAT_IOC_CHAIN_ID:
641 		*rvalp = kstat_chain_id;
642 		break;
643 
644 	case KSTAT_IOC_READ:
645 		rc = read_kstat_data(rvalp, (void *)data, flag);
646 		break;
647 
648 	case KSTAT_IOC_WRITE:
649 		rc = write_kstat_data(rvalp, (void *)data, flag, cr);
650 		break;
651 
652 	default:
653 		/* invalid request */
654 		rc = EINVAL;
655 	}
656 	return (rc);
657 }
658 
659 /* ARGSUSED */
660 static int
661 kstat_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
662 	void **result)
663 {
664 	switch (infocmd) {
665 	case DDI_INFO_DEVT2DEVINFO:
666 		*result = kstat_devi;
667 		return (DDI_SUCCESS);
668 	case DDI_INFO_DEVT2INSTANCE:
669 		*result = NULL;
670 		return (DDI_SUCCESS);
671 	}
672 	return (DDI_FAILURE);
673 }
674 
675 static int
676 kstat_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
677 {
678 	if (cmd != DDI_ATTACH)
679 		return (DDI_FAILURE);
680 
681 	if (ddi_create_minor_node(devi, "kstat", S_IFCHR,
682 	    0, DDI_PSEUDO, NULL) == DDI_FAILURE) {
683 		ddi_remove_minor_node(devi, NULL);
684 		return (DDI_FAILURE);
685 	}
686 	kstat_devi = devi;
687 	return (DDI_SUCCESS);
688 }
689 
690 static int
691 kstat_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
692 {
693 	if (cmd != DDI_DETACH)
694 		return (DDI_FAILURE);
695 
696 	ddi_remove_minor_node(devi, NULL);
697 	return (DDI_SUCCESS);
698 }
699 
700 static struct cb_ops kstat_cb_ops = {
701 	nulldev,		/* open */
702 	nulldev,		/* close */
703 	nodev,			/* strategy */
704 	nodev,			/* print */
705 	nodev,			/* dump */
706 	nodev,			/* read */
707 	nodev,			/* write */
708 	kstat_ioctl,		/* ioctl */
709 	nodev,			/* devmap */
710 	nodev,			/* mmap */
711 	nodev,			/* segmap */
712 	nochpoll,		/* poll */
713 	ddi_prop_op,		/* prop_op */
714 	0,			/* streamtab  */
715 	D_NEW | D_MP		/* Driver compatibility flag */
716 };
717 
718 static struct dev_ops kstat_ops = {
719 	DEVO_REV,		/* devo_rev, */
720 	0,			/* refcnt  */
721 	kstat_info,		/* get_dev_info */
722 	nulldev,		/* identify */
723 	nulldev,		/* probe */
724 	kstat_attach,		/* attach */
725 	kstat_detach,		/* detach */
726 	nodev,			/* reset */
727 	&kstat_cb_ops,		/* driver operations */
728 	(struct bus_ops *)0	/* no bus operations */
729 };
730 
731 static struct modldrv modldrv = {
732 	&mod_driverops, "kernel statistics driver %I%", &kstat_ops,
733 };
734 
735 static struct modlinkage modlinkage = {
736 	MODREV_1, &modldrv, NULL
737 };
738 
739 int
740 _init(void)
741 {
742 	return (mod_install(&modlinkage));
743 }
744 
745 int
746 _fini(void)
747 {
748 	return (mod_remove(&modlinkage));
749 }
750 
751 int
752 _info(struct modinfo *modinfop)
753 {
754 	return (mod_info(&modlinkage, modinfop));
755 }
756