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
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.
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]
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
44 kstat_zalloc(void **ptr
, size_t size
, int free_first
)
48 *ptr
= calloc(size
, 1);
52 kstat_chain_free(kstat_ctl_t
*kc
)
73 kd
= open("/dev/kstat", O_RDONLY
);
76 kstat_zalloc((void **)&kc
, sizeof (kstat_ctl_t
), 0);
83 if (kstat_chain_update(kc
) == -1) {
84 int saved_err
= errno
;
85 (void) kstat_close(kc
);
93 kstat_close(kstat_ctl_t
*kc
)
98 rc
= close(kc
->kc_kd
);
104 kstat_read(kstat_ctl_t
*kc
, kstat_t
*ksp
, void *data
)
108 if (ksp
->ks_data
== NULL
&& ksp
->ks_data_size
> 0) {
109 kstat_zalloc(&ksp
->ks_data
, ksp
->ks_data_size
, 0);
110 if (ksp
->ks_data
== NULL
)
113 while ((kcid
= (kid_t
)ioctl(kc
->kc_kd
, KSTAT_IOC_READ
, ksp
)) == -1) {
114 if (errno
== EAGAIN
) {
115 (void) poll(NULL
, 0, 100); /* back off a moment */
116 continue; /* and try again */
119 * Mating dance for variable-size kstats.
120 * You start with a buffer of a certain size,
121 * which you hope will hold all the data.
122 * If your buffer is too small, the kstat driver
123 * returns ENOMEM and sets ksp->ks_data_size to
124 * the current size of the kstat's data. You then
125 * resize your buffer and try again. In practice,
126 * this almost always converges in two passes.
128 if (errno
== ENOMEM
&& (ksp
->ks_flags
&
129 (KSTAT_FLAG_VAR_SIZE
| KSTAT_FLAG_LONGSTRINGS
))) {
130 kstat_zalloc(&ksp
->ks_data
, ksp
->ks_data_size
, 1);
131 if (ksp
->ks_data
!= NULL
)
137 (void) memcpy(data
, ksp
->ks_data
, ksp
->ks_data_size
);
138 if (ksp
->ks_type
== KSTAT_TYPE_NAMED
&&
140 ksp
->ks_ndata
* sizeof (kstat_named_t
)) {
142 * Has KSTAT_DATA_STRING fields. Fix the pointers.
145 kstat_named_t
*knp
= data
;
147 for (i
= 0; i
< ksp
->ks_ndata
; i
++, knp
++) {
148 if (knp
->data_type
!= KSTAT_DATA_STRING
)
150 if (KSTAT_NAMED_STR_PTR(knp
) == NULL
)
153 * The offsets of the strings within the
154 * buffers are the same, so add the offset of
155 * the string to the beginning of 'data' to fix
156 * the pointer so that strings in 'data' don't
157 * point at memory in 'ksp->ks_data'.
159 KSTAT_NAMED_STR_PTR(knp
) = (char *)data
+
160 (KSTAT_NAMED_STR_PTR(knp
) -
161 (char *)ksp
->ks_data
);
169 kstat_write(kstat_ctl_t
*kc
, kstat_t
*ksp
, void *data
)
173 if (ksp
->ks_data
== NULL
&& ksp
->ks_data_size
> 0) {
174 kstat_zalloc(&ksp
->ks_data
, ksp
->ks_data_size
, 0);
175 if (ksp
->ks_data
== NULL
)
179 (void) memcpy(ksp
->ks_data
, data
, ksp
->ks_data_size
);
180 if (ksp
->ks_type
== KSTAT_TYPE_NAMED
) {
181 kstat_named_t
*oknp
= data
;
182 kstat_named_t
*nknp
= KSTAT_NAMED_PTR(ksp
);
185 for (i
= 0; i
< ksp
->ks_ndata
; i
++, oknp
++, nknp
++) {
186 if (nknp
->data_type
!= KSTAT_DATA_STRING
)
188 if (KSTAT_NAMED_STR_PTR(nknp
) == NULL
)
191 * The buffer passed in as 'data' has string
192 * pointers that point within 'data'. Fix the
193 * pointers so they point into the same offset
194 * within the newly allocated buffer.
196 KSTAT_NAMED_STR_PTR(nknp
) =
197 (char *)ksp
->ks_data
+
198 (KSTAT_NAMED_STR_PTR(oknp
) - (char *)data
);
203 while ((kcid
= (kid_t
)ioctl(kc
->kc_kd
, KSTAT_IOC_WRITE
, ksp
)) == -1) {
204 if (errno
== EAGAIN
) {
205 (void) poll(NULL
, 0, 100); /* back off a moment */
206 continue; /* and try again */
214 * If the current KCID is the same as kc->kc_chain_id, return 0;
215 * if different, update the chain and return the new KCID.
216 * This operation is non-destructive for unchanged kstats.
219 kstat_chain_update(kstat_ctl_t
*kc
)
221 kstat_t k0
, *headers
, *oksp
, *nksp
, **okspp
, *next
;
225 kcid
= (kid_t
)ioctl(kc
->kc_kd
, KSTAT_IOC_CHAIN_ID
, NULL
);
228 if (kcid
== kc
->kc_chain_id
)
232 * kstat 0's data is the kstat chain, so we can get the chain
233 * by doing a kstat_read() of this kstat. The only fields the
234 * kstat driver needs are ks_kid (this identifies the kstat),
235 * ks_data (the pointer to our buffer), and ks_data_size (the
236 * size of our buffer). By zeroing the struct we set ks_data = NULL
237 * and ks_data_size = 0, so that kstat_read() will automatically
238 * determine the size and allocate space for us. We also fill in the
239 * name, so that truss can print something meaningful.
241 bzero(&k0
, sizeof (k0
));
242 (void) strcpy(k0
.ks_name
, "kstat_headers");
244 kcid
= kstat_read(kc
, &k0
, NULL
);
247 /* errno set by kstat_read() */
250 headers
= k0
.ks_data
;
253 * Chain the new headers together
255 for (i
= 1; i
< k0
.ks_ndata
; i
++)
256 headers
[i
- 1].ks_next
= &headers
[i
];
258 headers
[k0
.ks_ndata
- 1].ks_next
= NULL
;
261 * Remove all deleted kstats from the chain.
264 okspp
= &kc
->kc_chain
;
266 while (oksp
!= NULL
) {
267 next
= oksp
->ks_next
;
268 if (nksp
!= NULL
&& oksp
->ks_kid
== nksp
->ks_kid
) {
269 okspp
= &oksp
->ks_next
;
270 nksp
= nksp
->ks_next
;
272 *okspp
= oksp
->ks_next
;
280 * Add all new kstats to the chain.
282 while (nksp
!= NULL
) {
283 kstat_zalloc((void **)okspp
, sizeof (kstat_t
), 0);
284 if ((oksp
= *okspp
) == NULL
) {
289 okspp
= &oksp
->ks_next
;
290 oksp
->ks_next
= NULL
;
291 oksp
->ks_data
= NULL
;
292 nksp
= nksp
->ks_next
;
296 kc
->kc_chain_id
= kcid
;
301 kstat_lookup(kstat_ctl_t
*kc
, char *ks_module
, int ks_instance
, char *ks_name
)
305 for (ksp
= kc
->kc_chain
; ksp
; ksp
= ksp
->ks_next
) {
306 if ((ks_module
== NULL
||
307 strcmp(ksp
->ks_module
, ks_module
) == 0) &&
308 (ks_instance
== -1 || ksp
->ks_instance
== ks_instance
) &&
309 (ks_name
== NULL
|| strcmp(ksp
->ks_name
, ks_name
) == 0))
318 kstat_data_lookup(kstat_t
*ksp
, char *name
)
323 switch (ksp
->ks_type
) {
325 case KSTAT_TYPE_NAMED
:
326 size
= sizeof (kstat_named_t
);
327 namep
= KSTAT_NAMED_PTR(ksp
)->name
;
330 case KSTAT_TYPE_TIMER
:
331 size
= sizeof (kstat_timer_t
);
332 namep
= KSTAT_TIMER_PTR(ksp
)->name
;
340 datap
= ksp
->ks_data
;
341 for (i
= 0; i
< ksp
->ks_ndata
; i
++) {
342 if (strcmp(name
, namep
) == 0)