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 }