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