1 /*
2  * Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * Links to Illumos.org for more information on kstat function:
27  * [1] https://illumos.org/man/1M/kstat
28  * [2] https://illumos.org/man/9f/kstat_create
29  */
30 
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33 
34 #include <sys/types.h>
35 #include <sys/param.h>
36 #include <sys/kernel.h>
37 #include <sys/systm.h>
38 #include <sys/malloc.h>
39 #include <sys/sysctl.h>
40 #include <sys/kstat.h>
41 #include <sys/sbuf.h>
42 #include <sys/zone.h>
43 
44 static MALLOC_DEFINE(M_KSTAT, "kstat_data", "Kernel statistics");
45 
46 SYSCTL_ROOT_NODE(OID_AUTO, kstat, CTLFLAG_RW, 0, "Kernel statistics");
47 
48 void
49 __kstat_set_raw_ops(kstat_t *ksp,
50     int (*headers)(char *buf, size_t size),
51     int (*data)(char *buf, size_t size, void *data),
52     void *(*addr)(kstat_t *ksp, loff_t index))
53 {
54 	ksp->ks_raw_ops.headers = headers;
55 	ksp->ks_raw_ops.data    = data;
56 	ksp->ks_raw_ops.addr    = addr;
57 }
58 
59 void
60 __kstat_set_seq_raw_ops(kstat_t *ksp,
61     int (*headers)(struct seq_file *f),
62     int (*data)(char *buf, size_t size, void *data),
63     void *(*addr)(kstat_t *ksp, loff_t index))
64 {
65 	ksp->ks_raw_ops.seq_headers = headers;
66 	ksp->ks_raw_ops.data    = data;
67 	ksp->ks_raw_ops.addr    = addr;
68 }
69 
70 static int
71 kstat_default_update(kstat_t *ksp, int rw)
72 {
73 	ASSERT3P(ksp, !=, NULL);
74 
75 	if (rw == KSTAT_WRITE)
76 		return (EACCES);
77 
78 	return (0);
79 }
80 
81 static int
82 kstat_resize_raw(kstat_t *ksp)
83 {
84 	if (ksp->ks_raw_bufsize == KSTAT_RAW_MAX)
85 		return (ENOMEM);
86 
87 	free(ksp->ks_raw_buf, M_TEMP);
88 	ksp->ks_raw_bufsize = MIN(ksp->ks_raw_bufsize * 2, KSTAT_RAW_MAX);
89 	ksp->ks_raw_buf = malloc(ksp->ks_raw_bufsize, M_TEMP, M_WAITOK);
90 
91 	return (0);
92 }
93 
94 static void *
95 kstat_raw_default_addr(kstat_t *ksp, loff_t n)
96 {
97 	if (n == 0)
98 		return (ksp->ks_data);
99 	return (NULL);
100 }
101 
102 static int
103 kstat_sysctl(SYSCTL_HANDLER_ARGS)
104 {
105 	kstat_t *ksp = arg1;
106 	kstat_named_t *ksent;
107 	uint64_t val;
108 
109 	ksent = ksp->ks_data;
110 	/* Select the correct element */
111 	ksent += arg2;
112 	/* Update the aggsums before reading */
113 	(void) ksp->ks_update(ksp, KSTAT_READ);
114 	val = ksent->value.ui64;
115 
116 	return (sysctl_handle_64(oidp, &val, 0, req));
117 }
118 
119 static int
120 kstat_sysctl_string(SYSCTL_HANDLER_ARGS)
121 {
122 	kstat_t *ksp = arg1;
123 	kstat_named_t *ksent = ksp->ks_data;
124 	char *val;
125 	uint32_t len = 0;
126 
127 	/* Select the correct element */
128 	ksent += arg2;
129 	/* Update the aggsums before reading */
130 	(void) ksp->ks_update(ksp, KSTAT_READ);
131 	val = KSTAT_NAMED_STR_PTR(ksent);
132 	len = KSTAT_NAMED_STR_BUFLEN(ksent);
133 	val[len-1] = '\0';
134 
135 	return (sysctl_handle_string(oidp, val, len, req));
136 }
137 
138 static int
139 kstat_sysctl_dataset(SYSCTL_HANDLER_ARGS)
140 {
141 	kstat_t *ksp = arg1;
142 	kstat_named_t *ksent;
143 	kstat_named_t *ksent_ds;
144 	uint64_t val;
145 	char *ds_name;
146 	uint32_t ds_len = 0;
147 
148 	ksent_ds = ksent = ksp->ks_data;
149 	ds_name = KSTAT_NAMED_STR_PTR(ksent_ds);
150 	ds_len = KSTAT_NAMED_STR_BUFLEN(ksent_ds);
151 	ds_name[ds_len-1] = '\0';
152 
153 	if (!zone_dataset_visible(ds_name, NULL)) {
154 		return (EPERM);
155 	}
156 
157 	/* Select the correct element */
158 	ksent += arg2;
159 	/* Update the aggsums before reading */
160 	(void) ksp->ks_update(ksp, KSTAT_READ);
161 	val = ksent->value.ui64;
162 
163 	return (sysctl_handle_64(oidp, &val, 0, req));
164 }
165 
166 static int
167 kstat_sysctl_dataset_string(SYSCTL_HANDLER_ARGS)
168 {
169 	kstat_t *ksp = arg1;
170 	kstat_named_t *ksent = ksp->ks_data;
171 	char *val;
172 	uint32_t len = 0;
173 
174 	/* Select the correct element */
175 	ksent += arg2;
176 	val = KSTAT_NAMED_STR_PTR(ksent);
177 	len = KSTAT_NAMED_STR_BUFLEN(ksent);
178 	val[len-1] = '\0';
179 
180 	if (!zone_dataset_visible(val, NULL)) {
181 		return (EPERM);
182 	}
183 
184 	return (sysctl_handle_string(oidp, val, len, req));
185 }
186 
187 static int
188 kstat_sysctl_io(SYSCTL_HANDLER_ARGS)
189 {
190 	struct sbuf *sb;
191 	kstat_t *ksp = arg1;
192 	kstat_io_t *kip = ksp->ks_data;
193 	int rc;
194 
195 	sb = sbuf_new_auto();
196 	if (sb == NULL)
197 		return (ENOMEM);
198 	/* Update the aggsums before reading */
199 	(void) ksp->ks_update(ksp, KSTAT_READ);
200 
201 	/* though wlentime & friends are signed, they will never be negative */
202 	sbuf_printf(sb,
203 	    "%-8llu %-8llu %-8u %-8u %-8llu %-8llu "
204 	    "%-8llu %-8llu %-8llu %-8llu %-8u %-8u\n",
205 	    kip->nread, kip->nwritten,
206 	    kip->reads, kip->writes,
207 	    kip->wtime, kip->wlentime, kip->wlastupdate,
208 	    kip->rtime, kip->rlentime, kip->rlastupdate,
209 	    kip->wcnt,  kip->rcnt);
210 	rc = sbuf_finish(sb);
211 	if (rc == 0)
212 		rc = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb));
213 	sbuf_delete(sb);
214 	return (rc);
215 }
216 
217 static int
218 kstat_sysctl_raw(SYSCTL_HANDLER_ARGS)
219 {
220 	struct sbuf *sb;
221 	void *data;
222 	kstat_t *ksp = arg1;
223 	void *(*addr_op)(kstat_t *ksp, loff_t index);
224 	int n, has_header, rc = 0;
225 
226 	sb = sbuf_new_auto();
227 	if (sb == NULL)
228 		return (ENOMEM);
229 
230 	if (ksp->ks_raw_ops.addr)
231 		addr_op = ksp->ks_raw_ops.addr;
232 	else
233 		addr_op = kstat_raw_default_addr;
234 
235 	mutex_enter(ksp->ks_lock);
236 
237 	/* Update the aggsums before reading */
238 	(void) ksp->ks_update(ksp, KSTAT_READ);
239 
240 	ksp->ks_raw_bufsize = PAGE_SIZE;
241 	ksp->ks_raw_buf = malloc(PAGE_SIZE, M_TEMP, M_WAITOK);
242 
243 	n = 0;
244 	has_header = (ksp->ks_raw_ops.headers ||
245 	    ksp->ks_raw_ops.seq_headers);
246 
247 restart_headers:
248 	if (ksp->ks_raw_ops.headers) {
249 		rc = ksp->ks_raw_ops.headers(
250 		    ksp->ks_raw_buf, ksp->ks_raw_bufsize);
251 	} else if (ksp->ks_raw_ops.seq_headers) {
252 		struct seq_file f;
253 
254 		f.sf_buf = ksp->ks_raw_buf;
255 		f.sf_size = ksp->ks_raw_bufsize;
256 		rc = ksp->ks_raw_ops.seq_headers(&f);
257 	}
258 	if (has_header) {
259 		if (rc == ENOMEM && !kstat_resize_raw(ksp))
260 			goto restart_headers;
261 		if (rc == 0)
262 			sbuf_printf(sb, "\n%s", ksp->ks_raw_buf);
263 	}
264 
265 	while ((data = addr_op(ksp, n)) != NULL) {
266 restart:
267 		if (ksp->ks_raw_ops.data) {
268 			rc = ksp->ks_raw_ops.data(ksp->ks_raw_buf,
269 			    ksp->ks_raw_bufsize, data);
270 			if (rc == ENOMEM && !kstat_resize_raw(ksp))
271 				goto restart;
272 			if (rc == 0)
273 				sbuf_printf(sb, "%s", ksp->ks_raw_buf);
274 
275 		} else {
276 			ASSERT3U(ksp->ks_ndata, ==, 1);
277 			sbuf_hexdump(sb, ksp->ks_data,
278 			    ksp->ks_data_size, NULL, 0);
279 		}
280 		n++;
281 	}
282 	free(ksp->ks_raw_buf, M_TEMP);
283 	mutex_exit(ksp->ks_lock);
284 	sbuf_trim(sb);
285 	rc = sbuf_finish(sb);
286 	if (rc == 0)
287 		rc = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb));
288 	sbuf_delete(sb);
289 	return (rc);
290 }
291 
292 kstat_t *
293 __kstat_create(const char *module, int instance, const char *name,
294     const char *class, uchar_t ks_type, uint_t ks_ndata, uchar_t flags)
295 {
296 	char buf[KSTAT_STRLEN];
297 	struct sysctl_oid *root;
298 	kstat_t *ksp;
299 	char *pool;
300 
301 	KASSERT(instance == 0, ("instance=%d", instance));
302 	if ((ks_type == KSTAT_TYPE_INTR) || (ks_type == KSTAT_TYPE_IO))
303 		ASSERT3U(ks_ndata, ==, 1);
304 
305 	if (class == NULL)
306 		class = "misc";
307 
308 	/*
309 	 * Allocate the main structure. We don't need to keep a copy of
310 	 * module in here, because it is only used for sysctl node creation
311 	 * done in this function.
312 	 */
313 	ksp = malloc(sizeof (*ksp), M_KSTAT, M_WAITOK|M_ZERO);
314 
315 	ksp->ks_crtime = gethrtime();
316 	ksp->ks_snaptime = ksp->ks_crtime;
317 	ksp->ks_instance = instance;
318 	(void) strlcpy(ksp->ks_name, name, KSTAT_STRLEN);
319 	(void) strlcpy(ksp->ks_class, class, KSTAT_STRLEN);
320 	ksp->ks_type = ks_type;
321 	ksp->ks_flags = flags;
322 	ksp->ks_update = kstat_default_update;
323 
324 	mutex_init(&ksp->ks_private_lock, NULL, MUTEX_DEFAULT, NULL);
325 	ksp->ks_lock = &ksp->ks_private_lock;
326 
327 	switch (ksp->ks_type) {
328 	case KSTAT_TYPE_RAW:
329 		ksp->ks_ndata = 1;
330 		ksp->ks_data_size = ks_ndata;
331 		break;
332 	case KSTAT_TYPE_NAMED:
333 		ksp->ks_ndata = ks_ndata;
334 		ksp->ks_data_size = ks_ndata * sizeof (kstat_named_t);
335 		break;
336 	case KSTAT_TYPE_INTR:
337 		ksp->ks_ndata = ks_ndata;
338 		ksp->ks_data_size = ks_ndata * sizeof (kstat_intr_t);
339 		break;
340 	case KSTAT_TYPE_IO:
341 		ksp->ks_ndata = ks_ndata;
342 		ksp->ks_data_size = ks_ndata * sizeof (kstat_io_t);
343 		break;
344 	case KSTAT_TYPE_TIMER:
345 		ksp->ks_ndata = ks_ndata;
346 		ksp->ks_data_size = ks_ndata * sizeof (kstat_timer_t);
347 		break;
348 	default:
349 		panic("Undefined kstat type %d\n", ksp->ks_type);
350 	}
351 
352 	if (ksp->ks_flags & KSTAT_FLAG_VIRTUAL)
353 		ksp->ks_data = NULL;
354 	else
355 		ksp->ks_data = kmem_zalloc(ksp->ks_data_size, KM_SLEEP);
356 
357 	/*
358 	 * Some kstats use a module name like "zfs/poolname" to distinguish a
359 	 * set of kstats belonging to a specific pool.  Split on '/' to add an
360 	 * extra node for the pool name if needed.
361 	 */
362 	(void) strlcpy(buf, module, KSTAT_STRLEN);
363 	module = buf;
364 	pool = strchr(module, '/');
365 	if (pool != NULL)
366 		*pool++ = '\0';
367 
368 	/*
369 	 * Create sysctl tree for those statistics:
370 	 *
371 	 *	kstat.<module>[.<pool>].<class>.<name>
372 	 */
373 	sysctl_ctx_init(&ksp->ks_sysctl_ctx);
374 	root = SYSCTL_ADD_NODE(&ksp->ks_sysctl_ctx,
375 	    SYSCTL_STATIC_CHILDREN(_kstat), OID_AUTO, module, CTLFLAG_RW, 0,
376 	    "");
377 	if (root == NULL) {
378 		printf("%s: Cannot create kstat.%s tree!\n", __func__, module);
379 		sysctl_ctx_free(&ksp->ks_sysctl_ctx);
380 		free(ksp, M_KSTAT);
381 		return (NULL);
382 	}
383 	if (pool != NULL) {
384 		root = SYSCTL_ADD_NODE(&ksp->ks_sysctl_ctx,
385 		    SYSCTL_CHILDREN(root), OID_AUTO, pool, CTLFLAG_RW, 0, "");
386 		if (root == NULL) {
387 			printf("%s: Cannot create kstat.%s.%s tree!\n",
388 			    __func__, module, pool);
389 			sysctl_ctx_free(&ksp->ks_sysctl_ctx);
390 			free(ksp, M_KSTAT);
391 			return (NULL);
392 		}
393 	}
394 	root = SYSCTL_ADD_NODE(&ksp->ks_sysctl_ctx, SYSCTL_CHILDREN(root),
395 	    OID_AUTO, class, CTLFLAG_RW, 0, "");
396 	if (root == NULL) {
397 		if (pool != NULL)
398 			printf("%s: Cannot create kstat.%s.%s.%s tree!\n",
399 			    __func__, module, pool, class);
400 		else
401 			printf("%s: Cannot create kstat.%s.%s tree!\n",
402 			    __func__, module, class);
403 		sysctl_ctx_free(&ksp->ks_sysctl_ctx);
404 		free(ksp, M_KSTAT);
405 		return (NULL);
406 	}
407 	if (ksp->ks_type == KSTAT_TYPE_NAMED) {
408 		root = SYSCTL_ADD_NODE(&ksp->ks_sysctl_ctx,
409 		    SYSCTL_CHILDREN(root),
410 		    OID_AUTO, name, CTLFLAG_RW, 0, "");
411 		if (root == NULL) {
412 			if (pool != NULL)
413 				printf("%s: Cannot create kstat.%s.%s.%s.%s "
414 				    "tree!\n", __func__, module, pool, class,
415 				    name);
416 			else
417 				printf("%s: Cannot create kstat.%s.%s.%s "
418 				    "tree!\n", __func__, module, class, name);
419 			sysctl_ctx_free(&ksp->ks_sysctl_ctx);
420 			free(ksp, M_KSTAT);
421 			return (NULL);
422 		}
423 
424 	}
425 	ksp->ks_sysctl_root = root;
426 
427 	return (ksp);
428 }
429 
430 static void
431 kstat_install_named(kstat_t *ksp)
432 {
433 	kstat_named_t *ksent;
434 	char *namelast;
435 	int typelast;
436 
437 	ksent = ksp->ks_data;
438 
439 	VERIFY((ksp->ks_flags & KSTAT_FLAG_VIRTUAL) || ksent != NULL);
440 
441 	typelast = 0;
442 	namelast = NULL;
443 
444 	for (int i = 0; i < ksp->ks_ndata; i++, ksent++) {
445 		if (ksent->data_type != 0) {
446 			typelast = ksent->data_type;
447 			namelast = ksent->name;
448 		}
449 		switch (typelast) {
450 		case KSTAT_DATA_CHAR:
451 			/* Not Implemented */
452 			break;
453 		case KSTAT_DATA_INT32:
454 			SYSCTL_ADD_PROC(&ksp->ks_sysctl_ctx,
455 			    SYSCTL_CHILDREN(ksp->ks_sysctl_root),
456 			    OID_AUTO, namelast,
457 			    CTLTYPE_S32 | CTLFLAG_RD | CTLFLAG_MPSAFE,
458 			    ksp, i, kstat_sysctl, "I", namelast);
459 			break;
460 		case KSTAT_DATA_UINT32:
461 			SYSCTL_ADD_PROC(&ksp->ks_sysctl_ctx,
462 			    SYSCTL_CHILDREN(ksp->ks_sysctl_root),
463 			    OID_AUTO, namelast,
464 			    CTLTYPE_U32 | CTLFLAG_RD | CTLFLAG_MPSAFE,
465 			    ksp, i, kstat_sysctl, "IU", namelast);
466 			break;
467 		case KSTAT_DATA_INT64:
468 			SYSCTL_ADD_PROC(&ksp->ks_sysctl_ctx,
469 			    SYSCTL_CHILDREN(ksp->ks_sysctl_root),
470 			    OID_AUTO, namelast,
471 			    CTLTYPE_S64 | CTLFLAG_RD | CTLFLAG_MPSAFE,
472 			    ksp, i, kstat_sysctl, "Q", namelast);
473 			break;
474 		case KSTAT_DATA_UINT64:
475 			if (strcmp(ksp->ks_class, "dataset") == 0) {
476 				SYSCTL_ADD_PROC(&ksp->ks_sysctl_ctx,
477 				    SYSCTL_CHILDREN(ksp->ks_sysctl_root),
478 				    OID_AUTO, namelast,
479 				    CTLTYPE_U64 | CTLFLAG_RD | CTLFLAG_MPSAFE,
480 				    ksp, i, kstat_sysctl_dataset, "QU",
481 				    namelast);
482 			} else {
483 				SYSCTL_ADD_PROC(&ksp->ks_sysctl_ctx,
484 				    SYSCTL_CHILDREN(ksp->ks_sysctl_root),
485 				    OID_AUTO, namelast,
486 				    CTLTYPE_U64 | CTLFLAG_RD | CTLFLAG_MPSAFE,
487 				    ksp, i, kstat_sysctl, "QU", namelast);
488 			}
489 			break;
490 		case KSTAT_DATA_LONG:
491 			SYSCTL_ADD_PROC(&ksp->ks_sysctl_ctx,
492 			    SYSCTL_CHILDREN(ksp->ks_sysctl_root),
493 			    OID_AUTO, namelast,
494 			    CTLTYPE_LONG | CTLFLAG_RD | CTLFLAG_MPSAFE,
495 			    ksp, i, kstat_sysctl, "L", namelast);
496 			break;
497 		case KSTAT_DATA_ULONG:
498 			SYSCTL_ADD_PROC(&ksp->ks_sysctl_ctx,
499 			    SYSCTL_CHILDREN(ksp->ks_sysctl_root),
500 			    OID_AUTO, namelast,
501 			    CTLTYPE_ULONG | CTLFLAG_RD | CTLFLAG_MPSAFE,
502 			    ksp, i, kstat_sysctl, "LU", namelast);
503 			break;
504 		case KSTAT_DATA_STRING:
505 			if (strcmp(ksp->ks_class, "dataset") == 0) {
506 				SYSCTL_ADD_PROC(&ksp->ks_sysctl_ctx,
507 				    SYSCTL_CHILDREN(ksp->ks_sysctl_root),
508 				    OID_AUTO, namelast, CTLTYPE_STRING |
509 				    CTLFLAG_RD | CTLFLAG_MPSAFE,
510 				    ksp, i, kstat_sysctl_dataset_string, "A",
511 				    namelast);
512 			} else {
513 				SYSCTL_ADD_PROC(&ksp->ks_sysctl_ctx,
514 				    SYSCTL_CHILDREN(ksp->ks_sysctl_root),
515 				    OID_AUTO, namelast, CTLTYPE_STRING |
516 				    CTLFLAG_RD | CTLFLAG_MPSAFE,
517 				    ksp, i, kstat_sysctl_string, "A",
518 				    namelast);
519 			}
520 			break;
521 		default:
522 			panic("unsupported type: %d", typelast);
523 		}
524 	}
525 }
526 
527 void
528 kstat_install(kstat_t *ksp)
529 {
530 	struct sysctl_oid *root;
531 
532 	if (ksp->ks_ndata == UINT32_MAX)
533 		VERIFY3U(ksp->ks_type, ==, KSTAT_TYPE_RAW);
534 
535 	switch (ksp->ks_type) {
536 	case KSTAT_TYPE_NAMED:
537 		return (kstat_install_named(ksp));
538 	case KSTAT_TYPE_RAW:
539 		if (ksp->ks_raw_ops.data) {
540 			root = SYSCTL_ADD_PROC(&ksp->ks_sysctl_ctx,
541 			    SYSCTL_CHILDREN(ksp->ks_sysctl_root),
542 			    OID_AUTO, ksp->ks_name, CTLTYPE_STRING | CTLFLAG_RD
543 			    | CTLFLAG_MPSAFE | CTLFLAG_SKIP,
544 			    ksp, 0, kstat_sysctl_raw, "A", ksp->ks_name);
545 		} else {
546 			root = SYSCTL_ADD_PROC(&ksp->ks_sysctl_ctx,
547 			    SYSCTL_CHILDREN(ksp->ks_sysctl_root),
548 			    OID_AUTO, ksp->ks_name, CTLTYPE_OPAQUE | CTLFLAG_RD
549 			    | CTLFLAG_MPSAFE | CTLFLAG_SKIP,
550 			    ksp, 0, kstat_sysctl_raw, "", ksp->ks_name);
551 		}
552 		break;
553 	case KSTAT_TYPE_IO:
554 		root = SYSCTL_ADD_PROC(&ksp->ks_sysctl_ctx,
555 		    SYSCTL_CHILDREN(ksp->ks_sysctl_root),
556 		    OID_AUTO, ksp->ks_name,
557 		    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
558 		    ksp, 0, kstat_sysctl_io, "A", ksp->ks_name);
559 		break;
560 	case KSTAT_TYPE_TIMER:
561 	case KSTAT_TYPE_INTR:
562 	default:
563 		panic("unsupported kstat type %d\n", ksp->ks_type);
564 	}
565 	VERIFY3P(root, !=, NULL);
566 	ksp->ks_sysctl_root = root;
567 }
568 
569 void
570 kstat_delete(kstat_t *ksp)
571 {
572 
573 	sysctl_ctx_free(&ksp->ks_sysctl_ctx);
574 	ksp->ks_lock = NULL;
575 	mutex_destroy(&ksp->ks_private_lock);
576 	if (!(ksp->ks_flags & KSTAT_FLAG_VIRTUAL))
577 		kmem_free(ksp->ks_data, ksp->ks_data_size);
578 	free(ksp, M_KSTAT);
579 }
580