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