]> git.proxmox.com Git - mirror_spl.git/blame - module/spl/spl-kstat.c
Refactor existing code
[mirror_spl.git] / module / spl / spl-kstat.c
CommitLineData
716154c5
BB
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>.
715f6251 6 * UCRL-CODE-235197
7 *
716154c5 8 * This file is part of the SPL, Solaris Porting Layer.
3d6af2dd 9 * For details, see <http://zfsonlinux.org/>.
716154c5
BB
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.
715f6251 15 *
716154c5 16 * The SPL is distributed in the hope that it will be useful, but WITHOUT
715f6251 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
716154c5
BB
22 * with the SPL. If not, see <http://www.gnu.org/licenses/>.
23 *****************************************************************************
24 * Solaris Porting Layer (SPL) Kstat Implementation.
25\*****************************************************************************/
715f6251 26
ae4c36ad 27#include <linux/seq_file.h>
55abb092 28#include <sys/kstat.h>
e5b9b344 29#include <sys/vmem.h>
04a479f7 30
1ddf9722
YS
31#ifndef HAVE_PDE_DATA
32#define PDE_DATA(x) (PDE(x)->data)
33#endif
b17edc10 34
f2a745c4
RY
35static kmutex_t kstat_module_lock;
36static struct list_head kstat_module_list;
04a479f7 37static kid_t kstat_id;
38
56d40a68
PS
39static int
40kstat_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
f483a97a
NB
52void
53kstat_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}
67EXPORT_SYMBOL(kstat_waitq_enter);
68
69void
70kstat_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}
83EXPORT_SYMBOL(kstat_waitq_exit);
84
85void
86kstat_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}
100EXPORT_SYMBOL(kstat_runq_enter);
101
102void
103kstat_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}
116EXPORT_SYMBOL(kstat_runq_exit);
117
56d40a68 118static int
04a479f7 119kstat_seq_show_headers(struct seq_file *f)
120{
121 kstat_t *ksp = (kstat_t *)f->private;
56d40a68
PS
122 int rc = 0;
123
04a479f7 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:
56d40a68
PS
133restart:
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 }
04a479f7 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:
55abb092 171 PANIC("Undefined kstat type %d\n", ksp->ks_type);
04a479f7 172 }
56d40a68
PS
173
174 return -rc;
04a479f7 175}
176
177static int
178kstat_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 }
195out:
196 return 0;
197}
198
199static int
200kstat_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:
cfe57499 219 seq_printf(f, "%lld", (signed long long)knp->value.i64);
04a479f7 220 break;
221 case KSTAT_DATA_UINT64:
cfe57499 222 seq_printf(f, "%llu", (unsigned long long)knp->value.ui64);
04a479f7 223 break;
224 case KSTAT_DATA_LONG:
225 seq_printf(f, "%ld", knp->value.l);
226 break;
227 case KSTAT_DATA_ULONG:
cfe57499 228 seq_printf(f, "%lu", knp->value.ul);
04a479f7 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:
55abb092 236 PANIC("Undefined kstat data type %d\n", knp->data_type);
04a479f7 237 }
238
239 seq_printf(f, "\n");
240
241 return 0;
242}
243
244static int
245kstat_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
257static int
258kstat_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
272static int
273kstat_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
284static int
285kstat_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:
56d40a68
PS
294restart:
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 }
04a479f7 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:
55abb092 321 PANIC("Undefined kstat type %d\n", ksp->ks_type);
04a479f7 322 }
323
56d40a68 324 return -rc;
04a479f7 325}
326
9a8b7a74
BB
327int
328kstat_default_update(kstat_t *ksp, int rw)
329{
330 ASSERT(ksp != NULL);
56d40a68
PS
331
332 if (rw == KSTAT_WRITE)
333 return (EACCES);
334
9a8b7a74
BB
335 return 0;
336}
337
04a479f7 338static void *
339kstat_seq_data_addr(kstat_t *ksp, loff_t n)
340{
341 void *rc = NULL;
04a479f7 342
343 switch (ksp->ks_type) {
344 case KSTAT_TYPE_RAW:
56d40a68
PS
345 if (ksp->ks_raw_ops.addr)
346 rc = ksp->ks_raw_ops.addr(ksp, n);
347 else
348 rc = ksp->ks_data;
04a479f7 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:
55abb092 363 PANIC("Undefined kstat type %d\n", ksp->ks_type);
04a479f7 364 }
365
8d9a23e8 366 return (rc);
04a479f7 367}
368
369static void *
370kstat_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);
04a479f7 375
ffbf0e57 376 mutex_enter(ksp->ks_lock);
71c9f0b0 377
56d40a68
PS
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
9a8b7a74
BB
383 /* Dynamically update kstat, on error existing kstats are used */
384 (void) ksp->ks_update(ksp, KSTAT_READ);
385
04a479f7 386 ksp->ks_snaptime = gethrtime();
387
56d40a68 388 if (!n && kstat_seq_show_headers(f))
8d9a23e8 389 return (NULL);
04a479f7 390
391 if (n >= ksp->ks_ndata)
8d9a23e8 392 return (NULL);
04a479f7 393
8d9a23e8 394 return (kstat_seq_data_addr(ksp, n));
04a479f7 395}
396
397static void *
398kstat_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);
04a479f7 402
403 ++*pos;
404 if (*pos >= ksp->ks_ndata)
8d9a23e8 405 return (NULL);
04a479f7 406
8d9a23e8 407 return (kstat_seq_data_addr(ksp, *pos));
04a479f7 408}
409
410static void
411kstat_seq_stop(struct seq_file *f, void *v)
412{
ffbf0e57
CP
413 kstat_t *ksp = (kstat_t *)f->private;
414 ASSERT(ksp->ks_magic == KS_MAGIC);
04a479f7 415
56d40a68
PS
416 if (ksp->ks_type == KSTAT_TYPE_RAW)
417 vmem_free(ksp->ks_raw_buf, ksp->ks_raw_bufsize);
418
ffbf0e57 419 mutex_exit(ksp->ks_lock);
04a479f7 420}
421
422static 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
f2a745c4
RY
429static kstat_module_t *
430kstat_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
441static kstat_module_t *
442kstat_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
461static void
462kstat_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
04a479f7 470static int
471proc_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;
1ddf9722 481 f->private = PDE_DATA(inode);
04a479f7 482
483 return rc;
484}
485
56d40a68
PS
486static ssize_t
487proc_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
04a479f7 507static struct file_operations proc_kstat_operations = {
56d40a68
PS
508 .open = proc_kstat_open,
509 .write = proc_kstat_write,
510 .read = seq_read,
511 .llseek = seq_lseek,
512 .release = seq_release,
04a479f7 513};
514
56d40a68
PS
515void
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}
525EXPORT_SYMBOL(__kstat_set_raw_ops);
526
04a479f7 527kstat_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
f2a745c4 546 mutex_enter(&kstat_module_lock);
04a479f7 547 ksp->ks_kid = kstat_id;
548 kstat_id++;
f2a745c4 549 mutex_exit(&kstat_module_lock);
04a479f7 550
551 ksp->ks_magic = KS_MAGIC;
ffbf0e57
CP
552 mutex_init(&ksp->ks_private_lock, NULL, MUTEX_DEFAULT, NULL);
553 ksp->ks_lock = &ksp->ks_private_lock;
04a479f7 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;
9a8b7a74
BB
564 ksp->ks_update = kstat_default_update;
565 ksp->ks_private = NULL;
56d40a68
PS
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;
04a479f7 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:
55abb092 594 PANIC("Undefined kstat type %d\n", ksp->ks_type);
04a479f7 595 }
596
597 if (ksp->ks_flags & KSTAT_FLAG_VIRTUAL) {
598 ksp->ks_data = NULL;
599 } else {
f483a97a 600 ksp->ks_data = kmem_zalloc(ksp->ks_data_size, KM_SLEEP);
04a479f7 601 if (ksp->ks_data == NULL) {
602 kmem_free(ksp, sizeof(*ksp));
603 ksp = NULL;
604 }
605 }
606
607 return ksp;
608}
609EXPORT_SYMBOL(__kstat_create);
610
611void
612__kstat_install(kstat_t *ksp)
613{
f2a745c4 614 kstat_module_t *module;
04a479f7 615 kstat_t *tmp;
04a479f7 616
f2a745c4 617 ASSERT(ksp);
04a479f7 618
f2a745c4 619 mutex_enter(&kstat_module_lock);
04a479f7 620
f2a745c4
RY
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;
04a479f7 626 }
627
f2a745c4
RY
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);
04a479f7 637
ffbf0e57 638 mutex_enter(ksp->ks_lock);
f2a745c4 639 ksp->ks_owner = module;
56d40a68 640 ksp->ks_proc = proc_create_data(ksp->ks_name, 0644,
f2a745c4
RY
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 }
ffbf0e57 647 mutex_exit(ksp->ks_lock);
04a479f7 648out:
f2a745c4 649 mutex_exit(&kstat_module_lock);
04a479f7 650}
651EXPORT_SYMBOL(__kstat_install);
652
653void
654__kstat_delete(kstat_t *ksp)
655{
f2a745c4 656 kstat_module_t *module = ksp->ks_owner;
04a479f7 657
f2a745c4
RY
658 mutex_enter(&kstat_module_lock);
659 list_del_init(&ksp->ks_list);
660 mutex_exit(&kstat_module_lock);
04a479f7 661
f2a745c4
RY
662 if (ksp->ks_proc) {
663 remove_proc_entry(ksp->ks_name, module->ksm_proc);
04a479f7 664
f2a745c4
RY
665 /* Remove top level module directory if it's empty */
666 if (list_empty(&module->ksm_kstat_list))
667 kstat_delete_module(module);
04a479f7 668 }
669
670 if (!(ksp->ks_flags & KSTAT_FLAG_VIRTUAL))
f2a745c4 671 kmem_free(ksp->ks_data, ksp->ks_data_size);
04a479f7 672
ffbf0e57
CP
673 ksp->ks_lock = NULL;
674 mutex_destroy(&ksp->ks_private_lock);
04a479f7 675 kmem_free(ksp, sizeof(*ksp));
676
677 return;
678}
679EXPORT_SYMBOL(__kstat_delete);
680
04a479f7 681int
1114ae6a 682spl_kstat_init(void)
04a479f7 683{
f2a745c4
RY
684 mutex_init(&kstat_module_lock, NULL, MUTEX_DEFAULT, NULL);
685 INIT_LIST_HEAD(&kstat_module_list);
04a479f7 686 kstat_id = 0;
8d9a23e8 687 return (0);
04a479f7 688}
689
690void
1114ae6a 691spl_kstat_fini(void)
04a479f7 692{
f2a745c4
RY
693 ASSERT(list_empty(&kstat_module_list));
694 mutex_destroy(&kstat_module_lock);
04a479f7 695}
696