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