1*e6b4f1cdSmglocker /* $OpenBSD: kstat.c,v 1.5 2025/01/18 12:31:49 mglocker Exp $ */ 2402315e8Sdlg 3402315e8Sdlg /* 4402315e8Sdlg * Copyright (c) 2020 David Gwynne <dlg@openbsd.org> 5402315e8Sdlg * 6402315e8Sdlg * Permission to use, copy, modify, and distribute this software for any 7402315e8Sdlg * purpose with or without fee is hereby granted, provided that the above 8402315e8Sdlg * copyright notice and this permission notice appear in all copies. 9402315e8Sdlg * 10402315e8Sdlg * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11402315e8Sdlg * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12402315e8Sdlg * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13402315e8Sdlg * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14402315e8Sdlg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15402315e8Sdlg * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16402315e8Sdlg * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17402315e8Sdlg */ 18402315e8Sdlg 19402315e8Sdlg #include <sys/param.h> 20402315e8Sdlg #include <sys/systm.h> 21402315e8Sdlg #include <sys/types.h> 22402315e8Sdlg #include <sys/malloc.h> 23402315e8Sdlg #include <sys/pool.h> 24402315e8Sdlg #include <sys/time.h> 25402315e8Sdlg 26402315e8Sdlg /* for kstat_set_cpu */ 27402315e8Sdlg #include <sys/proc.h> 28402315e8Sdlg #include <sys/sched.h> 29402315e8Sdlg 30402315e8Sdlg #include <sys/kstat.h> 31402315e8Sdlg 32402315e8Sdlg RBT_HEAD(kstat_id_tree, kstat); 33402315e8Sdlg 34402315e8Sdlg static inline int 35402315e8Sdlg kstat_id_cmp(const struct kstat *a, const struct kstat *b) 36402315e8Sdlg { 37402315e8Sdlg if (a->ks_id > b->ks_id) 38402315e8Sdlg return (1); 39402315e8Sdlg if (a->ks_id < b->ks_id) 40402315e8Sdlg return (-1); 41402315e8Sdlg 42402315e8Sdlg return (0); 43402315e8Sdlg } 44402315e8Sdlg 45402315e8Sdlg RBT_PROTOTYPE(kstat_id_tree, kstat, ks_id_entry, kstat_id_cmp); 46402315e8Sdlg 47402315e8Sdlg RBT_HEAD(kstat_pv_tree, kstat); 48402315e8Sdlg 49402315e8Sdlg static inline int 50402315e8Sdlg kstat_pv_cmp(const struct kstat *a, const struct kstat *b) 51402315e8Sdlg { 52402315e8Sdlg int rv; 53402315e8Sdlg 54402315e8Sdlg rv = strcmp(a->ks_provider, b->ks_provider); 55402315e8Sdlg if (rv != 0) 56402315e8Sdlg return (rv); 57402315e8Sdlg 58402315e8Sdlg if (a->ks_instance > b->ks_instance) 59402315e8Sdlg return (1); 60402315e8Sdlg if (a->ks_instance < b->ks_instance) 61402315e8Sdlg return (-1); 62402315e8Sdlg 63402315e8Sdlg rv = strcmp(a->ks_name, b->ks_name); 64402315e8Sdlg if (rv != 0) 65402315e8Sdlg return (rv); 66402315e8Sdlg 67402315e8Sdlg if (a->ks_unit > b->ks_unit) 68402315e8Sdlg return (1); 69402315e8Sdlg if (a->ks_unit < b->ks_unit) 70402315e8Sdlg return (-1); 71402315e8Sdlg 72402315e8Sdlg return (0); 73402315e8Sdlg } 74402315e8Sdlg 75402315e8Sdlg RBT_PROTOTYPE(kstat_pv_tree, kstat, ks_pv_entry, kstat_pv_cmp); 76402315e8Sdlg 77402315e8Sdlg RBT_HEAD(kstat_nm_tree, kstat); 78402315e8Sdlg 79402315e8Sdlg static inline int 80402315e8Sdlg kstat_nm_cmp(const struct kstat *a, const struct kstat *b) 81402315e8Sdlg { 82402315e8Sdlg int rv; 83402315e8Sdlg 84402315e8Sdlg rv = strcmp(a->ks_name, b->ks_name); 85402315e8Sdlg if (rv != 0) 86402315e8Sdlg return (rv); 87402315e8Sdlg 88402315e8Sdlg if (a->ks_unit > b->ks_unit) 89402315e8Sdlg return (1); 90402315e8Sdlg if (a->ks_unit < b->ks_unit) 91402315e8Sdlg return (-1); 92402315e8Sdlg 93402315e8Sdlg rv = strcmp(a->ks_provider, b->ks_provider); 94402315e8Sdlg if (rv != 0) 95402315e8Sdlg return (rv); 96402315e8Sdlg 97402315e8Sdlg if (a->ks_instance > b->ks_instance) 98402315e8Sdlg return (1); 99402315e8Sdlg if (a->ks_instance < b->ks_instance) 100402315e8Sdlg return (-1); 101402315e8Sdlg 102402315e8Sdlg return (0); 103402315e8Sdlg } 104402315e8Sdlg 105402315e8Sdlg RBT_PROTOTYPE(kstat_nm_tree, kstat, ks_nm_entry, kstat_nm_cmp); 106402315e8Sdlg 107402315e8Sdlg struct kstat_lock_ops { 108402315e8Sdlg void (*enter)(void *); 109402315e8Sdlg void (*leave)(void *); 110402315e8Sdlg }; 111402315e8Sdlg 112402315e8Sdlg #define kstat_enter(_ks) (_ks)->ks_lock_ops->enter((_ks)->ks_lock) 113402315e8Sdlg #define kstat_leave(_ks) (_ks)->ks_lock_ops->leave((_ks)->ks_lock) 114402315e8Sdlg 115402315e8Sdlg const struct kstat_lock_ops kstat_rlock_ops = { 116402315e8Sdlg (void (*)(void *))rw_enter_read, 117402315e8Sdlg (void (*)(void *))rw_exit_read, 118402315e8Sdlg }; 119402315e8Sdlg 120402315e8Sdlg const struct kstat_lock_ops kstat_wlock_ops = { 121402315e8Sdlg (void (*)(void *))rw_enter_write, 122402315e8Sdlg (void (*)(void *))rw_exit_write, 123402315e8Sdlg }; 124402315e8Sdlg 125402315e8Sdlg const struct kstat_lock_ops kstat_mutex_ops = { 126402315e8Sdlg (void (*)(void *))mtx_enter, 127402315e8Sdlg (void (*)(void *))mtx_leave, 128402315e8Sdlg }; 129402315e8Sdlg 130402315e8Sdlg void kstat_cpu_enter(void *); 131402315e8Sdlg void kstat_cpu_leave(void *); 132402315e8Sdlg 133402315e8Sdlg const struct kstat_lock_ops kstat_cpu_ops = { 134402315e8Sdlg kstat_cpu_enter, 135402315e8Sdlg kstat_cpu_leave, 136402315e8Sdlg }; 137402315e8Sdlg 138402315e8Sdlg struct rwlock kstat_lock = RWLOCK_INITIALIZER("kstat"); 139402315e8Sdlg 140402315e8Sdlg /* 141402315e8Sdlg * The global state is versioned so changes to the set of kstats 142402315e8Sdlg * can be detected. This is an int so it can be read atomically on 143402315e8Sdlg * any arch, which is a ridiculous optimisation, really. 144402315e8Sdlg */ 145402315e8Sdlg unsigned int kstat_version = 0; 146402315e8Sdlg 147402315e8Sdlg /* 148402315e8Sdlg * kstat structures have a unique identifier so they can be found 149402315e8Sdlg * quickly. Identifiers are 64bit in the hope that it won't wrap 150402315e8Sdlg * during the runtime of a system. The identifiers start at 1 so that 151402315e8Sdlg * 0 can be used as the first value for userland to iterate with. 152402315e8Sdlg */ 153402315e8Sdlg uint64_t kstat_next_id = 1; 154402315e8Sdlg 155402315e8Sdlg struct kstat_id_tree kstat_id_tree = RBT_INITIALIZER(); 156402315e8Sdlg struct kstat_pv_tree kstat_pv_tree = RBT_INITIALIZER(); 157402315e8Sdlg struct kstat_nm_tree kstat_nm_tree = RBT_INITIALIZER(); 158402315e8Sdlg struct pool kstat_pool; 159402315e8Sdlg 160402315e8Sdlg struct rwlock kstat_default_lock = RWLOCK_INITIALIZER("kstatlk"); 161402315e8Sdlg 162402315e8Sdlg int kstat_read(struct kstat *); 163402315e8Sdlg int kstat_copy(struct kstat *, void *); 164402315e8Sdlg 165402315e8Sdlg int 166402315e8Sdlg kstatattach(int num) 167402315e8Sdlg { 168402315e8Sdlg /* XXX install system stats here */ 169402315e8Sdlg return (0); 170402315e8Sdlg } 171402315e8Sdlg 172402315e8Sdlg int 173402315e8Sdlg kstatopen(dev_t dev, int flag, int mode, struct proc *p) 174402315e8Sdlg { 175402315e8Sdlg return (0); 176402315e8Sdlg } 177402315e8Sdlg 178402315e8Sdlg int 179402315e8Sdlg kstatclose(dev_t dev, int flag, int mode, struct proc *p) 180402315e8Sdlg { 181402315e8Sdlg return (0); 182402315e8Sdlg } 183402315e8Sdlg 184402315e8Sdlg int 185402315e8Sdlg kstatioc_enter(struct kstat_req *ksreq) 186402315e8Sdlg { 187402315e8Sdlg int error; 188402315e8Sdlg 189402315e8Sdlg error = rw_enter(&kstat_lock, RW_READ | RW_INTR); 190402315e8Sdlg if (error != 0) 191402315e8Sdlg return (error); 192402315e8Sdlg 193402315e8Sdlg if (!ISSET(ksreq->ks_rflags, KSTATIOC_F_IGNVER) && 194402315e8Sdlg ksreq->ks_version != kstat_version) { 195402315e8Sdlg error = EINVAL; 196402315e8Sdlg goto error; 197402315e8Sdlg } 198402315e8Sdlg 199402315e8Sdlg return (0); 200402315e8Sdlg 201402315e8Sdlg error: 202402315e8Sdlg rw_exit(&kstat_lock); 203402315e8Sdlg return (error); 204402315e8Sdlg } 205402315e8Sdlg 206402315e8Sdlg int 207402315e8Sdlg kstatioc_leave(struct kstat_req *ksreq, struct kstat *ks) 208402315e8Sdlg { 209402315e8Sdlg void *buf = NULL; 210402315e8Sdlg size_t klen = 0, ulen = 0; 211402315e8Sdlg struct timespec updated; 212402315e8Sdlg int error = 0; 213402315e8Sdlg 214402315e8Sdlg if (ks == NULL) { 215402315e8Sdlg error = ENOENT; 216402315e8Sdlg goto error; 217402315e8Sdlg } 218402315e8Sdlg 219402315e8Sdlg switch (ks->ks_state) { 220402315e8Sdlg case KSTAT_S_CREATED: 221402315e8Sdlg ksreq->ks_updated = ks->ks_created; 222402315e8Sdlg ksreq->ks_interval.tv_sec = 0; 223402315e8Sdlg ksreq->ks_interval.tv_nsec = 0; 224402315e8Sdlg ksreq->ks_datalen = 0; 225402315e8Sdlg ksreq->ks_dataver = 0; 226402315e8Sdlg break; 227402315e8Sdlg 228402315e8Sdlg case KSTAT_S_INSTALLED: 229402315e8Sdlg ksreq->ks_dataver = ks->ks_dataver; 230402315e8Sdlg ksreq->ks_interval = ks->ks_interval; 231402315e8Sdlg 232402315e8Sdlg if (ksreq->ks_data == NULL) { 233402315e8Sdlg /* userland doesn't want actual data, so shortcut */ 234402315e8Sdlg kstat_enter(ks); 235402315e8Sdlg ksreq->ks_datalen = ks->ks_datalen; 236402315e8Sdlg ksreq->ks_updated = ks->ks_updated; 237402315e8Sdlg kstat_leave(ks); 238402315e8Sdlg break; 239402315e8Sdlg } 240402315e8Sdlg 241402315e8Sdlg klen = ks->ks_datalen; /* KSTAT_F_REALLOC */ 242402315e8Sdlg buf = malloc(klen, M_TEMP, M_WAITOK|M_CANFAIL); 243402315e8Sdlg if (buf == NULL) { 244402315e8Sdlg error = ENOMEM; 245402315e8Sdlg goto error; 246402315e8Sdlg } 247402315e8Sdlg 248402315e8Sdlg kstat_enter(ks); 249402315e8Sdlg error = (*ks->ks_read)(ks); 250402315e8Sdlg if (error == 0) { 251402315e8Sdlg updated = ks->ks_updated; 252402315e8Sdlg 253402315e8Sdlg /* KSTAT_F_REALLOC */ 254402315e8Sdlg KASSERTMSG(ks->ks_datalen == klen, 2559593dc34Smglocker "kstat doesn't support resized data yet"); 256402315e8Sdlg 257402315e8Sdlg error = (*ks->ks_copy)(ks, buf); 258402315e8Sdlg } 259402315e8Sdlg kstat_leave(ks); 260402315e8Sdlg 261402315e8Sdlg if (error != 0) 262402315e8Sdlg goto error; 263402315e8Sdlg 264402315e8Sdlg ulen = ksreq->ks_datalen; 265402315e8Sdlg ksreq->ks_datalen = klen; /* KSTAT_F_REALLOC */ 266402315e8Sdlg ksreq->ks_updated = updated; 267402315e8Sdlg break; 268402315e8Sdlg default: 269402315e8Sdlg panic("ks %p unexpected state %u", ks, ks->ks_state); 270402315e8Sdlg } 271402315e8Sdlg 272402315e8Sdlg ksreq->ks_version = kstat_version; 273402315e8Sdlg ksreq->ks_id = ks->ks_id; 274402315e8Sdlg 275402315e8Sdlg if (strlcpy(ksreq->ks_provider, ks->ks_provider, 276402315e8Sdlg sizeof(ksreq->ks_provider)) >= sizeof(ksreq->ks_provider)) 277402315e8Sdlg panic("kstat %p provider string has grown", ks); 278402315e8Sdlg ksreq->ks_instance = ks->ks_instance; 279402315e8Sdlg if (strlcpy(ksreq->ks_name, ks->ks_name, 280402315e8Sdlg sizeof(ksreq->ks_name)) >= sizeof(ksreq->ks_name)) 281402315e8Sdlg panic("kstat %p name string has grown", ks); 282402315e8Sdlg ksreq->ks_unit = ks->ks_unit; 283402315e8Sdlg 284402315e8Sdlg ksreq->ks_created = ks->ks_created; 285402315e8Sdlg ksreq->ks_type = ks->ks_type; 286402315e8Sdlg ksreq->ks_state = ks->ks_state; 287402315e8Sdlg 288402315e8Sdlg error: 289402315e8Sdlg rw_exit(&kstat_lock); 290402315e8Sdlg 291402315e8Sdlg if (buf != NULL) { 292402315e8Sdlg if (error == 0) 293402315e8Sdlg error = copyout(buf, ksreq->ks_data, min(klen, ulen)); 294402315e8Sdlg 295402315e8Sdlg free(buf, M_TEMP, klen); 296402315e8Sdlg } 297402315e8Sdlg 298402315e8Sdlg return (error); 299402315e8Sdlg } 300402315e8Sdlg 301402315e8Sdlg int 302402315e8Sdlg kstatioc_find_id(struct kstat_req *ksreq) 303402315e8Sdlg { 304402315e8Sdlg struct kstat *ks, key; 305402315e8Sdlg int error; 306402315e8Sdlg 307402315e8Sdlg error = kstatioc_enter(ksreq); 308402315e8Sdlg if (error != 0) 309402315e8Sdlg return (error); 310402315e8Sdlg 311402315e8Sdlg key.ks_id = ksreq->ks_id; 312402315e8Sdlg 313402315e8Sdlg ks = RBT_FIND(kstat_id_tree, &kstat_id_tree, &key); 314402315e8Sdlg 315402315e8Sdlg return (kstatioc_leave(ksreq, ks)); 316402315e8Sdlg } 317402315e8Sdlg 318402315e8Sdlg int 319402315e8Sdlg kstatioc_nfind_id(struct kstat_req *ksreq) 320402315e8Sdlg { 321402315e8Sdlg struct kstat *ks, key; 322402315e8Sdlg int error; 323402315e8Sdlg 324402315e8Sdlg error = kstatioc_enter(ksreq); 325402315e8Sdlg if (error != 0) 326402315e8Sdlg return (error); 327402315e8Sdlg 328402315e8Sdlg key.ks_id = ksreq->ks_id; 329402315e8Sdlg 330402315e8Sdlg ks = RBT_NFIND(kstat_id_tree, &kstat_id_tree, &key); 331402315e8Sdlg 332402315e8Sdlg return (kstatioc_leave(ksreq, ks)); 333402315e8Sdlg } 334402315e8Sdlg 335402315e8Sdlg int 336402315e8Sdlg kstatioc_find_pv(struct kstat_req *ksreq) 337402315e8Sdlg { 338402315e8Sdlg struct kstat *ks, key; 339402315e8Sdlg int error; 340402315e8Sdlg 341402315e8Sdlg error = kstatioc_enter(ksreq); 342402315e8Sdlg if (error != 0) 343402315e8Sdlg return (error); 344402315e8Sdlg 345402315e8Sdlg key.ks_provider = ksreq->ks_provider; 346402315e8Sdlg key.ks_instance = ksreq->ks_instance; 347402315e8Sdlg key.ks_name = ksreq->ks_name; 348402315e8Sdlg key.ks_unit = ksreq->ks_unit; 349402315e8Sdlg 350402315e8Sdlg ks = RBT_FIND(kstat_pv_tree, &kstat_pv_tree, &key); 351402315e8Sdlg 352402315e8Sdlg return (kstatioc_leave(ksreq, ks)); 353402315e8Sdlg } 354402315e8Sdlg 355402315e8Sdlg int 356402315e8Sdlg kstatioc_nfind_pv(struct kstat_req *ksreq) 357402315e8Sdlg { 358402315e8Sdlg struct kstat *ks, key; 359402315e8Sdlg int error; 360402315e8Sdlg 361402315e8Sdlg error = kstatioc_enter(ksreq); 362402315e8Sdlg if (error != 0) 363402315e8Sdlg return (error); 364402315e8Sdlg 365402315e8Sdlg key.ks_provider = ksreq->ks_provider; 366402315e8Sdlg key.ks_instance = ksreq->ks_instance; 367402315e8Sdlg key.ks_name = ksreq->ks_name; 368402315e8Sdlg key.ks_unit = ksreq->ks_unit; 369402315e8Sdlg 370402315e8Sdlg ks = RBT_NFIND(kstat_pv_tree, &kstat_pv_tree, &key); 371402315e8Sdlg 372402315e8Sdlg return (kstatioc_leave(ksreq, ks)); 373402315e8Sdlg } 374402315e8Sdlg 375402315e8Sdlg int 376402315e8Sdlg kstatioc_find_nm(struct kstat_req *ksreq) 377402315e8Sdlg { 378402315e8Sdlg struct kstat *ks, key; 379402315e8Sdlg int error; 380402315e8Sdlg 381402315e8Sdlg error = kstatioc_enter(ksreq); 382402315e8Sdlg if (error != 0) 383402315e8Sdlg return (error); 384402315e8Sdlg 385402315e8Sdlg key.ks_name = ksreq->ks_name; 386402315e8Sdlg key.ks_unit = ksreq->ks_unit; 387402315e8Sdlg key.ks_provider = ksreq->ks_provider; 388402315e8Sdlg key.ks_instance = ksreq->ks_instance; 389402315e8Sdlg 390402315e8Sdlg ks = RBT_FIND(kstat_nm_tree, &kstat_nm_tree, &key); 391402315e8Sdlg 392402315e8Sdlg return (kstatioc_leave(ksreq, ks)); 393402315e8Sdlg } 394402315e8Sdlg 395402315e8Sdlg int 396402315e8Sdlg kstatioc_nfind_nm(struct kstat_req *ksreq) 397402315e8Sdlg { 398402315e8Sdlg struct kstat *ks, key; 399402315e8Sdlg int error; 400402315e8Sdlg 401402315e8Sdlg error = kstatioc_enter(ksreq); 402402315e8Sdlg if (error != 0) 403402315e8Sdlg return (error); 404402315e8Sdlg 405402315e8Sdlg key.ks_name = ksreq->ks_name; 406402315e8Sdlg key.ks_unit = ksreq->ks_unit; 407402315e8Sdlg key.ks_provider = ksreq->ks_provider; 408402315e8Sdlg key.ks_instance = ksreq->ks_instance; 409402315e8Sdlg 410402315e8Sdlg ks = RBT_NFIND(kstat_nm_tree, &kstat_nm_tree, &key); 411402315e8Sdlg 412402315e8Sdlg return (kstatioc_leave(ksreq, ks)); 413402315e8Sdlg } 414402315e8Sdlg 415402315e8Sdlg int 416402315e8Sdlg kstatioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 417402315e8Sdlg { 418402315e8Sdlg struct kstat_req *ksreq = (struct kstat_req *)data; 419402315e8Sdlg int error = 0; 420402315e8Sdlg 421402315e8Sdlg KERNEL_UNLOCK(); 422402315e8Sdlg 423402315e8Sdlg switch (cmd) { 424402315e8Sdlg case KSTATIOC_VERSION: 425402315e8Sdlg *(unsigned int *)data = kstat_version; 426402315e8Sdlg break; 427402315e8Sdlg 428402315e8Sdlg case KSTATIOC_FIND_ID: 429402315e8Sdlg error = kstatioc_find_id(ksreq); 430402315e8Sdlg break; 431402315e8Sdlg case KSTATIOC_NFIND_ID: 432402315e8Sdlg error = kstatioc_nfind_id(ksreq); 433402315e8Sdlg break; 434402315e8Sdlg case KSTATIOC_FIND_PROVIDER: 435402315e8Sdlg error = kstatioc_find_pv(ksreq); 436402315e8Sdlg break; 437402315e8Sdlg case KSTATIOC_NFIND_PROVIDER: 438402315e8Sdlg error = kstatioc_nfind_pv(ksreq); 439402315e8Sdlg break; 440402315e8Sdlg case KSTATIOC_FIND_NAME: 441402315e8Sdlg error = kstatioc_find_nm(ksreq); 442402315e8Sdlg break; 443402315e8Sdlg case KSTATIOC_NFIND_NAME: 444402315e8Sdlg error = kstatioc_nfind_nm(ksreq); 445402315e8Sdlg break; 446402315e8Sdlg 447402315e8Sdlg default: 448402315e8Sdlg error = ENOTTY; 449402315e8Sdlg break; 450402315e8Sdlg } 451402315e8Sdlg 452402315e8Sdlg KERNEL_LOCK(); 453402315e8Sdlg 454402315e8Sdlg return (error); 455402315e8Sdlg } 456402315e8Sdlg 457402315e8Sdlg void 458402315e8Sdlg kstat_init(void) 459402315e8Sdlg { 460402315e8Sdlg static int initialized = 0; 461402315e8Sdlg 462402315e8Sdlg if (initialized) 463402315e8Sdlg return; 464402315e8Sdlg 465402315e8Sdlg pool_init(&kstat_pool, sizeof(struct kstat), 0, IPL_NONE, 466402315e8Sdlg PR_WAITOK | PR_RWLOCK, "kstatmem", NULL); 467402315e8Sdlg 468402315e8Sdlg initialized = 1; 469402315e8Sdlg } 470402315e8Sdlg 471402315e8Sdlg int 472402315e8Sdlg kstat_strcheck(const char *str) 473402315e8Sdlg { 474402315e8Sdlg size_t i, l; 475402315e8Sdlg 476402315e8Sdlg l = strlen(str); 477402315e8Sdlg if (l == 0 || l >= KSTAT_STRLEN) 478402315e8Sdlg return (-1); 479402315e8Sdlg for (i = 0; i < l; i++) { 480402315e8Sdlg int ch = str[i]; 481402315e8Sdlg if (ch >= 'a' && ch <= 'z') 482402315e8Sdlg continue; 483402315e8Sdlg if (ch >= 'A' && ch <= 'Z') 484402315e8Sdlg continue; 485402315e8Sdlg if (ch >= '0' && ch <= '9') 486402315e8Sdlg continue; 487402315e8Sdlg switch (ch) { 488402315e8Sdlg case '-': 489402315e8Sdlg case '_': 490402315e8Sdlg case '.': 491402315e8Sdlg break; 492402315e8Sdlg default: 493402315e8Sdlg return (-1); 494402315e8Sdlg } 495402315e8Sdlg } 496402315e8Sdlg 497402315e8Sdlg return (0); 498402315e8Sdlg } 499402315e8Sdlg 500402315e8Sdlg struct kstat * 501402315e8Sdlg kstat_create(const char *provider, unsigned int instance, 502402315e8Sdlg const char *name, unsigned int unit, 503402315e8Sdlg unsigned int type, unsigned int flags) 504402315e8Sdlg { 505402315e8Sdlg struct kstat *ks, *oks; 506402315e8Sdlg 507402315e8Sdlg if (kstat_strcheck(provider) == -1) 508402315e8Sdlg panic("invalid provider string"); 509402315e8Sdlg if (kstat_strcheck(name) == -1) 510402315e8Sdlg panic("invalid name string"); 511402315e8Sdlg 512402315e8Sdlg kstat_init(); 513402315e8Sdlg 514402315e8Sdlg ks = pool_get(&kstat_pool, PR_WAITOK|PR_ZERO); 515402315e8Sdlg 516402315e8Sdlg ks->ks_provider = provider; 517402315e8Sdlg ks->ks_instance = instance; 518402315e8Sdlg ks->ks_name = name; 519402315e8Sdlg ks->ks_unit = unit; 520402315e8Sdlg ks->ks_flags = flags; 521402315e8Sdlg ks->ks_type = type; 522402315e8Sdlg ks->ks_state = KSTAT_S_CREATED; 523402315e8Sdlg 524402315e8Sdlg getnanouptime(&ks->ks_created); 525402315e8Sdlg ks->ks_updated = ks->ks_created; 526402315e8Sdlg 527402315e8Sdlg ks->ks_lock = &kstat_default_lock; 528402315e8Sdlg ks->ks_lock_ops = &kstat_wlock_ops; 529402315e8Sdlg ks->ks_read = kstat_read; 530402315e8Sdlg ks->ks_copy = kstat_copy; 531402315e8Sdlg 532402315e8Sdlg rw_enter_write(&kstat_lock); 533402315e8Sdlg ks->ks_id = kstat_next_id; 534402315e8Sdlg 535402315e8Sdlg oks = RBT_INSERT(kstat_pv_tree, &kstat_pv_tree, ks); 536402315e8Sdlg if (oks == NULL) { 537402315e8Sdlg /* commit */ 538402315e8Sdlg kstat_next_id++; 539402315e8Sdlg kstat_version++; 540402315e8Sdlg 541402315e8Sdlg oks = RBT_INSERT(kstat_nm_tree, &kstat_nm_tree, ks); 542402315e8Sdlg if (oks != NULL) 543402315e8Sdlg panic("kstat name collision! (%llu)", ks->ks_id); 544402315e8Sdlg 545402315e8Sdlg oks = RBT_INSERT(kstat_id_tree, &kstat_id_tree, ks); 546402315e8Sdlg if (oks != NULL) 547402315e8Sdlg panic("kstat id collision! (%llu)", ks->ks_id); 548402315e8Sdlg } 549402315e8Sdlg rw_exit_write(&kstat_lock); 550402315e8Sdlg 551402315e8Sdlg if (oks != NULL) { 552402315e8Sdlg pool_put(&kstat_pool, ks); 553402315e8Sdlg return (NULL); 554402315e8Sdlg } 555402315e8Sdlg 556402315e8Sdlg return (ks); 557402315e8Sdlg } 558402315e8Sdlg 559402315e8Sdlg void 560402315e8Sdlg kstat_set_rlock(struct kstat *ks, struct rwlock *rwl) 561402315e8Sdlg { 562402315e8Sdlg KASSERT(ks->ks_state == KSTAT_S_CREATED); 563402315e8Sdlg 564402315e8Sdlg ks->ks_lock = rwl; 565402315e8Sdlg ks->ks_lock_ops = &kstat_rlock_ops; 566402315e8Sdlg } 567402315e8Sdlg 568402315e8Sdlg void 569402315e8Sdlg kstat_set_wlock(struct kstat *ks, struct rwlock *rwl) 570402315e8Sdlg { 571402315e8Sdlg KASSERT(ks->ks_state == KSTAT_S_CREATED); 572402315e8Sdlg 573402315e8Sdlg ks->ks_lock = rwl; 574402315e8Sdlg ks->ks_lock_ops = &kstat_wlock_ops; 575402315e8Sdlg } 576402315e8Sdlg 577402315e8Sdlg void 578402315e8Sdlg kstat_set_mutex(struct kstat *ks, struct mutex *mtx) 579402315e8Sdlg { 580402315e8Sdlg KASSERT(ks->ks_state == KSTAT_S_CREATED); 581402315e8Sdlg 582402315e8Sdlg ks->ks_lock = mtx; 583402315e8Sdlg ks->ks_lock_ops = &kstat_mutex_ops; 584402315e8Sdlg } 585402315e8Sdlg 586402315e8Sdlg void 587402315e8Sdlg kstat_cpu_enter(void *p) 588402315e8Sdlg { 589402315e8Sdlg struct cpu_info *ci = p; 590402315e8Sdlg sched_peg_curproc(ci); 591402315e8Sdlg } 592402315e8Sdlg 593402315e8Sdlg void 594402315e8Sdlg kstat_cpu_leave(void *p) 595402315e8Sdlg { 596cf31dfdeSmpi sched_unpeg_curproc(); 597402315e8Sdlg } 598402315e8Sdlg 599402315e8Sdlg void 600402315e8Sdlg kstat_set_cpu(struct kstat *ks, struct cpu_info *ci) 601402315e8Sdlg { 602402315e8Sdlg KASSERT(ks->ks_state == KSTAT_S_CREATED); 603402315e8Sdlg 604402315e8Sdlg ks->ks_lock = ci; 605402315e8Sdlg ks->ks_lock_ops = &kstat_cpu_ops; 606402315e8Sdlg } 607402315e8Sdlg 608402315e8Sdlg int 609402315e8Sdlg kstat_read_nop(struct kstat *ks) 610402315e8Sdlg { 611402315e8Sdlg return (0); 612402315e8Sdlg } 613402315e8Sdlg 614402315e8Sdlg void 615402315e8Sdlg kstat_install(struct kstat *ks) 616402315e8Sdlg { 617402315e8Sdlg if (!ISSET(ks->ks_flags, KSTAT_F_REALLOC)) { 618402315e8Sdlg KASSERTMSG(ks->ks_copy != NULL || ks->ks_data != NULL, 619402315e8Sdlg "kstat %p %s:%u:%s:%u must provide ks_copy or ks_data", ks, 620402315e8Sdlg ks->ks_provider, ks->ks_instance, ks->ks_name, ks->ks_unit); 621402315e8Sdlg KASSERT(ks->ks_datalen > 0); 622402315e8Sdlg } 623402315e8Sdlg 624402315e8Sdlg rw_enter_write(&kstat_lock); 625402315e8Sdlg ks->ks_state = KSTAT_S_INSTALLED; 626402315e8Sdlg rw_exit_write(&kstat_lock); 627402315e8Sdlg } 628402315e8Sdlg 629402315e8Sdlg void 630a94953c6Sdlg kstat_remove(struct kstat *ks) 631a94953c6Sdlg { 632a94953c6Sdlg rw_enter_write(&kstat_lock); 633a94953c6Sdlg KASSERTMSG(ks->ks_state == KSTAT_S_INSTALLED, 634a94953c6Sdlg "kstat %p %s:%u:%s:%u is not installed", ks, 635a94953c6Sdlg ks->ks_provider, ks->ks_instance, ks->ks_name, ks->ks_unit); 636a94953c6Sdlg 637a94953c6Sdlg ks->ks_state = KSTAT_S_CREATED; 638a94953c6Sdlg rw_exit_write(&kstat_lock); 639a94953c6Sdlg } 640a94953c6Sdlg 641a94953c6Sdlg void 642402315e8Sdlg kstat_destroy(struct kstat *ks) 643402315e8Sdlg { 644402315e8Sdlg rw_enter_write(&kstat_lock); 645402315e8Sdlg RBT_REMOVE(kstat_id_tree, &kstat_id_tree, ks); 646402315e8Sdlg RBT_REMOVE(kstat_pv_tree, &kstat_pv_tree, ks); 647402315e8Sdlg RBT_REMOVE(kstat_nm_tree, &kstat_nm_tree, ks); 648402315e8Sdlg kstat_version++; 649402315e8Sdlg rw_exit_write(&kstat_lock); 650402315e8Sdlg 651402315e8Sdlg pool_put(&kstat_pool, ks); 652402315e8Sdlg } 653402315e8Sdlg 654402315e8Sdlg int 655402315e8Sdlg kstat_read(struct kstat *ks) 656402315e8Sdlg { 657402315e8Sdlg getnanouptime(&ks->ks_updated); 658402315e8Sdlg return (0); 659402315e8Sdlg } 660402315e8Sdlg 661402315e8Sdlg int 662402315e8Sdlg kstat_copy(struct kstat *ks, void *buf) 663402315e8Sdlg { 664402315e8Sdlg memcpy(buf, ks->ks_data, ks->ks_datalen); 665402315e8Sdlg return (0); 666402315e8Sdlg } 667402315e8Sdlg 668402315e8Sdlg RBT_GENERATE(kstat_id_tree, kstat, ks_id_entry, kstat_id_cmp); 669402315e8Sdlg RBT_GENERATE(kstat_pv_tree, kstat, ks_pv_entry, kstat_pv_cmp); 670402315e8Sdlg RBT_GENERATE(kstat_nm_tree, kstat, ks_nm_entry, kstat_nm_cmp); 671402315e8Sdlg 672402315e8Sdlg void 673402315e8Sdlg kstat_kv_init(struct kstat_kv *kv, const char *name, enum kstat_kv_type type) 674402315e8Sdlg { 675402315e8Sdlg memset(kv, 0, sizeof(*kv)); 676402315e8Sdlg strlcpy(kv->kv_key, name, sizeof(kv->kv_key)); /* XXX truncated? */ 677402315e8Sdlg kv->kv_type = type; 678402315e8Sdlg kv->kv_unit = KSTAT_KV_U_NONE; 679402315e8Sdlg } 680402315e8Sdlg 681402315e8Sdlg void 682402315e8Sdlg kstat_kv_unit_init(struct kstat_kv *kv, const char *name, 683402315e8Sdlg enum kstat_kv_type type, enum kstat_kv_unit unit) 684402315e8Sdlg { 685402315e8Sdlg switch (type) { 686402315e8Sdlg case KSTAT_KV_T_COUNTER64: 687402315e8Sdlg case KSTAT_KV_T_COUNTER32: 688*e6b4f1cdSmglocker case KSTAT_KV_T_COUNTER16: 689402315e8Sdlg case KSTAT_KV_T_UINT64: 690402315e8Sdlg case KSTAT_KV_T_INT64: 691402315e8Sdlg case KSTAT_KV_T_UINT32: 692402315e8Sdlg case KSTAT_KV_T_INT32: 693*e6b4f1cdSmglocker case KSTAT_KV_T_UINT16: 694*e6b4f1cdSmglocker case KSTAT_KV_T_INT16: 695402315e8Sdlg break; 696402315e8Sdlg default: 697402315e8Sdlg panic("kv unit init %s: unit for non-integer type", name); 698402315e8Sdlg } 699402315e8Sdlg 700402315e8Sdlg memset(kv, 0, sizeof(*kv)); 701402315e8Sdlg strlcpy(kv->kv_key, name, sizeof(kv->kv_key)); /* XXX truncated? */ 702402315e8Sdlg kv->kv_type = type; 703402315e8Sdlg kv->kv_unit = unit; 704402315e8Sdlg } 705