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