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