]> git.proxmox.com Git - mirror_spl.git/blame - module/spl/spl-proc.c
Skip GPL-only symbols test when cross-compiling
[mirror_spl.git] / module / spl / spl-proc.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 8 * This file is part of the SPL, Solaris Porting Layer.
3d6af2dd 9 * For details, see <http://zfsonlinux.org/>.
716154c5
BB
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) Proc Implementation.
25\*****************************************************************************/
715f6251 26
ae4c36ad
BB
27#include <sys/systeminfo.h>
28#include <sys/kstat.h>
e5b9b344
BB
29#include <sys/kmem.h>
30#include <sys/kmem_cache.h>
31#include <sys/vmem.h>
32#include <linux/ctype.h>
ae4c36ad
BB
33#include <linux/kmod.h>
34#include <linux/seq_file.h>
35#include <linux/proc_compat.h>
e5b9b344 36#include <linux/uaccess.h>
e3c4d448 37#include <linux/version.h>
57d1b188 38
e3c4d448
RY
39#if defined(CONSTIFY_PLUGIN) && LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0)
40typedef struct ctl_table __no_const spl_ctl_table;
41#else
42typedef struct ctl_table spl_ctl_table;
43#endif
44
57d1b188 45static unsigned long table_min = 0;
46static unsigned long table_max = ~0;
404992e3 47
404992e3 48static struct ctl_table_header *spl_header = NULL;
c30df9c8 49static struct proc_dir_entry *proc_spl = NULL;
c30df9c8 50static struct proc_dir_entry *proc_spl_kmem = NULL;
ff449ac4 51static struct proc_dir_entry *proc_spl_kmem_slab = NULL;
c30df9c8 52struct proc_dir_entry *proc_spl_kstat = NULL;
57d1b188 53
57d1b188 54static int
55proc_copyin_string(char *kbuffer, int kbuffer_size,
56 const char *ubuffer, int ubuffer_size)
57{
58 int size;
59
60 if (ubuffer_size > kbuffer_size)
61 return -EOVERFLOW;
62
63 if (copy_from_user((void *)kbuffer, (void *)ubuffer, ubuffer_size))
64 return -EFAULT;
65
66 /* strip trailing whitespace */
67 size = strnlen(kbuffer, ubuffer_size);
68 while (size-- >= 0)
69 if (!isspace(kbuffer[size]))
70 break;
71
72 /* empty string */
73 if (size < 0)
74 return -EINVAL;
75
76 /* no space to terminate */
77 if (size == kbuffer_size)
78 return -EOVERFLOW;
79
80 kbuffer[size + 1] = 0;
81 return 0;
82}
83
84static int
85proc_copyout_string(char *ubuffer, int ubuffer_size,
86 const char *kbuffer, char *append)
87{
88 /* NB if 'append' != NULL, it's a single character to append to the
89 * copied out string - usually "\n", for /proc entries and
90 * (i.e. a terminating zero byte) for sysctl entries
91 */
92 int size = MIN(strlen(kbuffer), ubuffer_size);
93
94 if (copy_to_user(ubuffer, kbuffer, size))
95 return -EFAULT;
96
97 if (append != NULL && size < ubuffer_size) {
98 if (copy_to_user(ubuffer + size, append, 1))
99 return -EFAULT;
100
101 size++;
102 }
103
104 return size;
105}
106
c6dc93d6 107#ifdef DEBUG_KMEM
0fac9c9e
BB
108static int
109proc_domemused(struct ctl_table *table, int write,
110 void __user *buffer, size_t *lenp, loff_t *ppos)
57d1b188 111{
112 int rc = 0;
113 unsigned long min = 0, max = ~0, val;
e3c4d448 114 spl_ctl_table dummy = *table;
57d1b188 115
116 dummy.data = &val;
117 dummy.proc_handler = &proc_dointvec;
118 dummy.extra1 = &min;
119 dummy.extra2 = &max;
120
121 if (write) {
122 *ppos += *lenp;
123 } else {
d04c8a56 124# ifdef HAVE_ATOMIC64_T
550f1705 125 val = atomic64_read((atomic64_t *)table->data);
d04c8a56
BB
126# else
127 val = atomic_read((atomic_t *)table->data);
128# endif /* HAVE_ATOMIC64_T */
0fac9c9e 129 rc = proc_doulongvec_minmax(&dummy, write, buffer, lenp, ppos);
57d1b188 130 }
131
8d9a23e8 132 return (rc);
57d1b188 133}
9eb361aa 134#endif /* DEBUG_KMEM */
3336e29c 135
0fac9c9e
BB
136static int
137proc_doslab(struct ctl_table *table, int write,
138 void __user *buffer, size_t *lenp, loff_t *ppos)
3336e29c
BB
139{
140 int rc = 0;
141 unsigned long min = 0, max = ~0, val = 0, mask;
e3c4d448 142 spl_ctl_table dummy = *table;
3336e29c 143 spl_kmem_cache_t *skc;
3336e29c
BB
144
145 dummy.data = &val;
146 dummy.proc_handler = &proc_dointvec;
147 dummy.extra1 = &min;
148 dummy.extra2 = &max;
149
150 if (write) {
151 *ppos += *lenp;
152 } else {
153 down_read(&spl_kmem_cache_sem);
154 mask = (unsigned long)table->data;
155
156 list_for_each_entry(skc, &spl_kmem_cache_list, skc_list) {
157
158 /* Only use slabs of the correct kmem/vmem type */
159 if (!(skc->skc_flags & mask))
160 continue;
161
162 /* Sum the specified field for selected slabs */
163 switch (mask & (KMC_TOTAL | KMC_ALLOC | KMC_MAX)) {
164 case KMC_TOTAL:
165 val += skc->skc_slab_size * skc->skc_slab_total;
166 break;
167 case KMC_ALLOC:
168 val += skc->skc_obj_size * skc->skc_obj_alloc;
169 break;
170 case KMC_MAX:
171 val += skc->skc_obj_size * skc->skc_obj_max;
172 break;
173 }
174 }
175
176 up_read(&spl_kmem_cache_sem);
0fac9c9e 177 rc = proc_doulongvec_minmax(&dummy, write, buffer, lenp, ppos);
3336e29c
BB
178 }
179
8d9a23e8 180 return (rc);
3336e29c 181}
57d1b188 182
0fac9c9e
BB
183static int
184proc_dohostid(struct ctl_table *table, int write,
185 void __user *buffer, size_t *lenp, loff_t *ppos)
57d1b188 186{
187 int len, rc = 0;
57d1b188 188 char *end, str[32];
57d1b188 189
190 if (write) {
0fac9c9e 191 /* We can't use proc_doulongvec_minmax() in the write
c95b308d 192 * case here because hostid while a hex value has no
a0b5ae8a 193 * leading 0x which confuses the helper function. */
57d1b188 194 rc = proc_copyin_string(str, sizeof(str), buffer, *lenp);
195 if (rc < 0)
8d9a23e8 196 return (rc);
57d1b188 197
fa6f7d8f 198 spl_hostid = simple_strtoul(str, &end, 16);
a0b5ae8a 199 if (str == end)
8d9a23e8 200 return (-EINVAL);
57d1b188 201
57d1b188 202 } else {
c95b308d 203 len = snprintf(str, sizeof(str), "%lx", spl_hostid);
57d1b188 204 if (*ppos >= len)
205 rc = 0;
206 else
3977f837 207 rc = proc_copyout_string(buffer,*lenp,str+*ppos,"\n");
57d1b188 208
209 if (rc >= 0) {
210 *lenp = rc;
211 *ppos += rc;
212 }
213 }
214
8d9a23e8 215 return (rc);
57d1b188 216}
217
ff449ac4 218static void
219slab_seq_show_headers(struct seq_file *f)
220{
d0a1038f
BB
221 seq_printf(f,
222 "--------------------- cache ----------"
223 "--------------------------------------------- "
224 "----- slab ------ "
165f13c3
BB
225 "---- object ----- "
226 "--- emergency ---\n");
d0a1038f
BB
227 seq_printf(f,
228 "name "
229 " flags size alloc slabsize objsize "
230 "total alloc max "
165f13c3
BB
231 "total alloc max "
232 "dlock alloc max\n");
ff449ac4 233}
234
235static int
236slab_seq_show(struct seq_file *f, void *p)
237{
242f539a 238 spl_kmem_cache_t *skc = p;
ff449ac4 239
242f539a 240 ASSERT(skc->skc_magic == SKC_MAGIC);
ff449ac4 241
a073aeb0
BB
242 /*
243 * Backed by Linux slab see /proc/slabinfo.
244 */
245 if (skc->skc_flags & KMC_SLAB)
246 return (0);
247
242f539a 248 spin_lock(&skc->skc_lock);
d0a1038f
BB
249 seq_printf(f, "%-36s ", skc->skc_name);
250 seq_printf(f, "0x%05lx %9lu %9lu %8u %8u "
165f13c3 251 "%5lu %5lu %5lu %5lu %5lu %5lu %5lu %5lu %5lu\n",
d0a1038f
BB
252 (long unsigned)skc->skc_flags,
253 (long unsigned)(skc->skc_slab_size * skc->skc_slab_total),
254 (long unsigned)(skc->skc_obj_size * skc->skc_obj_alloc),
255 (unsigned)skc->skc_slab_size,
256 (unsigned)skc->skc_obj_size,
257 (long unsigned)skc->skc_slab_total,
258 (long unsigned)skc->skc_slab_alloc,
259 (long unsigned)skc->skc_slab_max,
260 (long unsigned)skc->skc_obj_total,
261 (long unsigned)skc->skc_obj_alloc,
e2dcc6e2 262 (long unsigned)skc->skc_obj_max,
165f13c3 263 (long unsigned)skc->skc_obj_deadlock,
e2dcc6e2
BB
264 (long unsigned)skc->skc_obj_emergency,
265 (long unsigned)skc->skc_obj_emergency_max);
242f539a
BB
266
267 spin_unlock(&skc->skc_lock);
ff449ac4 268
269 return 0;
270}
271
272static void *
273slab_seq_start(struct seq_file *f, loff_t *pos)
274{
275 struct list_head *p;
276 loff_t n = *pos;
ff449ac4 277
278 down_read(&spl_kmem_cache_sem);
279 if (!n)
280 slab_seq_show_headers(f);
281
282 p = spl_kmem_cache_list.next;
283 while (n--) {
284 p = p->next;
285 if (p == &spl_kmem_cache_list)
8d9a23e8 286 return (NULL);
ff449ac4 287 }
288
8d9a23e8 289 return (list_entry(p, spl_kmem_cache_t, skc_list));
ff449ac4 290}
291
292static void *
293slab_seq_next(struct seq_file *f, void *p, loff_t *pos)
294{
295 spl_kmem_cache_t *skc = p;
ff449ac4 296
297 ++*pos;
8d9a23e8 298 return ((skc->skc_list.next == &spl_kmem_cache_list) ?
3977f837 299 NULL : list_entry(skc->skc_list.next,spl_kmem_cache_t,skc_list));
ff449ac4 300}
301
302static void
303slab_seq_stop(struct seq_file *f, void *v)
304{
305 up_read(&spl_kmem_cache_sem);
306}
307
308static struct seq_operations slab_seq_ops = {
309 .show = slab_seq_show,
310 .start = slab_seq_start,
311 .next = slab_seq_next,
312 .stop = slab_seq_stop,
313};
314
315static int
316proc_slab_open(struct inode *inode, struct file *filp)
317{
318 return seq_open(filp, &slab_seq_ops);
319}
320
321static struct file_operations proc_slab_operations = {
322 .open = proc_slab_open,
323 .read = seq_read,
324 .llseek = seq_lseek,
325 .release = seq_release,
326};
ff449ac4 327
9ab1ac14 328static struct ctl_table spl_kmem_table[] = {
9eb361aa 329#ifdef DEBUG_KMEM
57d1b188 330 {
57d1b188 331 .procname = "kmem_used",
332 .data = &kmem_alloc_used,
d04c8a56 333# ifdef HAVE_ATOMIC64_T
57d1b188 334 .maxlen = sizeof(atomic64_t),
d04c8a56
BB
335# else
336 .maxlen = sizeof(atomic_t),
337# endif /* HAVE_ATOMIC64_T */
57d1b188 338 .mode = 0444,
d04c8a56 339 .proc_handler = &proc_domemused,
57d1b188 340 },
341 {
57d1b188 342 .procname = "kmem_max",
343 .data = &kmem_alloc_max,
344 .maxlen = sizeof(unsigned long),
345 .extra1 = &table_min,
346 .extra2 = &table_max,
347 .mode = 0444,
348 .proc_handler = &proc_doulongvec_minmax,
349 },
9eb361aa 350#endif /* DEBUG_KMEM */
3336e29c 351 {
3336e29c
BB
352 .procname = "slab_kmem_total",
353 .data = (void *)(KMC_KMEM | KMC_TOTAL),
354 .maxlen = sizeof(unsigned long),
355 .extra1 = &table_min,
356 .extra2 = &table_max,
357 .mode = 0444,
358 .proc_handler = &proc_doslab,
359 },
360 {
3336e29c
BB
361 .procname = "slab_kmem_alloc",
362 .data = (void *)(KMC_KMEM | KMC_ALLOC),
363 .maxlen = sizeof(unsigned long),
364 .extra1 = &table_min,
365 .extra2 = &table_max,
366 .mode = 0444,
367 .proc_handler = &proc_doslab,
368 },
369 {
3336e29c
BB
370 .procname = "slab_kmem_max",
371 .data = (void *)(KMC_KMEM | KMC_MAX),
372 .maxlen = sizeof(unsigned long),
373 .extra1 = &table_min,
374 .extra2 = &table_max,
375 .mode = 0444,
376 .proc_handler = &proc_doslab,
377 },
378 {
3336e29c
BB
379 .procname = "slab_vmem_total",
380 .data = (void *)(KMC_VMEM | KMC_TOTAL),
381 .maxlen = sizeof(unsigned long),
382 .extra1 = &table_min,
383 .extra2 = &table_max,
384 .mode = 0444,
385 .proc_handler = &proc_doslab,
386 },
387 {
3336e29c
BB
388 .procname = "slab_vmem_alloc",
389 .data = (void *)(KMC_VMEM | KMC_ALLOC),
390 .maxlen = sizeof(unsigned long),
391 .extra1 = &table_min,
392 .extra2 = &table_max,
393 .mode = 0444,
394 .proc_handler = &proc_doslab,
395 },
396 {
3336e29c
BB
397 .procname = "slab_vmem_max",
398 .data = (void *)(KMC_VMEM | KMC_MAX),
399 .maxlen = sizeof(unsigned long),
400 .extra1 = &table_min,
401 .extra2 = &table_max,
402 .mode = 0444,
403 .proc_handler = &proc_doslab,
404 },
9ab1ac14 405 {0},
406};
04a479f7 407
04a479f7 408static struct ctl_table spl_kstat_table[] = {
409 {0},
410};
9ab1ac14 411
412static struct ctl_table spl_table[] = {
413 /* NB No .strategy entries have been provided since
414 * sysctl(8) prefers to go via /proc for portability.
415 */
416 {
9ab1ac14 417 .procname = "version",
418 .data = spl_version,
419 .maxlen = sizeof(spl_version),
420 .mode = 0444,
421 .proc_handler = &proc_dostring,
422 },
57d1b188 423 {
57d1b188 424 .procname = "hostid",
425 .data = &spl_hostid,
426 .maxlen = sizeof(unsigned long),
427 .mode = 0644,
428 .proc_handler = &proc_dohostid,
429 },
9ab1ac14 430 {
9ab1ac14 431 .procname = "kmem",
432 .mode = 0555,
433 .child = spl_kmem_table,
434 },
04a479f7 435 {
04a479f7 436 .procname = "kstat",
437 .mode = 0555,
438 .child = spl_kstat_table,
439 },
57d1b188 440 { 0 },
441};
442
9ab1ac14 443static struct ctl_table spl_dir[] = {
57d1b188 444 {
57d1b188 445 .procname = "spl",
446 .mode = 0555,
447 .child = spl_table,
448 },
57d86234 449 { 0 }
450};
451
452static struct ctl_table spl_root[] = {
453 {
9c91800d
BB
454#ifdef HAVE_CTL_NAME
455 .ctl_name = CTL_KERN,
456#endif
57d86234 457 .procname = "kernel",
458 .mode = 0555,
459 .child = spl_dir,
460 },
461 { 0 }
57d1b188 462};
463
464int
1114ae6a 465spl_proc_init(void)
57d1b188 466{
404992e3 467 int rc = 0;
57d1b188 468
b38bf6a4 469 spl_header = register_sysctl_table(spl_root);
57d1b188 470 if (spl_header == NULL)
8d9a23e8 471 return (-EUNATCH);
9ab1ac14 472
c30df9c8 473 proc_spl = proc_mkdir("spl", NULL);
8d9a23e8
BB
474 if (proc_spl == NULL) {
475 rc = -EUNATCH;
476 goto out;
477 }
404992e3 478
c30df9c8 479 proc_spl_kmem = proc_mkdir("kmem", proc_spl);
8d9a23e8
BB
480 if (proc_spl_kmem == NULL) {
481 rc = -EUNATCH;
482 goto out;
483 }
ff449ac4 484
f2a745c4
RY
485 proc_spl_kmem_slab = proc_create_data("slab", 0444,
486 proc_spl_kmem, &proc_slab_operations, NULL);
8d9a23e8
BB
487 if (proc_spl_kmem_slab == NULL) {
488 rc = -EUNATCH;
489 goto out;
490 }
ff449ac4 491
c30df9c8 492 proc_spl_kstat = proc_mkdir("kstat", proc_spl);
8d9a23e8
BB
493 if (proc_spl_kstat == NULL) {
494 rc = -EUNATCH;
495 goto out;
496 }
404992e3 497out:
c30df9c8 498 if (rc) {
499 remove_proc_entry("kstat", proc_spl);
ff449ac4 500 remove_proc_entry("slab", proc_spl_kmem);
c30df9c8 501 remove_proc_entry("kmem", proc_spl);
a02118a8 502 remove_proc_entry("spl", NULL);
b38bf6a4 503 unregister_sysctl_table(spl_header);
c30df9c8 504 }
c30df9c8 505
8d9a23e8 506 return (rc);
57d1b188 507}
508
509void
1114ae6a 510spl_proc_fini(void)
57d1b188 511{
c30df9c8 512 remove_proc_entry("kstat", proc_spl);
ff449ac4 513 remove_proc_entry("slab", proc_spl_kmem);
c30df9c8 514 remove_proc_entry("kmem", proc_spl);
a02118a8 515 remove_proc_entry("spl", NULL);
c30df9c8 516
57d1b188 517 ASSERT(spl_header != NULL);
b38bf6a4 518 unregister_sysctl_table(spl_header);
57d1b188 519}