]> granicus.if.org Git - zfs/blob - module/spl/spl-kstat.c
2b45549d6f6c229586983d63857718da6aa01bd2
[zfs] / 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://github.com/behlendorf/spl/>.
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 <sys/kstat.h>
28
29 static spinlock_t kstat_lock;
30 static struct list_head kstat_list;
31 static kid_t kstat_id;
32
33 static void
34 kstat_seq_show_headers(struct seq_file *f)
35 {
36         kstat_t *ksp = (kstat_t *)f->private;
37         ASSERT(ksp->ks_magic == KS_MAGIC);
38
39         seq_printf(f, "%d %d 0x%02x %d %d %lld %lld\n",
40                    ksp->ks_kid, ksp->ks_type, ksp->ks_flags,
41                    ksp->ks_ndata, (int)ksp->ks_data_size,
42                    ksp->ks_crtime, ksp->ks_snaptime);
43
44         switch (ksp->ks_type) {
45                 case KSTAT_TYPE_RAW:
46                         seq_printf(f, "raw data");
47                         break;
48                 case KSTAT_TYPE_NAMED:
49                         seq_printf(f, "%-31s %-4s %s\n",
50                                    "name", "type", "data");
51                         break;
52                 case KSTAT_TYPE_INTR:
53                         seq_printf(f, "%-8s %-8s %-8s %-8s %-8s\n",
54                                    "hard", "soft", "watchdog",
55                                    "spurious", "multsvc");
56                         break;
57                 case KSTAT_TYPE_IO:
58                         seq_printf(f,
59                                    "%-8s %-8s %-8s %-8s %-8s %-8s "
60                                    "%-8s %-8s %-8s %-8s %-8s %-8s\n",
61                                    "nread", "nwritten", "reads", "writes",
62                                    "wtime", "wlentime", "wupdate",
63                                    "rtime", "rlentime", "rupdate",
64                                    "wcnt", "rcnt");
65                         break;
66                 case KSTAT_TYPE_TIMER:
67                         seq_printf(f,
68                                    "%-31s %-8s "
69                                    "%-8s %-8s %-8s %-8s %-8s\n",
70                                    "name", "events", "elapsed",
71                                    "min", "max", "start", "stop");
72                         break;
73                 default:
74                         SBUG(); /* Unreachable */
75         }
76 }
77
78 static int
79 kstat_seq_show_raw(struct seq_file *f, unsigned char *p, int l)
80 {
81         int i, j;
82
83         for (i = 0; ; i++) {
84                 seq_printf(f, "%03x:", i);
85
86                 for (j = 0; j < 16; j++) {
87                         if (i * 16 + j >= l) {
88                                 seq_printf(f, "\n");
89                                 goto out;
90                         }
91
92                         seq_printf(f, " %02x", (unsigned char)p[i * 16 + j]);
93                 }
94                 seq_printf(f, "\n");
95         }
96 out:
97         return 0;
98 }
99
100 static int
101 kstat_seq_show_named(struct seq_file *f, kstat_named_t *knp)
102 {
103         seq_printf(f, "%-31s %-4d ", knp->name, knp->data_type);
104
105         switch (knp->data_type) {
106                 case KSTAT_DATA_CHAR:
107                         knp->value.c[15] = '\0'; /* NULL terminate */
108                         seq_printf(f, "%-16s", knp->value.c);
109                         break;
110                 /* XXX - We need to be more careful able what tokens are
111                  * used for each arch, for now this is correct for x86_64.
112                  */
113                 case KSTAT_DATA_INT32:
114                         seq_printf(f, "%d", knp->value.i32);
115                         break;
116                 case KSTAT_DATA_UINT32:
117                         seq_printf(f, "%u", knp->value.ui32);
118                         break;
119                 case KSTAT_DATA_INT64:
120                         seq_printf(f, "%lld", (signed long long)knp->value.i64);
121                         break;
122                 case KSTAT_DATA_UINT64:
123                         seq_printf(f, "%llu", (unsigned long long)knp->value.ui64);
124                         break;
125                 case KSTAT_DATA_LONG:
126                         seq_printf(f, "%ld", knp->value.l);
127                         break;
128                 case KSTAT_DATA_ULONG:
129                         seq_printf(f, "%lu", knp->value.ul);
130                         break;
131                 case KSTAT_DATA_STRING:
132                         KSTAT_NAMED_STR_PTR(knp)
133                                 [KSTAT_NAMED_STR_BUFLEN(knp)-1] = '\0';
134                         seq_printf(f, "%s", KSTAT_NAMED_STR_PTR(knp));
135                         break;
136                 default:
137                         SBUG(); /* Unreachable */
138         }
139
140         seq_printf(f, "\n");
141
142         return 0;
143 }
144
145 static int
146 kstat_seq_show_intr(struct seq_file *f, kstat_intr_t *kip)
147 {
148         seq_printf(f, "%-8u %-8u %-8u %-8u %-8u\n",
149                    kip->intrs[KSTAT_INTR_HARD],
150                    kip->intrs[KSTAT_INTR_SOFT],
151                    kip->intrs[KSTAT_INTR_WATCHDOG],
152                    kip->intrs[KSTAT_INTR_SPURIOUS],
153                    kip->intrs[KSTAT_INTR_MULTSVC]);
154
155         return 0;
156 }
157
158 static int
159 kstat_seq_show_io(struct seq_file *f, kstat_io_t *kip)
160 {
161         seq_printf(f,
162                    "%-8llu %-8llu %-8u %-8u %-8lld %-8lld "
163                    "%-8lld %-8lld %-8lld %-8lld %-8u %-8u\n",
164                    kip->nread, kip->nwritten,
165                    kip->reads, kip->writes,
166                    kip->wtime, kip->wlentime, kip->wlastupdate,
167                    kip->rtime, kip->wlentime, kip->rlastupdate,
168                    kip->wcnt,  kip->rcnt);
169
170         return 0;
171 }
172
173 static int
174 kstat_seq_show_timer(struct seq_file *f, kstat_timer_t *ktp)
175 {
176         seq_printf(f,
177                    "%-31s %-8llu %-8lld %-8lld %-8lld %-8lld %-8lld\n",
178                    ktp->name, ktp->num_events, ktp->elapsed_time,
179                    ktp->min_time, ktp->max_time,
180                    ktp->start_time, ktp->stop_time);
181
182         return 0;
183 }
184
185 static int
186 kstat_seq_show(struct seq_file *f, void *p)
187 {
188         kstat_t *ksp = (kstat_t *)f->private;
189         int rc = 0;
190
191         ASSERT(ksp->ks_magic == KS_MAGIC);
192
193         switch (ksp->ks_type) {
194                 case KSTAT_TYPE_RAW:
195                         ASSERT(ksp->ks_ndata == 1);
196                         rc = kstat_seq_show_raw(f, ksp->ks_data,
197                                                 ksp->ks_data_size);
198                         break;
199                 case KSTAT_TYPE_NAMED:
200                         rc = kstat_seq_show_named(f, (kstat_named_t *)p);
201                         break;
202                 case KSTAT_TYPE_INTR:
203                         rc = kstat_seq_show_intr(f, (kstat_intr_t *)p);
204                         break;
205                 case KSTAT_TYPE_IO:
206                         rc = kstat_seq_show_io(f, (kstat_io_t *)p);
207                         break;
208                 case KSTAT_TYPE_TIMER:
209                         rc = kstat_seq_show_timer(f, (kstat_timer_t *)p);
210                         break;
211                 default:
212                         SBUG(); /* Unreachable */
213         }
214
215         return rc;
216 }
217
218 static void *
219 kstat_seq_data_addr(kstat_t *ksp, loff_t n)
220 {
221         void *rc = NULL;
222         ENTRY;
223
224         switch (ksp->ks_type) {
225                 case KSTAT_TYPE_RAW:
226                         rc = ksp->ks_data;
227                         break;
228                 case KSTAT_TYPE_NAMED:
229                         rc = ksp->ks_data + n * sizeof(kstat_named_t);
230                         break;
231                 case KSTAT_TYPE_INTR:
232                         rc = ksp->ks_data + n * sizeof(kstat_intr_t);
233                         break;
234                 case KSTAT_TYPE_IO:
235                         rc = ksp->ks_data + n * sizeof(kstat_io_t);
236                         break;
237                 case KSTAT_TYPE_TIMER:
238                         rc = ksp->ks_data + n * sizeof(kstat_timer_t);
239                         break;
240                 default:
241                         SBUG(); /* Unreachable */
242         }
243
244         RETURN(rc);
245 }
246
247 static void *
248 kstat_seq_start(struct seq_file *f, loff_t *pos)
249 {
250         loff_t n = *pos;
251         kstat_t *ksp = (kstat_t *)f->private;
252         ASSERT(ksp->ks_magic == KS_MAGIC);
253         ENTRY;
254
255         spin_lock(&ksp->ks_lock);
256         ksp->ks_snaptime = gethrtime();
257
258         if (!n)
259                 kstat_seq_show_headers(f);
260
261         if (n >= ksp->ks_ndata)
262                 RETURN(NULL);
263
264         RETURN(kstat_seq_data_addr(ksp, n));
265 }
266
267 static void *
268 kstat_seq_next(struct seq_file *f, void *p, loff_t *pos)
269 {
270         kstat_t *ksp = (kstat_t *)f->private;
271         ASSERT(ksp->ks_magic == KS_MAGIC);
272         ENTRY;
273
274         ++*pos;
275         if (*pos >= ksp->ks_ndata)
276                 RETURN(NULL);
277
278         RETURN(kstat_seq_data_addr(ksp, *pos));
279 }
280
281 static void
282 kstat_seq_stop(struct seq_file *f, void *v)
283 {
284         kstat_t *ksp = (kstat_t *)f->private;
285         ASSERT(ksp->ks_magic == KS_MAGIC);
286
287         spin_unlock(&ksp->ks_lock);
288 }
289
290 static struct seq_operations kstat_seq_ops = {
291         .show  = kstat_seq_show,
292         .start = kstat_seq_start,
293         .next  = kstat_seq_next,
294         .stop  = kstat_seq_stop,
295 };
296
297 static int
298 proc_kstat_open(struct inode *inode, struct file *filp)
299 {
300         struct seq_file *f;
301         int rc;
302
303         rc = seq_open(filp, &kstat_seq_ops);
304         if (rc)
305                 return rc;
306
307         f = filp->private_data;
308         f->private = PDE(inode)->data;
309
310         return rc;
311 }
312
313 static struct file_operations proc_kstat_operations = {
314         .open           = proc_kstat_open,
315         .read           = seq_read,
316         .llseek         = seq_lseek,
317         .release        = seq_release,
318 };
319
320 kstat_t *
321 __kstat_create(const char *ks_module, int ks_instance, const char *ks_name,
322              const char *ks_class, uchar_t ks_type, uint_t ks_ndata,
323              uchar_t ks_flags)
324 {
325         kstat_t *ksp;
326
327         ASSERT(ks_module);
328         ASSERT(ks_instance == 0);
329         ASSERT(ks_name);
330         ASSERT(!(ks_flags & KSTAT_FLAG_UNSUPPORTED));
331
332         if ((ks_type == KSTAT_TYPE_INTR) || (ks_type == KSTAT_TYPE_IO))
333                 ASSERT(ks_ndata == 1);
334
335         ksp = kmem_zalloc(sizeof(*ksp), KM_SLEEP);
336         if (ksp == NULL)
337                 return ksp;
338
339         spin_lock(&kstat_lock);
340         ksp->ks_kid = kstat_id;
341         kstat_id++;
342         spin_unlock(&kstat_lock);
343
344         ksp->ks_magic = KS_MAGIC;
345         spin_lock_init(&ksp->ks_lock);
346         INIT_LIST_HEAD(&ksp->ks_list);
347
348         ksp->ks_crtime = gethrtime();
349         ksp->ks_snaptime = ksp->ks_crtime;
350         strncpy(ksp->ks_module, ks_module, KSTAT_STRLEN);
351         ksp->ks_instance = ks_instance;
352         strncpy(ksp->ks_name, ks_name, KSTAT_STRLEN);
353         strncpy(ksp->ks_class, ks_class, KSTAT_STRLEN);
354         ksp->ks_type = ks_type;
355         ksp->ks_flags = ks_flags;
356
357         switch (ksp->ks_type) {
358                 case KSTAT_TYPE_RAW:
359                         ksp->ks_ndata = 1;
360                         ksp->ks_data_size = ks_ndata;
361                         break;
362                 case KSTAT_TYPE_NAMED:
363                         ksp->ks_ndata = ks_ndata;
364                         ksp->ks_data_size = ks_ndata * sizeof(kstat_named_t);
365                         break;
366                 case KSTAT_TYPE_INTR:
367                         ksp->ks_ndata = ks_ndata;
368                         ksp->ks_data_size = ks_ndata * sizeof(kstat_intr_t);
369                         break;
370                 case KSTAT_TYPE_IO:
371                         ksp->ks_ndata = ks_ndata;
372                         ksp->ks_data_size = ks_ndata * sizeof(kstat_io_t);
373                         break;
374                 case KSTAT_TYPE_TIMER:
375                         ksp->ks_ndata = ks_ndata;
376                         ksp->ks_data_size = ks_ndata * sizeof(kstat_timer_t);
377                         break;
378                 default:
379                         SBUG(); /* Unreachable */
380         }
381
382         if (ksp->ks_flags & KSTAT_FLAG_VIRTUAL) {
383                 ksp->ks_data = NULL;
384         } else {
385                 ksp->ks_data = kmem_alloc(ksp->ks_data_size, KM_SLEEP);
386                 if (ksp->ks_data == NULL) {
387                         kmem_free(ksp, sizeof(*ksp));
388                         ksp = NULL;
389                 }
390         }
391
392         return ksp;
393 }
394 EXPORT_SYMBOL(__kstat_create);
395
396 void
397 __kstat_install(kstat_t *ksp)
398 {
399         struct proc_dir_entry *de_module, *de_name;
400         kstat_t *tmp;
401         int rc = 0;
402         ENTRY;
403
404         spin_lock(&kstat_lock);
405
406         /* Item may only be added to the list once */
407         list_for_each_entry(tmp, &kstat_list, ks_list) {
408                 if (tmp == ksp) {
409                         spin_unlock(&kstat_lock);
410                         GOTO(out, rc = -EEXIST);
411                 }
412         }
413
414         list_add_tail(&ksp->ks_list, &kstat_list);
415         spin_unlock(&kstat_lock);
416
417         de_module = proc_dir_entry_find(proc_spl_kstat, ksp->ks_module);
418         if (de_module == NULL) {
419                 de_module = proc_mkdir(ksp->ks_module, proc_spl_kstat);
420                 if (de_module == NULL)
421                         GOTO(out, rc = -EUNATCH);
422         }
423
424         de_name = create_proc_entry(ksp->ks_name, 0444, de_module);
425         if (de_name == NULL)
426                 GOTO(out, rc = -EUNATCH);
427
428         spin_lock(&ksp->ks_lock);
429         ksp->ks_proc = de_name;
430         de_name->proc_fops = &proc_kstat_operations;
431         de_name->data = (void *)ksp;
432         spin_unlock(&ksp->ks_lock);
433 out:
434         if (rc) {
435                 spin_lock(&kstat_lock);
436                 list_del_init(&ksp->ks_list);
437                 spin_unlock(&kstat_lock);
438         }
439
440         EXIT;
441 }
442 EXPORT_SYMBOL(__kstat_install);
443
444 void
445 __kstat_delete(kstat_t *ksp)
446 {
447         struct proc_dir_entry *de_module;
448
449         spin_lock(&kstat_lock);
450         list_del_init(&ksp->ks_list);
451         spin_unlock(&kstat_lock);
452
453         if (ksp->ks_proc) {
454                 de_module = ksp->ks_proc->parent;
455                 remove_proc_entry(ksp->ks_name, de_module);
456
457                 /* Remove top level module directory if it's empty */
458                 if (proc_dir_entries(de_module) == 0)
459                         remove_proc_entry(de_module->name, de_module->parent);
460         }
461
462         if (!(ksp->ks_flags & KSTAT_FLAG_VIRTUAL))
463                 kmem_free(ksp->ks_data, ksp->ks_data_size);
464
465         kmem_free(ksp, sizeof(*ksp));
466
467         return;
468 }
469 EXPORT_SYMBOL(__kstat_delete);
470
471 int
472 kstat_init(void)
473 {
474         ENTRY;
475         spin_lock_init(&kstat_lock);
476         INIT_LIST_HEAD(&kstat_list);
477         kstat_id = 0;
478         RETURN(0);
479 }
480
481 void
482 kstat_fini(void)
483 {
484         ENTRY;
485         ASSERT(list_empty(&kstat_list));
486         EXIT;
487 }
488