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 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 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 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 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 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 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 772 _init(void) 773 { 774 return (mod_install(&modlinkage)); 775 } 776 777 int 778 _fini(void) 779 { 780 return (mod_remove(&modlinkage)); 781 } 782 783 int 784 _info(struct modinfo *modinfop) 785 { 786 return (mod_info(&modlinkage, modinfop)); 787 } 788