]> git.proxmox.com Git - mirror_spl-debian.git/blame - module/spl/spl-kstat.c
Add 3 missing typedefs.
[mirror_spl-debian.git] / module / spl / spl-kstat.c
CommitLineData
715f6251 1/*
2 * This file is part of the SPL: Solaris Porting Layer.
3 *
4 * Copyright (c) 2008 Lawrence Livermore National Security, LLC.
5 * Produced at Lawrence Livermore National Laboratory
6 * Written by:
7 * Brian Behlendorf <behlendorf1@llnl.gov>,
8 * Herb Wartens <wartens2@llnl.gov>,
9 * Jim Garlick <garlick@llnl.gov>
10 * UCRL-CODE-235197
11 *
12 * This is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
21 *
22 * You should have received a copy of the GNU General Public License along
23 * with this program; if not, write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 */
26
04a479f7 27#include <sys/kstat.h>
28
04a479f7 29static spinlock_t kstat_lock;
30static struct list_head kstat_list;
31static kid_t kstat_id;
32
33static void
34kstat_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
78static int
79kstat_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 }
96out:
97 return 0;
98}
99
100static int
101kstat_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:
cfe57499 120 seq_printf(f, "%lld", (signed long long)knp->value.i64);
04a479f7 121 break;
122 case KSTAT_DATA_UINT64:
cfe57499 123 seq_printf(f, "%llu", (unsigned long long)knp->value.ui64);
04a479f7 124 break;
125 case KSTAT_DATA_LONG:
126 seq_printf(f, "%ld", knp->value.l);
127 break;
128 case KSTAT_DATA_ULONG:
cfe57499 129 seq_printf(f, "%lu", knp->value.ul);
04a479f7 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
145static int
146kstat_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
158static int
159kstat_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
173static int
174kstat_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
185static int
186kstat_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
218static void *
219kstat_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
247static void *
248kstat_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
267static void *
268kstat_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
281static void
282kstat_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
290static 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
297static int
298proc_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
313static 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
320kstat_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}
394EXPORT_SYMBOL(__kstat_create);
395
396void
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
c30df9c8 417 de_module = proc_dir_entry_find(proc_spl_kstat, ksp->ks_module);
04a479f7 418 if (de_module == NULL) {
c30df9c8 419 de_module = proc_mkdir(ksp->ks_module, proc_spl_kstat);
04a479f7 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);
433out:
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}
442EXPORT_SYMBOL(__kstat_install);
443
444void
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}
469EXPORT_SYMBOL(__kstat_delete);
470
04a479f7 471int
472kstat_init(void)
473{
474 ENTRY;
04a479f7 475 spin_lock_init(&kstat_lock);
476 INIT_LIST_HEAD(&kstat_list);
477 kstat_id = 0;
04a479f7 478 RETURN(0);
479}
480
481void
482kstat_fini(void)
483{
484 ENTRY;
04a479f7 485 ASSERT(list_empty(&kstat_list));
04a479f7 486 EXIT;
487}
488