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.
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.
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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
28 * kernel statistics driver
31 #include <sys/types.h>
33 #include <sys/param.h>
34 #include <sys/sysmacros.h>
36 #include <sys/cmn_err.h>
37 #include <sys/t_lock.h>
39 #include <sys/fcntl.h>
44 #include <sys/errno.h>
45 #include <sys/ioccom.h>
46 #include <sys/cpuvar.h>
50 #include <sys/sunddi.h>
51 #include <sys/modctl.h>
53 #include <sys/kstat.h>
54 #include <sys/atomic.h>
55 #include <sys/policy.h>
58 static dev_info_t
*kstat_devi
;
61 read_kstat_data(int *rvalp
, void *user_ksp
, int flag
)
63 kstat_t user_kstat
, *ksp
;
64 #ifdef _MULTI_DATAMODEL
65 kstat32_t user_kstat32
;
68 size_t kbufsize
, ubufsize
, copysize
;
72 switch (model
= ddi_model_convert_from(flag
& FMODELS
)) {
73 #ifdef _MULTI_DATAMODEL
75 if (copyin(user_ksp
, &user_kstat32
, sizeof (kstat32_t
)) != 0)
77 user_kstat
.ks_kid
= user_kstat32
.ks_kid
;
78 user_kstat
.ks_data
= (void *)(uintptr_t)user_kstat32
.ks_data
;
79 user_kstat
.ks_data_size
= (size_t)user_kstat32
.ks_data_size
;
84 if (copyin(user_ksp
, &user_kstat
, sizeof (kstat_t
)) != 0)
88 ksp
= kstat_hold_bykid(user_kstat
.ks_kid
, getzoneid());
91 * There is no kstat with the specified KID
95 if (ksp
->ks_flags
& KSTAT_FLAG_INVALID
) {
97 * The kstat exists, but is momentarily in some
98 * indeterminate state (e.g. the data section is not
99 * yet initialized). Try again in a few milliseconds.
106 * If it's a fixed-size kstat, allocate the buffer now, so we
107 * don't have to do it under the kstat's data lock. (If it's a
108 * var-size kstat, we don't know the size until after the update
109 * routine is called, so we can't do this optimization.)
110 * The allocator relies on this behavior to prevent recursive
111 * mutex_enter in its (fixed-size) kstat update routine.
112 * It's a zalloc to prevent unintentional exposure of random
113 * juicy morsels of (old) kernel data.
115 if (!(ksp
->ks_flags
& KSTAT_FLAG_VAR_SIZE
)) {
116 kbufsize
= ksp
->ks_data_size
;
117 kbuf
= kmem_zalloc(kbufsize
+ 1, KM_NOSLEEP
);
124 if ((error
= KSTAT_UPDATE(ksp
, KSTAT_READ
)) != 0) {
128 kmem_free(kbuf
, kbufsize
+ 1);
132 kbufsize
= ksp
->ks_data_size
;
133 ubufsize
= user_kstat
.ks_data_size
;
135 if (ubufsize
< kbufsize
) {
139 kbuf
= kmem_zalloc(kbufsize
+ 1, KM_NOSLEEP
);
143 error
= KSTAT_SNAPSHOT(ksp
, kbuf
, KSTAT_READ
);
148 * The following info must be returned to user level,
149 * even if the the update or snapshot failed. This allows
150 * kstat readers to get a handle on variable-size kstats,
151 * detect dormant kstats, etc.
153 user_kstat
.ks_ndata
= ksp
->ks_ndata
;
154 user_kstat
.ks_data_size
= kbufsize
;
155 user_kstat
.ks_flags
= ksp
->ks_flags
;
156 user_kstat
.ks_snaptime
= ksp
->ks_snaptime
;
158 *rvalp
= kstat_chain_id
;
163 * Copy the buffer containing the kstat back to userland.
167 #ifdef _MULTI_DATAMODEL
174 #ifdef _MULTI_DATAMODEL
175 case DDI_MODEL_ILP32
:
177 if (ksp
->ks_type
== KSTAT_TYPE_NAMED
) {
178 kstat_named_t
*kn
= kbuf
;
180 for (i
= 0; i
< user_kstat
.ks_ndata
; kn
++, i
++)
181 switch (kn
->data_type
) {
183 * Named statistics have fields of type
184 * 'long'. For a 32-bit application
185 * looking at a 64-bit kernel,
186 * forcibly truncate these 64-bit
187 * quantities to 32-bit values.
189 case KSTAT_DATA_LONG
:
191 (int32_t)kn
->value
.l
;
195 case KSTAT_DATA_ULONG
:
197 (uint32_t)kn
->value
.ul
;
202 * Long strings must be massaged before
203 * being copied out to userland. Do
206 case KSTAT_DATA_STRING
:
207 if (KSTAT_NAMED_STR_PTR(kn
)
211 * The offsets within the
212 * buffers are the same, so add
213 * the offset to the beginning
214 * of the new buffer to fix the
217 KSTAT_NAMED_STR_PTR(kn
) =
218 (char *)user_kstat
.ks_data
+
219 (KSTAT_NAMED_STR_PTR(kn
) -
222 * Make sure the string pointer
223 * lies within the allocated
226 ASSERT(KSTAT_NAMED_STR_PTR(kn
) +
227 KSTAT_NAMED_STR_BUFLEN(kn
)
232 ASSERT(KSTAT_NAMED_STR_PTR(kn
)
237 user_kstat
.ks_ndata
));
239 * Cast 64-bit ptr to 32-bit.
241 kn
->value
.str
.addr
.ptr32
=
242 (caddr32_t
)(uintptr_t)
243 KSTAT_NAMED_STR_PTR(kn
);
250 if (user_kstat
.ks_kid
!= 0)
254 * This is the special case of the kstat header
255 * list for the entire system. Reshape the
256 * array in place, then copy it out.
260 for (i
= 0; i
< user_kstat
.ks_ndata
; k32
++, k
++, i
++) {
261 k32
->ks_crtime
= k
->ks_crtime
;
263 k32
->ks_kid
= k
->ks_kid
;
264 (void) strcpy(k32
->ks_module
, k
->ks_module
);
265 k32
->ks_resv
= k
->ks_resv
;
266 k32
->ks_instance
= k
->ks_instance
;
267 (void) strcpy(k32
->ks_name
, k
->ks_name
);
268 k32
->ks_type
= k
->ks_type
;
269 (void) strcpy(k32
->ks_class
, k
->ks_class
);
270 k32
->ks_flags
= k
->ks_flags
;
272 k32
->ks_ndata
= k
->ks_ndata
;
273 if (k
->ks_data_size
> UINT32_MAX
) {
277 k32
->ks_data_size
= (size32_t
)k
->ks_data_size
;
278 k32
->ks_snaptime
= k
->ks_snaptime
;
282 * XXX In this case we copy less data than is
283 * claimed in the header.
285 copysize
= user_kstat
.ks_ndata
* sizeof (kstat32_t
);
287 #endif /* _MULTI_DATAMODEL */
290 if (ksp
->ks_type
== KSTAT_TYPE_NAMED
) {
291 kstat_named_t
*kn
= kbuf
;
293 for (i
= 0; i
< user_kstat
.ks_ndata
; kn
++, i
++)
294 switch (kn
->data_type
) {
296 case KSTAT_DATA_LONG
:
300 case KSTAT_DATA_ULONG
:
305 case KSTAT_DATA_STRING
:
306 if (KSTAT_NAMED_STR_PTR(kn
)
309 KSTAT_NAMED_STR_PTR(kn
) =
310 (char *)user_kstat
.ks_data
+
311 (KSTAT_NAMED_STR_PTR(kn
) -
313 ASSERT(KSTAT_NAMED_STR_PTR(kn
) +
314 KSTAT_NAMED_STR_BUFLEN(kn
)
319 ASSERT(KSTAT_NAMED_STR_PTR(kn
)
324 user_kstat
.ks_ndata
));
334 copyout(kbuf
, user_kstat
.ks_data
, copysize
))
336 kmem_free(kbuf
, kbufsize
+ 1);
340 * We have modified the ks_ndata, ks_data_size, ks_flags, and
341 * ks_snaptime fields of the user kstat; now copy it back to userland.
344 #ifdef _MULTI_DATAMODEL
345 case DDI_MODEL_ILP32
:
346 if (kbufsize
> UINT32_MAX
) {
350 user_kstat32
.ks_ndata
= user_kstat
.ks_ndata
;
351 user_kstat32
.ks_data_size
= (size32_t
)kbufsize
;
352 user_kstat32
.ks_flags
= user_kstat
.ks_flags
;
353 user_kstat32
.ks_snaptime
= user_kstat
.ks_snaptime
;
354 if (copyout(&user_kstat32
, user_ksp
, sizeof (kstat32_t
)) &&
361 if (copyout(&user_kstat
, user_ksp
, sizeof (kstat_t
)) &&
371 write_kstat_data(int *rvalp
, void *user_ksp
, int flag
, cred_t
*cred
)
373 kstat_t user_kstat
, *ksp
;
378 if (secpolicy_sys_config(cred
, B_FALSE
) != 0)
381 switch (ddi_model_convert_from(flag
& FMODELS
)) {
382 #ifdef _MULTI_DATAMODEL
383 kstat32_t user_kstat32
;
385 case DDI_MODEL_ILP32
:
386 if (copyin(user_ksp
, &user_kstat32
, sizeof (kstat32_t
)))
389 * These are the only fields we actually look at.
391 user_kstat
.ks_kid
= user_kstat32
.ks_kid
;
392 user_kstat
.ks_data
= (void *)(uintptr_t)user_kstat32
.ks_data
;
393 user_kstat
.ks_data_size
= (size_t)user_kstat32
.ks_data_size
;
394 user_kstat
.ks_ndata
= user_kstat32
.ks_ndata
;
399 if (copyin(user_ksp
, &user_kstat
, sizeof (kstat_t
)))
403 bufsize
= user_kstat
.ks_data_size
;
404 buf
= kmem_alloc(bufsize
+ 1, KM_NOSLEEP
);
408 if (copyin(user_kstat
.ks_data
, buf
, bufsize
)) {
409 kmem_free(buf
, bufsize
+ 1);
413 ksp
= kstat_hold_bykid(user_kstat
.ks_kid
, getzoneid());
415 kmem_free(buf
, bufsize
+ 1);
418 if (ksp
->ks_flags
& KSTAT_FLAG_INVALID
) {
420 kmem_free(buf
, bufsize
+ 1);
423 if (!(ksp
->ks_flags
& KSTAT_FLAG_WRITABLE
)) {
425 kmem_free(buf
, bufsize
+ 1);
430 * With KSTAT_FLAG_VARIABLE, one must call the kstat's update callback
431 * routine to ensure ks_data_size is up to date.
432 * In this case it makes sense to do it anyhow, as it will be shortly
433 * followed by a KSTAT_SNAPSHOT().
436 error
= KSTAT_UPDATE(ksp
, KSTAT_READ
);
437 if (error
|| user_kstat
.ks_data_size
!= ksp
->ks_data_size
||
438 user_kstat
.ks_ndata
!= ksp
->ks_ndata
) {
441 kmem_free(buf
, bufsize
+ 1);
442 return (error
? error
: EINVAL
);
446 * We have to ensure that we don't accidentally change the type of
447 * existing kstat_named statistics when writing over them.
448 * Since read_kstat_data() modifies some of the types on their way
449 * out, we need to be sure to handle these types seperately.
451 if (ksp
->ks_type
== KSTAT_TYPE_NAMED
) {
454 kstat_named_t
*knew
= buf
;
457 #ifdef _MULTI_DATAMODEL
458 int model
= ddi_model_convert_from(flag
& FMODELS
);
462 * Since ksp->ks_data may be NULL, we need to take a snapshot
463 * of the published data to look at the types.
465 kbuf
= kmem_alloc(bufsize
+ 1, KM_NOSLEEP
);
469 kmem_free(buf
, bufsize
+ 1);
472 error
= KSTAT_SNAPSHOT(ksp
, kbuf
, KSTAT_READ
);
476 kmem_free(kbuf
, bufsize
+ 1);
477 kmem_free(buf
, bufsize
+ 1);
483 * read_kstat_data() changes the types of
484 * KSTAT_DATA_LONG / KSTAT_DATA_ULONG, so we need to
485 * make sure that these (modified) types are considered
488 for (i
= 0; i
< ksp
->ks_ndata
; i
++, kold
++, knew
++) {
489 switch (kold
->data_type
) {
490 #ifdef _MULTI_DATAMODEL
491 case KSTAT_DATA_LONG
:
493 case DDI_MODEL_ILP32
:
494 if (knew
->data_type
==
497 (long)knew
->value
.i32
;
505 if (knew
->data_type
==
508 (long)knew
->value
.i64
;
516 case KSTAT_DATA_ULONG
:
518 case DDI_MODEL_ILP32
:
519 if (knew
->data_type
==
522 (ulong_t
)knew
->value
.ui32
;
530 if (knew
->data_type
==
533 (ulong_t
)knew
->value
.ui64
;
541 #endif /* _MULTI_DATAMODEL */
542 case KSTAT_DATA_STRING
:
543 if (knew
->data_type
!= KSTAT_DATA_STRING
) {
546 kmem_free(kbuf
, bufsize
+ 1);
547 kmem_free(buf
, bufsize
+ 1);
551 #ifdef _MULTI_DATAMODEL
552 if (model
== DDI_MODEL_ILP32
)
553 KSTAT_NAMED_STR_PTR(knew
) =
555 knew
->value
.str
.addr
.ptr32
;
558 * Nothing special for NULL
560 if (KSTAT_NAMED_STR_PTR(knew
) == NULL
)
564 * Check to see that the pointers all point
565 * to within the buffer and after the array
566 * of kstat_named_t's.
568 if (KSTAT_NAMED_STR_PTR(knew
) <
570 ((kstat_named_t
*)user_kstat
.ks_data
+
574 kmem_free(kbuf
, bufsize
+ 1);
575 kmem_free(buf
, bufsize
+ 1);
578 if (KSTAT_NAMED_STR_PTR(knew
) +
579 KSTAT_NAMED_STR_BUFLEN(knew
) >
580 ((char *)user_kstat
.ks_data
+
581 ksp
->ks_data_size
)) {
584 kmem_free(kbuf
, bufsize
+ 1);
585 kmem_free(buf
, bufsize
+ 1);
590 * Update the pointers within the buffer
592 KSTAT_NAMED_STR_PTR(knew
) =
594 (KSTAT_NAMED_STR_PTR(knew
) -
595 (char *)user_kstat
.ks_data
);
606 * Now make sure the types are what we expected them to be.
608 for (i
= 0; i
< ksp
->ks_ndata
; i
++, kold
++, knew
++)
609 if (kold
->data_type
!= knew
->data_type
) {
612 kmem_free(kbuf
, bufsize
+ 1);
613 kmem_free(buf
, bufsize
+ 1);
617 kmem_free(kbuf
, bufsize
+ 1);
620 error
= KSTAT_SNAPSHOT(ksp
, buf
, KSTAT_WRITE
);
622 error
= KSTAT_UPDATE(ksp
, KSTAT_WRITE
);
623 *rvalp
= kstat_chain_id
;
626 kmem_free(buf
, bufsize
+ 1);
632 kstat_ioctl(dev_t dev
, int cmd
, intptr_t data
, int flag
, cred_t
*cr
, int *rvalp
)
638 case KSTAT_IOC_CHAIN_ID
:
639 *rvalp
= kstat_chain_id
;
643 rc
= read_kstat_data(rvalp
, (void *)data
, flag
);
646 case KSTAT_IOC_WRITE
:
647 rc
= write_kstat_data(rvalp
, (void *)data
, flag
, cr
);
651 /* invalid request */
659 kstat_info(dev_info_t
*dip
, ddi_info_cmd_t infocmd
, void *arg
,
663 case DDI_INFO_DEVT2DEVINFO
:
664 *result
= kstat_devi
;
665 return (DDI_SUCCESS
);
666 case DDI_INFO_DEVT2INSTANCE
:
668 return (DDI_SUCCESS
);
670 return (DDI_FAILURE
);
674 kstat_attach(dev_info_t
*devi
, ddi_attach_cmd_t cmd
)
676 if (cmd
!= DDI_ATTACH
)
677 return (DDI_FAILURE
);
679 if (ddi_create_minor_node(devi
, "kstat", S_IFCHR
,
680 0, DDI_PSEUDO
, NULL
) == DDI_FAILURE
) {
681 ddi_remove_minor_node(devi
, NULL
);
682 return (DDI_FAILURE
);
685 return (DDI_SUCCESS
);
689 kstat_detach(dev_info_t
*devi
, ddi_detach_cmd_t cmd
)
691 if (cmd
!= DDI_DETACH
)
692 return (DDI_FAILURE
);
694 ddi_remove_minor_node(devi
, NULL
);
695 return (DDI_SUCCESS
);
698 static struct cb_ops kstat_cb_ops
= {
701 nodev
, /* strategy */
706 kstat_ioctl
, /* ioctl */
711 ddi_prop_op
, /* prop_op */
713 D_NEW
| D_MP
/* Driver compatibility flag */
716 static struct dev_ops kstat_ops
= {
717 DEVO_REV
, /* devo_rev, */
719 kstat_info
, /* get_dev_info */
720 nulldev
, /* identify */
722 kstat_attach
, /* attach */
723 kstat_detach
, /* detach */
725 &kstat_cb_ops
, /* driver operations */
726 (struct bus_ops
*)0, /* no bus operations */
728 ddi_quiesce_not_needed
, /* quiesce */
731 static struct modldrv modldrv
= {
732 &mod_driverops
, "kernel statistics driver", &kstat_ops
,
735 static struct modlinkage modlinkage
= {
736 MODREV_1
, &modldrv
, NULL
742 return (mod_install(&modlinkage
));
748 return (mod_remove(&modlinkage
));
752 _info(struct modinfo
*modinfop
)
754 return (mod_info(&modlinkage
, modinfop
));