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