]> git.proxmox.com Git - mirror_spl.git/blob - module/spl/spl-kstat.c
e8917a3ea80c1edf93880c70d025f96e7a647ef8
[mirror_spl.git] / module / spl / spl-kstat.c
1 /*****************************************************************************\
2 * Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
3 * Copyright (C) 2007 The Regents of the University of California.
4 * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
5 * Written by Brian Behlendorf <behlendorf1@llnl.gov>.
6 * UCRL-CODE-235197
7 *
8 * This file is part of the SPL, Solaris Porting Layer.
9 * For details, see <http://zfsonlinux.org/>.
10 *
11 * The SPL is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the
13 * Free Software Foundation; either version 2 of the License, or (at your
14 * option) any later version.
15 *
16 * The SPL is distributed in the hope that it will be useful, but WITHOUT
17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 * for more details.
20 *
21 * You should have received a copy of the GNU General Public License along
22 * with the SPL. If not, see <http://www.gnu.org/licenses/>.
23 *****************************************************************************
24 * Solaris Porting Layer (SPL) Kstat Implementation.
25 \*****************************************************************************/
26
27 #include <linux/seq_file.h>
28 #include <sys/kstat.h>
29 #include <sys/vmem.h>
30
31 #ifndef HAVE_PDE_DATA
32 #define PDE_DATA(x) (PDE(x)->data)
33 #endif
34
35 static kmutex_t kstat_module_lock;
36 static struct list_head kstat_module_list;
37 static kid_t kstat_id;
38
39 static int
40 kstat_resize_raw(kstat_t *ksp)
41 {
42 if (ksp->ks_raw_bufsize == KSTAT_RAW_MAX)
43 return ENOMEM;
44
45 vmem_free(ksp->ks_raw_buf, ksp->ks_raw_bufsize);
46 ksp->ks_raw_bufsize = MIN(ksp->ks_raw_bufsize * 2, KSTAT_RAW_MAX);
47 ksp->ks_raw_buf = vmem_alloc(ksp->ks_raw_bufsize, KM_SLEEP);
48
49 return 0;
50 }
51
52 void
53 kstat_waitq_enter(kstat_io_t *kiop)
54 {
55 hrtime_t new, delta;
56 ulong_t wcnt;
57
58 new = gethrtime();
59 delta = new - kiop->wlastupdate;
60 kiop->wlastupdate = new;
61 wcnt = kiop->wcnt++;
62 if (wcnt != 0) {
63 kiop->wlentime += delta * wcnt;
64 kiop->wtime += delta;
65 }
66 }
67 EXPORT_SYMBOL(kstat_waitq_enter);
68
69 void
70 kstat_waitq_exit(kstat_io_t *kiop)
71 {
72 hrtime_t new, delta;
73 ulong_t wcnt;
74
75 new = gethrtime();
76 delta = new - kiop->wlastupdate;
77 kiop->wlastupdate = new;
78 wcnt = kiop->wcnt--;
79 ASSERT((int)wcnt > 0);
80 kiop->wlentime += delta * wcnt;
81 kiop->wtime += delta;
82 }
83 EXPORT_SYMBOL(kstat_waitq_exit);
84
85 void
86 kstat_runq_enter(kstat_io_t *kiop)
87 {
88 hrtime_t new, delta;
89 ulong_t rcnt;
90
91 new = gethrtime();
92 delta = new - kiop->rlastupdate;
93 kiop->rlastupdate = new;
94 rcnt = kiop->rcnt++;
95 if (rcnt != 0) {
96 kiop->rlentime += delta * rcnt;
97 kiop->rtime += delta;
98 }
99 }
100 EXPORT_SYMBOL(kstat_runq_enter);
101
102 void
103 kstat_runq_exit(kstat_io_t *kiop)
104 {
105 hrtime_t new, delta;
106 ulong_t rcnt;
107
108 new = gethrtime();
109 delta = new - kiop->rlastupdate;
110 kiop->rlastupdate = new;
111 rcnt = kiop->rcnt--;
112 ASSERT((int)rcnt > 0);
113 kiop->rlentime += delta * rcnt;
114 kiop->rtime += delta;
115 }
116 EXPORT_SYMBOL(kstat_runq_exit);
117
118 static int
119 kstat_seq_show_headers(struct seq_file *f)
120 {
121 kstat_t *ksp = (kstat_t *)f->private;
122 int rc = 0;
123
124 ASSERT(ksp->ks_magic == KS_MAGIC);
125
126 seq_printf(f, "%d %d 0x%02x %d %d %lld %lld\n",
127 ksp->ks_kid, ksp->ks_type, ksp->ks_flags,
128 ksp->ks_ndata, (int)ksp->ks_data_size,
129 ksp->ks_crtime, ksp->ks_snaptime);
130
131 switch (ksp->ks_type) {
132 case KSTAT_TYPE_RAW:
133 restart:
134 if (ksp->ks_raw_ops.headers) {
135 rc = ksp->ks_raw_ops.headers(
136 ksp->ks_raw_buf, ksp->ks_raw_bufsize);
137 if (rc == ENOMEM && !kstat_resize_raw(ksp))
138 goto restart;
139 if (!rc)
140 seq_puts(f, ksp->ks_raw_buf);
141 } else {
142 seq_printf(f, "raw data\n");
143 }
144 break;
145 case KSTAT_TYPE_NAMED:
146 seq_printf(f, "%-31s %-4s %s\n",
147 "name", "type", "data");
148 break;
149 case KSTAT_TYPE_INTR:
150 seq_printf(f, "%-8s %-8s %-8s %-8s %-8s\n",
151 "hard", "soft", "watchdog",
152 "spurious", "multsvc");
153 break;
154 case KSTAT_TYPE_IO:
155 seq_printf(f,
156 "%-8s %-8s %-8s %-8s %-8s %-8s "
157 "%-8s %-8s %-8s %-8s %-8s %-8s\n",
158 "nread", "nwritten", "reads", "writes",
159 "wtime", "wlentime", "wupdate",
160 "rtime", "rlentime", "rupdate",
161 "wcnt", "rcnt");
162 break;
163 case KSTAT_TYPE_TIMER:
164 seq_printf(f,
165 "%-31s %-8s "
166 "%-8s %-8s %-8s %-8s %-8s\n",
167 "name", "events", "elapsed",
168 "min", "max", "start", "stop");
169 break;
170 default:
171 PANIC("Undefined kstat type %d\n", ksp->ks_type);
172 }
173
174 return -rc;
175 }
176
177 static int
178 kstat_seq_show_raw(struct seq_file *f, unsigned char *p, int l)
179 {
180 int i, j;
181
182 for (i = 0; ; i++) {
183 seq_printf(f, "%03x:", i);
184
185 for (j = 0; j < 16; j++) {
186 if (i * 16 + j >= l) {
187 seq_printf(f, "\n");
188 goto out;
189 }
190
191 seq_printf(f, " %02x", (unsigned char)p[i * 16 + j]);
192 }
193 seq_printf(f, "\n");
194 }
195 out:
196 return 0;
197 }
198
199 static int
200 kstat_seq_show_named(struct seq_file *f, kstat_named_t *knp)
201 {
202 seq_printf(f, "%-31s %-4d ", knp->name, knp->data_type);
203
204 switch (knp->data_type) {
205 case KSTAT_DATA_CHAR:
206 knp->value.c[15] = '\0'; /* NULL terminate */
207 seq_printf(f, "%-16s", knp->value.c);
208 break;
209 /* XXX - We need to be more careful able what tokens are
210 * used for each arch, for now this is correct for x86_64.
211 */
212 case KSTAT_DATA_INT32:
213 seq_printf(f, "%d", knp->value.i32);
214 break;
215 case KSTAT_DATA_UINT32:
216 seq_printf(f, "%u", knp->value.ui32);
217 break;
218 case KSTAT_DATA_INT64:
219 seq_printf(f, "%lld", (signed long long)knp->value.i64);
220 break;
221 case KSTAT_DATA_UINT64:
222 seq_printf(f, "%llu", (unsigned long long)knp->value.ui64);
223 break;
224 case KSTAT_DATA_LONG:
225 seq_printf(f, "%ld", knp->value.l);
226 break;
227 case KSTAT_DATA_ULONG:
228 seq_printf(f, "%lu", knp->value.ul);
229 break;
230 case KSTAT_DATA_STRING:
231 KSTAT_NAMED_STR_PTR(knp)
232 [KSTAT_NAMED_STR_BUFLEN(knp)-1] = '\0';
233 seq_printf(f, "%s", KSTAT_NAMED_STR_PTR(knp));
234 break;
235 default:
236 PANIC("Undefined kstat data type %d\n", knp->data_type);
237 }
238
239 seq_printf(f, "\n");
240
241 return 0;
242 }
243
244 static int
245 kstat_seq_show_intr(struct seq_file *f, kstat_intr_t *kip)
246 {
247 seq_printf(f, "%-8u %-8u %-8u %-8u %-8u\n",
248 kip->intrs[KSTAT_INTR_HARD],
249 kip->intrs[KSTAT_INTR_SOFT],
250 kip->intrs[KSTAT_INTR_WATCHDOG],
251 kip->intrs[KSTAT_INTR_SPURIOUS],
252 kip->intrs[KSTAT_INTR_MULTSVC]);
253
254 return 0;
255 }
256
257 static int
258 kstat_seq_show_io(struct seq_file *f, kstat_io_t *kip)
259 {
260 seq_printf(f,
261 "%-8llu %-8llu %-8u %-8u %-8lld %-8lld "
262 "%-8lld %-8lld %-8lld %-8lld %-8u %-8u\n",
263 kip->nread, kip->nwritten,
264 kip->reads, kip->writes,
265 kip->wtime, kip->wlentime, kip->wlastupdate,
266 kip->rtime, kip->wlentime, kip->rlastupdate,
267 kip->wcnt, kip->rcnt);
268
269 return 0;
270 }
271
272 static int
273 kstat_seq_show_timer(struct seq_file *f, kstat_timer_t *ktp)
274 {
275 seq_printf(f,
276 "%-31s %-8llu %-8lld %-8lld %-8lld %-8lld %-8lld\n",
277 ktp->name, ktp->num_events, ktp->elapsed_time,
278 ktp->min_time, ktp->max_time,
279 ktp->start_time, ktp->stop_time);
280
281 return 0;
282 }
283
284 static int
285 kstat_seq_show(struct seq_file *f, void *p)
286 {
287 kstat_t *ksp = (kstat_t *)f->private;
288 int rc = 0;
289
290 ASSERT(ksp->ks_magic == KS_MAGIC);
291
292 switch (ksp->ks_type) {
293 case KSTAT_TYPE_RAW:
294 restart:
295 if (ksp->ks_raw_ops.data) {
296 rc = ksp->ks_raw_ops.data(
297 ksp->ks_raw_buf, ksp->ks_raw_bufsize, p);
298 if (rc == ENOMEM && !kstat_resize_raw(ksp))
299 goto restart;
300 if (!rc)
301 seq_puts(f, ksp->ks_raw_buf);
302 } else {
303 ASSERT(ksp->ks_ndata == 1);
304 rc = kstat_seq_show_raw(f, ksp->ks_data,
305 ksp->ks_data_size);
306 }
307 break;
308 case KSTAT_TYPE_NAMED:
309 rc = kstat_seq_show_named(f, (kstat_named_t *)p);
310 break;
311 case KSTAT_TYPE_INTR:
312 rc = kstat_seq_show_intr(f, (kstat_intr_t *)p);
313 break;
314 case KSTAT_TYPE_IO:
315 rc = kstat_seq_show_io(f, (kstat_io_t *)p);
316 break;
317 case KSTAT_TYPE_TIMER:
318 rc = kstat_seq_show_timer(f, (kstat_timer_t *)p);
319 break;
320 default:
321 PANIC("Undefined kstat type %d\n", ksp->ks_type);
322 }
323
324 return -rc;
325 }
326
327 int
328 kstat_default_update(kstat_t *ksp, int rw)
329 {
330 ASSERT(ksp != NULL);
331
332 if (rw == KSTAT_WRITE)
333 return (EACCES);
334
335 return 0;
336 }
337
338 static void *
339 kstat_seq_data_addr(kstat_t *ksp, loff_t n)
340 {
341 void *rc = NULL;
342
343 switch (ksp->ks_type) {
344 case KSTAT_TYPE_RAW:
345 if (ksp->ks_raw_ops.addr)
346 rc = ksp->ks_raw_ops.addr(ksp, n);
347 else
348 rc = ksp->ks_data;
349 break;
350 case KSTAT_TYPE_NAMED:
351 rc = ksp->ks_data + n * sizeof(kstat_named_t);
352 break;
353 case KSTAT_TYPE_INTR:
354 rc = ksp->ks_data + n * sizeof(kstat_intr_t);
355 break;
356 case KSTAT_TYPE_IO:
357 rc = ksp->ks_data + n * sizeof(kstat_io_t);
358 break;
359 case KSTAT_TYPE_TIMER:
360 rc = ksp->ks_data + n * sizeof(kstat_timer_t);
361 break;
362 default:
363 PANIC("Undefined kstat type %d\n", ksp->ks_type);
364 }
365
366 return (rc);
367 }
368
369 static void *
370 kstat_seq_start(struct seq_file *f, loff_t *pos)
371 {
372 loff_t n = *pos;
373 kstat_t *ksp = (kstat_t *)f->private;
374 ASSERT(ksp->ks_magic == KS_MAGIC);
375
376 mutex_enter(ksp->ks_lock);
377
378 if (ksp->ks_type == KSTAT_TYPE_RAW) {
379 ksp->ks_raw_bufsize = PAGE_SIZE;
380 ksp->ks_raw_buf = vmem_alloc(ksp->ks_raw_bufsize, KM_SLEEP);
381 }
382
383 /* Dynamically update kstat, on error existing kstats are used */
384 (void) ksp->ks_update(ksp, KSTAT_READ);
385
386 ksp->ks_snaptime = gethrtime();
387
388 if (!n && kstat_seq_show_headers(f))
389 return (NULL);
390
391 if (n >= ksp->ks_ndata)
392 return (NULL);
393
394 return (kstat_seq_data_addr(ksp, n));
395 }
396
397 static void *
398 kstat_seq_next(struct seq_file *f, void *p, loff_t *pos)
399 {
400 kstat_t *ksp = (kstat_t *)f->private;
401 ASSERT(ksp->ks_magic == KS_MAGIC);
402
403 ++*pos;
404 if (*pos >= ksp->ks_ndata)
405 return (NULL);
406
407 return (kstat_seq_data_addr(ksp, *pos));
408 }
409
410 static void
411 kstat_seq_stop(struct seq_file *f, void *v)
412 {
413 kstat_t *ksp = (kstat_t *)f->private;
414 ASSERT(ksp->ks_magic == KS_MAGIC);
415
416 if (ksp->ks_type == KSTAT_TYPE_RAW)
417 vmem_free(ksp->ks_raw_buf, ksp->ks_raw_bufsize);
418
419 mutex_exit(ksp->ks_lock);
420 }
421
422 static struct seq_operations kstat_seq_ops = {
423 .show = kstat_seq_show,
424 .start = kstat_seq_start,
425 .next = kstat_seq_next,
426 .stop = kstat_seq_stop,
427 };
428
429 static kstat_module_t *
430 kstat_find_module(char *name)
431 {
432 kstat_module_t *module;
433
434 list_for_each_entry(module, &kstat_module_list, ksm_module_list)
435 if (strncmp(name, module->ksm_name, KSTAT_STRLEN) == 0)
436 return (module);
437
438 return (NULL);
439 }
440
441 static kstat_module_t *
442 kstat_create_module(char *name)
443 {
444 kstat_module_t *module;
445 struct proc_dir_entry *pde;
446
447 pde = proc_mkdir(name, proc_spl_kstat);
448 if (pde == NULL)
449 return (NULL);
450
451 module = kmem_alloc(sizeof (kstat_module_t), KM_SLEEP);
452 module->ksm_proc = pde;
453 strlcpy(module->ksm_name, name, KSTAT_STRLEN+1);
454 INIT_LIST_HEAD(&module->ksm_kstat_list);
455 list_add_tail(&module->ksm_module_list, &kstat_module_list);
456
457 return (module);
458
459 }
460
461 static void
462 kstat_delete_module(kstat_module_t *module)
463 {
464 ASSERT(list_empty(&module->ksm_kstat_list));
465 remove_proc_entry(module->ksm_name, proc_spl_kstat);
466 list_del(&module->ksm_module_list);
467 kmem_free(module, sizeof(kstat_module_t));
468 }
469
470 static int
471 proc_kstat_open(struct inode *inode, struct file *filp)
472 {
473 struct seq_file *f;
474 int rc;
475
476 rc = seq_open(filp, &kstat_seq_ops);
477 if (rc)
478 return rc;
479
480 f = filp->private_data;
481 f->private = PDE_DATA(inode);
482
483 return rc;
484 }
485
486 static ssize_t
487 proc_kstat_write(struct file *filp, const char __user *buf,
488 size_t len, loff_t *ppos)
489 {
490 struct seq_file *f = filp->private_data;
491 kstat_t *ksp = f->private;
492 int rc;
493
494 ASSERT(ksp->ks_magic == KS_MAGIC);
495
496 mutex_enter(ksp->ks_lock);
497 rc = ksp->ks_update(ksp, KSTAT_WRITE);
498 mutex_exit(ksp->ks_lock);
499
500 if (rc)
501 return (-rc);
502
503 *ppos += len;
504 return (len);
505 }
506
507 static struct file_operations proc_kstat_operations = {
508 .open = proc_kstat_open,
509 .write = proc_kstat_write,
510 .read = seq_read,
511 .llseek = seq_lseek,
512 .release = seq_release,
513 };
514
515 void
516 __kstat_set_raw_ops(kstat_t *ksp,
517 int (*headers)(char *buf, size_t size),
518 int (*data)(char *buf, size_t size, void *data),
519 void *(*addr)(kstat_t *ksp, loff_t index))
520 {
521 ksp->ks_raw_ops.headers = headers;
522 ksp->ks_raw_ops.data = data;
523 ksp->ks_raw_ops.addr = addr;
524 }
525 EXPORT_SYMBOL(__kstat_set_raw_ops);
526
527 kstat_t *
528 __kstat_create(const char *ks_module, int ks_instance, const char *ks_name,
529 const char *ks_class, uchar_t ks_type, uint_t ks_ndata,
530 uchar_t ks_flags)
531 {
532 kstat_t *ksp;
533
534 ASSERT(ks_module);
535 ASSERT(ks_instance == 0);
536 ASSERT(ks_name);
537 ASSERT(!(ks_flags & KSTAT_FLAG_UNSUPPORTED));
538
539 if ((ks_type == KSTAT_TYPE_INTR) || (ks_type == KSTAT_TYPE_IO))
540 ASSERT(ks_ndata == 1);
541
542 ksp = kmem_zalloc(sizeof(*ksp), KM_SLEEP);
543 if (ksp == NULL)
544 return ksp;
545
546 mutex_enter(&kstat_module_lock);
547 ksp->ks_kid = kstat_id;
548 kstat_id++;
549 mutex_exit(&kstat_module_lock);
550
551 ksp->ks_magic = KS_MAGIC;
552 mutex_init(&ksp->ks_private_lock, NULL, MUTEX_DEFAULT, NULL);
553 ksp->ks_lock = &ksp->ks_private_lock;
554 INIT_LIST_HEAD(&ksp->ks_list);
555
556 ksp->ks_crtime = gethrtime();
557 ksp->ks_snaptime = ksp->ks_crtime;
558 strncpy(ksp->ks_module, ks_module, KSTAT_STRLEN);
559 ksp->ks_instance = ks_instance;
560 strncpy(ksp->ks_name, ks_name, KSTAT_STRLEN);
561 strncpy(ksp->ks_class, ks_class, KSTAT_STRLEN);
562 ksp->ks_type = ks_type;
563 ksp->ks_flags = ks_flags;
564 ksp->ks_update = kstat_default_update;
565 ksp->ks_private = NULL;
566 ksp->ks_raw_ops.headers = NULL;
567 ksp->ks_raw_ops.data = NULL;
568 ksp->ks_raw_ops.addr = NULL;
569 ksp->ks_raw_buf = NULL;
570 ksp->ks_raw_bufsize = 0;
571
572 switch (ksp->ks_type) {
573 case KSTAT_TYPE_RAW:
574 ksp->ks_ndata = 1;
575 ksp->ks_data_size = ks_ndata;
576 break;
577 case KSTAT_TYPE_NAMED:
578 ksp->ks_ndata = ks_ndata;
579 ksp->ks_data_size = ks_ndata * sizeof(kstat_named_t);
580 break;
581 case KSTAT_TYPE_INTR:
582 ksp->ks_ndata = ks_ndata;
583 ksp->ks_data_size = ks_ndata * sizeof(kstat_intr_t);
584 break;
585 case KSTAT_TYPE_IO:
586 ksp->ks_ndata = ks_ndata;
587 ksp->ks_data_size = ks_ndata * sizeof(kstat_io_t);
588 break;
589 case KSTAT_TYPE_TIMER:
590 ksp->ks_ndata = ks_ndata;
591 ksp->ks_data_size = ks_ndata * sizeof(kstat_timer_t);
592 break;
593 default:
594 PANIC("Undefined kstat type %d\n", ksp->ks_type);
595 }
596
597 if (ksp->ks_flags & KSTAT_FLAG_VIRTUAL) {
598 ksp->ks_data = NULL;
599 } else {
600 ksp->ks_data = kmem_zalloc(ksp->ks_data_size, KM_SLEEP);
601 if (ksp->ks_data == NULL) {
602 kmem_free(ksp, sizeof(*ksp));
603 ksp = NULL;
604 }
605 }
606
607 return ksp;
608 }
609 EXPORT_SYMBOL(__kstat_create);
610
611 void
612 __kstat_install(kstat_t *ksp)
613 {
614 kstat_module_t *module;
615 kstat_t *tmp;
616
617 ASSERT(ksp);
618
619 mutex_enter(&kstat_module_lock);
620
621 module = kstat_find_module(ksp->ks_module);
622 if (module == NULL) {
623 module = kstat_create_module(ksp->ks_module);
624 if (module == NULL)
625 goto out;
626 }
627
628 /*
629 * Only one entry by this name per-module, on failure the module
630 * shouldn't be deleted because we know it has at least one entry.
631 */
632 list_for_each_entry(tmp, &module->ksm_kstat_list, ks_list)
633 if (strncmp(tmp->ks_name, ksp->ks_name, KSTAT_STRLEN) == 0)
634 goto out;
635
636 list_add_tail(&ksp->ks_list, &module->ksm_kstat_list);
637
638 mutex_enter(ksp->ks_lock);
639 ksp->ks_owner = module;
640 ksp->ks_proc = proc_create_data(ksp->ks_name, 0644,
641 module->ksm_proc, &proc_kstat_operations, (void *)ksp);
642 if (ksp->ks_proc == NULL) {
643 list_del_init(&ksp->ks_list);
644 if (list_empty(&module->ksm_kstat_list))
645 kstat_delete_module(module);
646 }
647 mutex_exit(ksp->ks_lock);
648 out:
649 mutex_exit(&kstat_module_lock);
650 }
651 EXPORT_SYMBOL(__kstat_install);
652
653 void
654 __kstat_delete(kstat_t *ksp)
655 {
656 kstat_module_t *module = ksp->ks_owner;
657
658 mutex_enter(&kstat_module_lock);
659 list_del_init(&ksp->ks_list);
660 mutex_exit(&kstat_module_lock);
661
662 if (ksp->ks_proc) {
663 remove_proc_entry(ksp->ks_name, module->ksm_proc);
664
665 /* Remove top level module directory if it's empty */
666 if (list_empty(&module->ksm_kstat_list))
667 kstat_delete_module(module);
668 }
669
670 if (!(ksp->ks_flags & KSTAT_FLAG_VIRTUAL))
671 kmem_free(ksp->ks_data, ksp->ks_data_size);
672
673 ksp->ks_lock = NULL;
674 mutex_destroy(&ksp->ks_private_lock);
675 kmem_free(ksp, sizeof(*ksp));
676
677 return;
678 }
679 EXPORT_SYMBOL(__kstat_delete);
680
681 int
682 spl_kstat_init(void)
683 {
684 mutex_init(&kstat_module_lock, NULL, MUTEX_DEFAULT, NULL);
685 INIT_LIST_HEAD(&kstat_module_list);
686 kstat_id = 0;
687 return (0);
688 }
689
690 void
691 spl_kstat_fini(void)
692 {
693 ASSERT(list_empty(&kstat_module_list));
694 mutex_destroy(&kstat_module_lock);
695 }
696