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