]>
Commit | Line | Data |
---|---|---|
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> | |
29 | #include <linux/kmod.h> | |
30 | #include <linux/seq_file.h> | |
31 | #include <linux/proc_compat.h> | |
e3c4d448 | 32 | #include <linux/version.h> |
55abb092 | 33 | #include <spl-debug.h> |
57d1b188 | 34 | |
b17edc10 BB |
35 | #ifdef SS_DEBUG_SUBSYS |
36 | #undef SS_DEBUG_SUBSYS | |
57d1b188 | 37 | #endif |
38 | ||
b17edc10 | 39 | #define SS_DEBUG_SUBSYS SS_PROC |
57d1b188 | 40 | |
e3c4d448 RY |
41 | #if defined(CONSTIFY_PLUGIN) && LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0) |
42 | typedef struct ctl_table __no_const spl_ctl_table; | |
43 | #else | |
44 | typedef struct ctl_table spl_ctl_table; | |
45 | #endif | |
46 | ||
404992e3 | 47 | #ifdef DEBUG_KMEM |
57d1b188 | 48 | static unsigned long table_min = 0; |
49 | static unsigned long table_max = ~0; | |
404992e3 | 50 | #endif |
51 | ||
404992e3 | 52 | static struct ctl_table_header *spl_header = NULL; |
c30df9c8 | 53 | static struct proc_dir_entry *proc_spl = NULL; |
04a479f7 | 54 | #ifdef DEBUG_KMEM |
c30df9c8 | 55 | static struct proc_dir_entry *proc_spl_kmem = NULL; |
ff449ac4 | 56 | static struct proc_dir_entry *proc_spl_kmem_slab = NULL; |
c30df9c8 | 57 | #endif /* DEBUG_KMEM */ |
c30df9c8 | 58 | struct proc_dir_entry *proc_spl_kstat = NULL; |
57d1b188 | 59 | |
57d1b188 | 60 | static int |
61 | proc_copyin_string(char *kbuffer, int kbuffer_size, | |
62 | const char *ubuffer, int ubuffer_size) | |
63 | { | |
64 | int size; | |
65 | ||
66 | if (ubuffer_size > kbuffer_size) | |
67 | return -EOVERFLOW; | |
68 | ||
69 | if (copy_from_user((void *)kbuffer, (void *)ubuffer, ubuffer_size)) | |
70 | return -EFAULT; | |
71 | ||
72 | /* strip trailing whitespace */ | |
73 | size = strnlen(kbuffer, ubuffer_size); | |
74 | while (size-- >= 0) | |
75 | if (!isspace(kbuffer[size])) | |
76 | break; | |
77 | ||
78 | /* empty string */ | |
79 | if (size < 0) | |
80 | return -EINVAL; | |
81 | ||
82 | /* no space to terminate */ | |
83 | if (size == kbuffer_size) | |
84 | return -EOVERFLOW; | |
85 | ||
86 | kbuffer[size + 1] = 0; | |
87 | return 0; | |
88 | } | |
89 | ||
90 | static int | |
91 | proc_copyout_string(char *ubuffer, int ubuffer_size, | |
92 | const char *kbuffer, char *append) | |
93 | { | |
94 | /* NB if 'append' != NULL, it's a single character to append to the | |
95 | * copied out string - usually "\n", for /proc entries and | |
96 | * (i.e. a terminating zero byte) for sysctl entries | |
97 | */ | |
98 | int size = MIN(strlen(kbuffer), ubuffer_size); | |
99 | ||
100 | if (copy_to_user(ubuffer, kbuffer, size)) | |
101 | return -EFAULT; | |
102 | ||
103 | if (append != NULL && size < ubuffer_size) { | |
104 | if (copy_to_user(ubuffer + size, append, 1)) | |
105 | return -EFAULT; | |
106 | ||
107 | size++; | |
108 | } | |
109 | ||
110 | return size; | |
111 | } | |
112 | ||
4b2220f0 | 113 | #ifdef DEBUG_LOG |
0fac9c9e BB |
114 | static int |
115 | proc_dobitmasks(struct ctl_table *table, int write, | |
116 | void __user *buffer, size_t *lenp, loff_t *ppos) | |
57d1b188 | 117 | { |
118 | unsigned long *mask = table->data; | |
119 | int is_subsys = (mask == &spl_debug_subsys) ? 1 : 0; | |
120 | int is_printk = (mask == &spl_debug_printk) ? 1 : 0; | |
121 | int size = 512, rc; | |
122 | char *str; | |
b17edc10 | 123 | SENTRY; |
57d1b188 | 124 | |
125 | str = kmem_alloc(size, KM_SLEEP); | |
126 | if (str == NULL) | |
b17edc10 | 127 | SRETURN(-ENOMEM); |
57d1b188 | 128 | |
129 | if (write) { | |
130 | rc = proc_copyin_string(str, size, buffer, *lenp); | |
131 | if (rc < 0) | |
b17edc10 | 132 | SRETURN(rc); |
57d1b188 | 133 | |
134 | rc = spl_debug_str2mask(mask, str, is_subsys); | |
135 | /* Always print BUG/ASSERT to console, so keep this mask */ | |
136 | if (is_printk) | |
b17edc10 | 137 | *mask |= SD_EMERG; |
57d1b188 | 138 | |
139 | *ppos += *lenp; | |
140 | } else { | |
141 | rc = spl_debug_mask2str(str, size, *mask, is_subsys); | |
142 | if (*ppos >= rc) | |
143 | rc = 0; | |
144 | else | |
145 | rc = proc_copyout_string(buffer, *lenp, | |
146 | str + *ppos, "\n"); | |
147 | if (rc >= 0) { | |
148 | *lenp = rc; | |
149 | *ppos += rc; | |
150 | } | |
151 | } | |
152 | ||
153 | kmem_free(str, size); | |
b17edc10 | 154 | SRETURN(rc); |
57d1b188 | 155 | } |
156 | ||
0fac9c9e BB |
157 | static int |
158 | proc_debug_mb(struct ctl_table *table, int write, | |
159 | void __user *buffer, size_t *lenp, loff_t *ppos) | |
57d1b188 | 160 | { |
161 | char str[32]; | |
162 | int rc, len; | |
b17edc10 | 163 | SENTRY; |
57d1b188 | 164 | |
165 | if (write) { | |
166 | rc = proc_copyin_string(str, sizeof(str), buffer, *lenp); | |
167 | if (rc < 0) | |
b17edc10 | 168 | SRETURN(rc); |
57d1b188 | 169 | |
170 | rc = spl_debug_set_mb(simple_strtoul(str, NULL, 0)); | |
171 | *ppos += *lenp; | |
172 | } else { | |
173 | len = snprintf(str, sizeof(str), "%d", spl_debug_get_mb()); | |
174 | if (*ppos >= len) | |
175 | rc = 0; | |
176 | else | |
3977f837 | 177 | rc = proc_copyout_string(buffer,*lenp,str+*ppos,"\n"); |
57d1b188 | 178 | |
179 | if (rc >= 0) { | |
180 | *lenp = rc; | |
181 | *ppos += rc; | |
182 | } | |
183 | } | |
184 | ||
b17edc10 | 185 | SRETURN(rc); |
57d1b188 | 186 | } |
187 | ||
0fac9c9e BB |
188 | static int |
189 | proc_dump_kernel(struct ctl_table *table, int write, | |
190 | void __user *buffer, size_t *lenp, loff_t *ppos) | |
57d1b188 | 191 | { |
b17edc10 | 192 | SENTRY; |
57d1b188 | 193 | |
194 | if (write) { | |
7fea96c0 | 195 | spl_debug_dumplog(0); |
57d1b188 | 196 | *ppos += *lenp; |
197 | } else { | |
198 | *lenp = 0; | |
199 | } | |
200 | ||
b17edc10 | 201 | SRETURN(0); |
57d1b188 | 202 | } |
203 | ||
0fac9c9e BB |
204 | static int |
205 | proc_force_bug(struct ctl_table *table, int write, | |
206 | void __user *buffer, size_t *lenp, loff_t *ppos) | |
57d1b188 | 207 | { |
b17edc10 | 208 | SENTRY; |
57d1b188 | 209 | |
55abb092 BB |
210 | if (write) |
211 | PANIC("Crashing due to forced panic\n"); | |
212 | else | |
57d1b188 | 213 | *lenp = 0; |
57d1b188 | 214 | |
b17edc10 | 215 | SRETURN(0); |
57d1b188 | 216 | } |
217 | ||
0fac9c9e BB |
218 | static int |
219 | proc_console_max_delay_cs(struct ctl_table *table, int write, | |
220 | void __user *buffer, size_t *lenp, loff_t *ppos) | |
57d1b188 | 221 | { |
222 | int rc, max_delay_cs; | |
e3c4d448 | 223 | spl_ctl_table dummy = *table; |
57d1b188 | 224 | long d; |
b17edc10 | 225 | SENTRY; |
57d1b188 | 226 | |
227 | dummy.data = &max_delay_cs; | |
228 | dummy.proc_handler = &proc_dointvec; | |
229 | ||
230 | if (write) { | |
231 | max_delay_cs = 0; | |
0fac9c9e | 232 | rc = proc_dointvec(&dummy, write, buffer, lenp, ppos); |
57d1b188 | 233 | if (rc < 0) |
b17edc10 | 234 | SRETURN(rc); |
57d1b188 | 235 | |
236 | if (max_delay_cs <= 0) | |
b17edc10 | 237 | SRETURN(-EINVAL); |
57d1b188 | 238 | |
239 | d = (max_delay_cs * HZ) / 100; | |
240 | if (d == 0 || d < spl_console_min_delay) | |
b17edc10 | 241 | SRETURN(-EINVAL); |
57d1b188 | 242 | |
243 | spl_console_max_delay = d; | |
244 | } else { | |
245 | max_delay_cs = (spl_console_max_delay * 100) / HZ; | |
0fac9c9e | 246 | rc = proc_dointvec(&dummy, write, buffer, lenp, ppos); |
57d1b188 | 247 | } |
248 | ||
b17edc10 | 249 | SRETURN(rc); |
57d1b188 | 250 | } |
251 | ||
0fac9c9e BB |
252 | static int |
253 | proc_console_min_delay_cs(struct ctl_table *table, int write, | |
254 | void __user *buffer, size_t *lenp, loff_t *ppos) | |
57d1b188 | 255 | { |
256 | int rc, min_delay_cs; | |
e3c4d448 | 257 | spl_ctl_table dummy = *table; |
57d1b188 | 258 | long d; |
b17edc10 | 259 | SENTRY; |
57d1b188 | 260 | |
261 | dummy.data = &min_delay_cs; | |
262 | dummy.proc_handler = &proc_dointvec; | |
263 | ||
264 | if (write) { | |
265 | min_delay_cs = 0; | |
0fac9c9e | 266 | rc = proc_dointvec(&dummy, write, buffer, lenp, ppos); |
57d1b188 | 267 | if (rc < 0) |
b17edc10 | 268 | SRETURN(rc); |
57d1b188 | 269 | |
270 | if (min_delay_cs <= 0) | |
b17edc10 | 271 | SRETURN(-EINVAL); |
57d1b188 | 272 | |
273 | d = (min_delay_cs * HZ) / 100; | |
274 | if (d == 0 || d > spl_console_max_delay) | |
b17edc10 | 275 | SRETURN(-EINVAL); |
57d1b188 | 276 | |
277 | spl_console_min_delay = d; | |
278 | } else { | |
279 | min_delay_cs = (spl_console_min_delay * 100) / HZ; | |
0fac9c9e | 280 | rc = proc_dointvec(&dummy, write, buffer, lenp, ppos); |
57d1b188 | 281 | } |
282 | ||
b17edc10 | 283 | SRETURN(rc); |
57d1b188 | 284 | } |
285 | ||
0fac9c9e BB |
286 | static int |
287 | proc_console_backoff(struct ctl_table *table, int write, | |
288 | void __user *buffer, size_t *lenp, loff_t *ppos) | |
57d1b188 | 289 | { |
290 | int rc, backoff; | |
e3c4d448 | 291 | spl_ctl_table dummy = *table; |
b17edc10 | 292 | SENTRY; |
57d1b188 | 293 | |
294 | dummy.data = &backoff; | |
295 | dummy.proc_handler = &proc_dointvec; | |
296 | ||
297 | if (write) { | |
298 | backoff = 0; | |
0fac9c9e | 299 | rc = proc_dointvec(&dummy, write, buffer, lenp, ppos); |
57d1b188 | 300 | if (rc < 0) |
b17edc10 | 301 | SRETURN(rc); |
57d1b188 | 302 | |
303 | if (backoff <= 0) | |
b17edc10 | 304 | SRETURN(-EINVAL); |
57d1b188 | 305 | |
306 | spl_console_backoff = backoff; | |
307 | } else { | |
308 | backoff = spl_console_backoff; | |
0fac9c9e | 309 | rc = proc_dointvec(&dummy, write, buffer, lenp, ppos); |
57d1b188 | 310 | } |
311 | ||
b17edc10 | 312 | SRETURN(rc); |
57d1b188 | 313 | } |
4b2220f0 | 314 | #endif /* DEBUG_LOG */ |
57d1b188 | 315 | |
c6dc93d6 | 316 | #ifdef DEBUG_KMEM |
0fac9c9e BB |
317 | static int |
318 | proc_domemused(struct ctl_table *table, int write, | |
319 | void __user *buffer, size_t *lenp, loff_t *ppos) | |
57d1b188 | 320 | { |
321 | int rc = 0; | |
322 | unsigned long min = 0, max = ~0, val; | |
e3c4d448 | 323 | spl_ctl_table dummy = *table; |
b17edc10 | 324 | SENTRY; |
57d1b188 | 325 | |
326 | dummy.data = &val; | |
327 | dummy.proc_handler = &proc_dointvec; | |
328 | dummy.extra1 = &min; | |
329 | dummy.extra2 = &max; | |
330 | ||
331 | if (write) { | |
332 | *ppos += *lenp; | |
333 | } else { | |
d04c8a56 | 334 | # ifdef HAVE_ATOMIC64_T |
550f1705 | 335 | val = atomic64_read((atomic64_t *)table->data); |
d04c8a56 BB |
336 | # else |
337 | val = atomic_read((atomic_t *)table->data); | |
338 | # endif /* HAVE_ATOMIC64_T */ | |
0fac9c9e | 339 | rc = proc_doulongvec_minmax(&dummy, write, buffer, lenp, ppos); |
57d1b188 | 340 | } |
341 | ||
b17edc10 | 342 | SRETURN(rc); |
57d1b188 | 343 | } |
3336e29c | 344 | |
0fac9c9e BB |
345 | static int |
346 | proc_doslab(struct ctl_table *table, int write, | |
347 | void __user *buffer, size_t *lenp, loff_t *ppos) | |
3336e29c BB |
348 | { |
349 | int rc = 0; | |
350 | unsigned long min = 0, max = ~0, val = 0, mask; | |
e3c4d448 | 351 | spl_ctl_table dummy = *table; |
3336e29c BB |
352 | spl_kmem_cache_t *skc; |
353 | SENTRY; | |
354 | ||
355 | dummy.data = &val; | |
356 | dummy.proc_handler = &proc_dointvec; | |
357 | dummy.extra1 = &min; | |
358 | dummy.extra2 = &max; | |
359 | ||
360 | if (write) { | |
361 | *ppos += *lenp; | |
362 | } else { | |
363 | down_read(&spl_kmem_cache_sem); | |
364 | mask = (unsigned long)table->data; | |
365 | ||
366 | list_for_each_entry(skc, &spl_kmem_cache_list, skc_list) { | |
367 | ||
368 | /* Only use slabs of the correct kmem/vmem type */ | |
369 | if (!(skc->skc_flags & mask)) | |
370 | continue; | |
371 | ||
372 | /* Sum the specified field for selected slabs */ | |
373 | switch (mask & (KMC_TOTAL | KMC_ALLOC | KMC_MAX)) { | |
374 | case KMC_TOTAL: | |
375 | val += skc->skc_slab_size * skc->skc_slab_total; | |
376 | break; | |
377 | case KMC_ALLOC: | |
378 | val += skc->skc_obj_size * skc->skc_obj_alloc; | |
379 | break; | |
380 | case KMC_MAX: | |
381 | val += skc->skc_obj_size * skc->skc_obj_max; | |
382 | break; | |
383 | } | |
384 | } | |
385 | ||
386 | up_read(&spl_kmem_cache_sem); | |
0fac9c9e | 387 | rc = proc_doulongvec_minmax(&dummy, write, buffer, lenp, ppos); |
3336e29c BB |
388 | } |
389 | ||
390 | SRETURN(rc); | |
391 | } | |
c6dc93d6 | 392 | #endif /* DEBUG_KMEM */ |
57d1b188 | 393 | |
0fac9c9e BB |
394 | static int |
395 | proc_dohostid(struct ctl_table *table, int write, | |
396 | void __user *buffer, size_t *lenp, loff_t *ppos) | |
57d1b188 | 397 | { |
398 | int len, rc = 0; | |
57d1b188 | 399 | char *end, str[32]; |
b17edc10 | 400 | SENTRY; |
57d1b188 | 401 | |
402 | if (write) { | |
0fac9c9e | 403 | /* We can't use proc_doulongvec_minmax() in the write |
c95b308d | 404 | * case here because hostid while a hex value has no |
a0b5ae8a | 405 | * leading 0x which confuses the helper function. */ |
57d1b188 | 406 | rc = proc_copyin_string(str, sizeof(str), buffer, *lenp); |
407 | if (rc < 0) | |
b17edc10 | 408 | SRETURN(rc); |
57d1b188 | 409 | |
fa6f7d8f | 410 | spl_hostid = simple_strtoul(str, &end, 16); |
a0b5ae8a | 411 | if (str == end) |
b17edc10 | 412 | SRETURN(-EINVAL); |
57d1b188 | 413 | |
57d1b188 | 414 | } else { |
c95b308d | 415 | len = snprintf(str, sizeof(str), "%lx", spl_hostid); |
57d1b188 | 416 | if (*ppos >= len) |
417 | rc = 0; | |
418 | else | |
3977f837 | 419 | rc = proc_copyout_string(buffer,*lenp,str+*ppos,"\n"); |
57d1b188 | 420 | |
421 | if (rc >= 0) { | |
422 | *lenp = rc; | |
423 | *ppos += rc; | |
424 | } | |
425 | } | |
426 | ||
b17edc10 | 427 | SRETURN(rc); |
57d1b188 | 428 | } |
429 | ||
ff449ac4 | 430 | #ifdef DEBUG_KMEM |
431 | static void | |
432 | slab_seq_show_headers(struct seq_file *f) | |
433 | { | |
d0a1038f BB |
434 | seq_printf(f, |
435 | "--------------------- cache ----------" | |
436 | "--------------------------------------------- " | |
437 | "----- slab ------ " | |
165f13c3 BB |
438 | "---- object ----- " |
439 | "--- emergency ---\n"); | |
d0a1038f BB |
440 | seq_printf(f, |
441 | "name " | |
442 | " flags size alloc slabsize objsize " | |
443 | "total alloc max " | |
165f13c3 BB |
444 | "total alloc max " |
445 | "dlock alloc max\n"); | |
ff449ac4 | 446 | } |
447 | ||
448 | static int | |
449 | slab_seq_show(struct seq_file *f, void *p) | |
450 | { | |
242f539a | 451 | spl_kmem_cache_t *skc = p; |
ff449ac4 | 452 | |
242f539a | 453 | ASSERT(skc->skc_magic == SKC_MAGIC); |
ff449ac4 | 454 | |
a073aeb0 BB |
455 | /* |
456 | * Backed by Linux slab see /proc/slabinfo. | |
457 | */ | |
458 | if (skc->skc_flags & KMC_SLAB) | |
459 | return (0); | |
460 | ||
242f539a | 461 | spin_lock(&skc->skc_lock); |
d0a1038f BB |
462 | seq_printf(f, "%-36s ", skc->skc_name); |
463 | seq_printf(f, "0x%05lx %9lu %9lu %8u %8u " | |
165f13c3 | 464 | "%5lu %5lu %5lu %5lu %5lu %5lu %5lu %5lu %5lu\n", |
d0a1038f BB |
465 | (long unsigned)skc->skc_flags, |
466 | (long unsigned)(skc->skc_slab_size * skc->skc_slab_total), | |
467 | (long unsigned)(skc->skc_obj_size * skc->skc_obj_alloc), | |
468 | (unsigned)skc->skc_slab_size, | |
469 | (unsigned)skc->skc_obj_size, | |
470 | (long unsigned)skc->skc_slab_total, | |
471 | (long unsigned)skc->skc_slab_alloc, | |
472 | (long unsigned)skc->skc_slab_max, | |
473 | (long unsigned)skc->skc_obj_total, | |
474 | (long unsigned)skc->skc_obj_alloc, | |
e2dcc6e2 | 475 | (long unsigned)skc->skc_obj_max, |
165f13c3 | 476 | (long unsigned)skc->skc_obj_deadlock, |
e2dcc6e2 BB |
477 | (long unsigned)skc->skc_obj_emergency, |
478 | (long unsigned)skc->skc_obj_emergency_max); | |
242f539a BB |
479 | |
480 | spin_unlock(&skc->skc_lock); | |
ff449ac4 | 481 | |
482 | return 0; | |
483 | } | |
484 | ||
485 | static void * | |
486 | slab_seq_start(struct seq_file *f, loff_t *pos) | |
487 | { | |
488 | struct list_head *p; | |
489 | loff_t n = *pos; | |
b17edc10 | 490 | SENTRY; |
ff449ac4 | 491 | |
492 | down_read(&spl_kmem_cache_sem); | |
493 | if (!n) | |
494 | slab_seq_show_headers(f); | |
495 | ||
496 | p = spl_kmem_cache_list.next; | |
497 | while (n--) { | |
498 | p = p->next; | |
499 | if (p == &spl_kmem_cache_list) | |
b17edc10 | 500 | SRETURN(NULL); |
ff449ac4 | 501 | } |
502 | ||
b17edc10 | 503 | SRETURN(list_entry(p, spl_kmem_cache_t, skc_list)); |
ff449ac4 | 504 | } |
505 | ||
506 | static void * | |
507 | slab_seq_next(struct seq_file *f, void *p, loff_t *pos) | |
508 | { | |
509 | spl_kmem_cache_t *skc = p; | |
b17edc10 | 510 | SENTRY; |
ff449ac4 | 511 | |
512 | ++*pos; | |
b17edc10 | 513 | SRETURN((skc->skc_list.next == &spl_kmem_cache_list) ? |
3977f837 | 514 | NULL : list_entry(skc->skc_list.next,spl_kmem_cache_t,skc_list)); |
ff449ac4 | 515 | } |
516 | ||
517 | static void | |
518 | slab_seq_stop(struct seq_file *f, void *v) | |
519 | { | |
520 | up_read(&spl_kmem_cache_sem); | |
521 | } | |
522 | ||
523 | static struct seq_operations slab_seq_ops = { | |
524 | .show = slab_seq_show, | |
525 | .start = slab_seq_start, | |
526 | .next = slab_seq_next, | |
527 | .stop = slab_seq_stop, | |
528 | }; | |
529 | ||
530 | static int | |
531 | proc_slab_open(struct inode *inode, struct file *filp) | |
532 | { | |
533 | return seq_open(filp, &slab_seq_ops); | |
534 | } | |
535 | ||
536 | static struct file_operations proc_slab_operations = { | |
537 | .open = proc_slab_open, | |
538 | .read = seq_read, | |
539 | .llseek = seq_lseek, | |
540 | .release = seq_release, | |
541 | }; | |
542 | #endif /* DEBUG_KMEM */ | |
543 | ||
4b2220f0 | 544 | #ifdef DEBUG_LOG |
9ab1ac14 | 545 | static struct ctl_table spl_debug_table[] = { |
57d1b188 | 546 | { |
9ab1ac14 | 547 | .procname = "subsystem", |
57d1b188 | 548 | .data = &spl_debug_subsys, |
549 | .maxlen = sizeof(unsigned long), | |
550 | .mode = 0644, | |
551 | .proc_handler = &proc_dobitmasks | |
552 | }, | |
553 | { | |
9ab1ac14 | 554 | .procname = "mask", |
57d1b188 | 555 | .data = &spl_debug_mask, |
556 | .maxlen = sizeof(unsigned long), | |
557 | .mode = 0644, | |
558 | .proc_handler = &proc_dobitmasks | |
559 | }, | |
560 | { | |
9ab1ac14 | 561 | .procname = "printk", |
57d1b188 | 562 | .data = &spl_debug_printk, |
563 | .maxlen = sizeof(unsigned long), | |
564 | .mode = 0644, | |
565 | .proc_handler = &proc_dobitmasks | |
566 | }, | |
567 | { | |
9ab1ac14 | 568 | .procname = "mb", |
57d1b188 | 569 | .mode = 0644, |
570 | .proc_handler = &proc_debug_mb, | |
571 | }, | |
572 | { | |
9ab1ac14 | 573 | .procname = "binary", |
57d1b188 | 574 | .data = &spl_debug_binary, |
575 | .maxlen = sizeof(int), | |
576 | .mode = 0644, | |
577 | .proc_handler = &proc_dointvec, | |
578 | }, | |
579 | { | |
57d1b188 | 580 | .procname = "catastrophe", |
581 | .data = &spl_debug_catastrophe, | |
582 | .maxlen = sizeof(int), | |
583 | .mode = 0444, | |
584 | .proc_handler = &proc_dointvec, | |
585 | }, | |
586 | { | |
57d1b188 | 587 | .procname = "panic_on_bug", |
588 | .data = &spl_debug_panic_on_bug, | |
589 | .maxlen = sizeof(int), | |
590 | .mode = 0644, | |
591 | .proc_handler = &proc_dointvec | |
592 | }, | |
593 | { | |
9ab1ac14 | 594 | .procname = "path", |
57d1b188 | 595 | .data = spl_debug_file_path, |
596 | .maxlen = sizeof(spl_debug_file_path), | |
597 | .mode = 0644, | |
598 | .proc_handler = &proc_dostring, | |
599 | }, | |
600 | { | |
9ab1ac14 | 601 | .procname = "dump", |
57d1b188 | 602 | .mode = 0200, |
603 | .proc_handler = &proc_dump_kernel, | |
604 | }, | |
9c91800d | 605 | { |
57d1b188 | 606 | .procname = "force_bug", |
607 | .mode = 0200, | |
608 | .proc_handler = &proc_force_bug, | |
609 | }, | |
610 | { | |
57d1b188 | 611 | .procname = "console_ratelimit", |
612 | .data = &spl_console_ratelimit, | |
613 | .maxlen = sizeof(int), | |
614 | .mode = 0644, | |
615 | .proc_handler = &proc_dointvec, | |
616 | }, | |
617 | { | |
57d1b188 | 618 | .procname = "console_max_delay_centisecs", |
619 | .maxlen = sizeof(int), | |
620 | .mode = 0644, | |
621 | .proc_handler = &proc_console_max_delay_cs, | |
622 | }, | |
623 | { | |
57d1b188 | 624 | .procname = "console_min_delay_centisecs", |
625 | .maxlen = sizeof(int), | |
626 | .mode = 0644, | |
627 | .proc_handler = &proc_console_min_delay_cs, | |
628 | }, | |
629 | { | |
57d1b188 | 630 | .procname = "console_backoff", |
631 | .maxlen = sizeof(int), | |
632 | .mode = 0644, | |
633 | .proc_handler = &proc_console_backoff, | |
634 | }, | |
635 | { | |
57d1b188 | 636 | .procname = "stack_max", |
637 | .data = &spl_debug_stack, | |
638 | .maxlen = sizeof(int), | |
639 | .mode = 0444, | |
640 | .proc_handler = &proc_dointvec, | |
641 | }, | |
9ab1ac14 | 642 | {0}, |
643 | }; | |
4b2220f0 | 644 | #endif /* DEBUG_LOG */ |
9ab1ac14 | 645 | |
57d1b188 | 646 | #ifdef DEBUG_KMEM |
9ab1ac14 | 647 | static struct ctl_table spl_kmem_table[] = { |
57d1b188 | 648 | { |
57d1b188 | 649 | .procname = "kmem_used", |
650 | .data = &kmem_alloc_used, | |
d04c8a56 | 651 | # ifdef HAVE_ATOMIC64_T |
57d1b188 | 652 | .maxlen = sizeof(atomic64_t), |
d04c8a56 BB |
653 | # else |
654 | .maxlen = sizeof(atomic_t), | |
655 | # endif /* HAVE_ATOMIC64_T */ | |
57d1b188 | 656 | .mode = 0444, |
d04c8a56 | 657 | .proc_handler = &proc_domemused, |
57d1b188 | 658 | }, |
659 | { | |
57d1b188 | 660 | .procname = "kmem_max", |
661 | .data = &kmem_alloc_max, | |
662 | .maxlen = sizeof(unsigned long), | |
663 | .extra1 = &table_min, | |
664 | .extra2 = &table_max, | |
665 | .mode = 0444, | |
666 | .proc_handler = &proc_doulongvec_minmax, | |
667 | }, | |
668 | { | |
57d1b188 | 669 | .procname = "vmem_used", |
670 | .data = &vmem_alloc_used, | |
d04c8a56 | 671 | # ifdef HAVE_ATOMIC64_T |
57d1b188 | 672 | .maxlen = sizeof(atomic64_t), |
d04c8a56 BB |
673 | # else |
674 | .maxlen = sizeof(atomic_t), | |
675 | # endif /* HAVE_ATOMIC64_T */ | |
57d1b188 | 676 | .mode = 0444, |
d04c8a56 | 677 | .proc_handler = &proc_domemused, |
57d1b188 | 678 | }, |
679 | { | |
57d1b188 | 680 | .procname = "vmem_max", |
681 | .data = &vmem_alloc_max, | |
682 | .maxlen = sizeof(unsigned long), | |
683 | .extra1 = &table_min, | |
684 | .extra2 = &table_max, | |
685 | .mode = 0444, | |
686 | .proc_handler = &proc_doulongvec_minmax, | |
687 | }, | |
3336e29c | 688 | { |
3336e29c BB |
689 | .procname = "slab_kmem_total", |
690 | .data = (void *)(KMC_KMEM | KMC_TOTAL), | |
691 | .maxlen = sizeof(unsigned long), | |
692 | .extra1 = &table_min, | |
693 | .extra2 = &table_max, | |
694 | .mode = 0444, | |
695 | .proc_handler = &proc_doslab, | |
696 | }, | |
697 | { | |
3336e29c BB |
698 | .procname = "slab_kmem_alloc", |
699 | .data = (void *)(KMC_KMEM | KMC_ALLOC), | |
700 | .maxlen = sizeof(unsigned long), | |
701 | .extra1 = &table_min, | |
702 | .extra2 = &table_max, | |
703 | .mode = 0444, | |
704 | .proc_handler = &proc_doslab, | |
705 | }, | |
706 | { | |
3336e29c BB |
707 | .procname = "slab_kmem_max", |
708 | .data = (void *)(KMC_KMEM | KMC_MAX), | |
709 | .maxlen = sizeof(unsigned long), | |
710 | .extra1 = &table_min, | |
711 | .extra2 = &table_max, | |
712 | .mode = 0444, | |
713 | .proc_handler = &proc_doslab, | |
714 | }, | |
715 | { | |
3336e29c BB |
716 | .procname = "slab_vmem_total", |
717 | .data = (void *)(KMC_VMEM | KMC_TOTAL), | |
718 | .maxlen = sizeof(unsigned long), | |
719 | .extra1 = &table_min, | |
720 | .extra2 = &table_max, | |
721 | .mode = 0444, | |
722 | .proc_handler = &proc_doslab, | |
723 | }, | |
724 | { | |
3336e29c BB |
725 | .procname = "slab_vmem_alloc", |
726 | .data = (void *)(KMC_VMEM | KMC_ALLOC), | |
727 | .maxlen = sizeof(unsigned long), | |
728 | .extra1 = &table_min, | |
729 | .extra2 = &table_max, | |
730 | .mode = 0444, | |
731 | .proc_handler = &proc_doslab, | |
732 | }, | |
733 | { | |
3336e29c BB |
734 | .procname = "slab_vmem_max", |
735 | .data = (void *)(KMC_VMEM | KMC_MAX), | |
736 | .maxlen = sizeof(unsigned long), | |
737 | .extra1 = &table_min, | |
738 | .extra2 = &table_max, | |
739 | .mode = 0444, | |
740 | .proc_handler = &proc_doslab, | |
741 | }, | |
9ab1ac14 | 742 | {0}, |
743 | }; | |
04a479f7 | 744 | #endif /* DEBUG_KMEM */ |
745 | ||
04a479f7 | 746 | static struct ctl_table spl_kstat_table[] = { |
747 | {0}, | |
748 | }; | |
9ab1ac14 | 749 | |
750 | static struct ctl_table spl_table[] = { | |
751 | /* NB No .strategy entries have been provided since | |
752 | * sysctl(8) prefers to go via /proc for portability. | |
753 | */ | |
754 | { | |
9ab1ac14 | 755 | .procname = "version", |
756 | .data = spl_version, | |
757 | .maxlen = sizeof(spl_version), | |
758 | .mode = 0444, | |
759 | .proc_handler = &proc_dostring, | |
760 | }, | |
57d1b188 | 761 | { |
57d1b188 | 762 | .procname = "hostid", |
763 | .data = &spl_hostid, | |
764 | .maxlen = sizeof(unsigned long), | |
765 | .mode = 0644, | |
766 | .proc_handler = &proc_dohostid, | |
767 | }, | |
4b2220f0 | 768 | #ifdef DEBUG_LOG |
9ab1ac14 | 769 | { |
9ab1ac14 | 770 | .procname = "debug", |
771 | .mode = 0555, | |
772 | .child = spl_debug_table, | |
773 | }, | |
4b2220f0 | 774 | #endif |
9ab1ac14 | 775 | #ifdef DEBUG_KMEM |
776 | { | |
9ab1ac14 | 777 | .procname = "kmem", |
778 | .mode = 0555, | |
779 | .child = spl_kmem_table, | |
780 | }, | |
04a479f7 | 781 | #endif |
04a479f7 | 782 | { |
04a479f7 | 783 | .procname = "kstat", |
784 | .mode = 0555, | |
785 | .child = spl_kstat_table, | |
786 | }, | |
57d1b188 | 787 | { 0 }, |
788 | }; | |
789 | ||
9ab1ac14 | 790 | static struct ctl_table spl_dir[] = { |
57d1b188 | 791 | { |
57d1b188 | 792 | .procname = "spl", |
793 | .mode = 0555, | |
794 | .child = spl_table, | |
795 | }, | |
57d86234 | 796 | { 0 } |
797 | }; | |
798 | ||
799 | static struct ctl_table spl_root[] = { | |
800 | { | |
9c91800d BB |
801 | #ifdef HAVE_CTL_NAME |
802 | .ctl_name = CTL_KERN, | |
803 | #endif | |
57d86234 | 804 | .procname = "kernel", |
805 | .mode = 0555, | |
806 | .child = spl_dir, | |
807 | }, | |
808 | { 0 } | |
57d1b188 | 809 | }; |
810 | ||
811 | int | |
1114ae6a | 812 | spl_proc_init(void) |
57d1b188 | 813 | { |
404992e3 | 814 | int rc = 0; |
b17edc10 | 815 | SENTRY; |
57d1b188 | 816 | |
b38bf6a4 | 817 | spl_header = register_sysctl_table(spl_root); |
57d1b188 | 818 | if (spl_header == NULL) |
b17edc10 | 819 | SRETURN(-EUNATCH); |
9ab1ac14 | 820 | |
c30df9c8 | 821 | proc_spl = proc_mkdir("spl", NULL); |
822 | if (proc_spl == NULL) | |
b17edc10 | 823 | SGOTO(out, rc = -EUNATCH); |
404992e3 | 824 | |
04a479f7 | 825 | #ifdef DEBUG_KMEM |
c30df9c8 | 826 | proc_spl_kmem = proc_mkdir("kmem", proc_spl); |
827 | if (proc_spl_kmem == NULL) | |
b17edc10 | 828 | SGOTO(out, rc = -EUNATCH); |
ff449ac4 | 829 | |
f2a745c4 RY |
830 | proc_spl_kmem_slab = proc_create_data("slab", 0444, |
831 | proc_spl_kmem, &proc_slab_operations, NULL); | |
ff449ac4 | 832 | if (proc_spl_kmem_slab == NULL) |
b17edc10 | 833 | SGOTO(out, rc = -EUNATCH); |
ff449ac4 | 834 | |
04a479f7 | 835 | #endif /* DEBUG_KMEM */ |
836 | ||
c30df9c8 | 837 | proc_spl_kstat = proc_mkdir("kstat", proc_spl); |
838 | if (proc_spl_kstat == NULL) | |
b17edc10 | 839 | SGOTO(out, rc = -EUNATCH); |
404992e3 | 840 | out: |
c30df9c8 | 841 | if (rc) { |
842 | remove_proc_entry("kstat", proc_spl); | |
ff449ac4 | 843 | #ifdef DEBUG_KMEM |
844 | remove_proc_entry("slab", proc_spl_kmem); | |
c30df9c8 | 845 | remove_proc_entry("kmem", proc_spl); |
055ffd98 | 846 | #endif |
a02118a8 | 847 | remove_proc_entry("spl", NULL); |
b38bf6a4 | 848 | unregister_sysctl_table(spl_header); |
c30df9c8 | 849 | } |
c30df9c8 | 850 | |
b17edc10 | 851 | SRETURN(rc); |
57d1b188 | 852 | } |
853 | ||
854 | void | |
1114ae6a | 855 | spl_proc_fini(void) |
57d1b188 | 856 | { |
b17edc10 | 857 | SENTRY; |
57d1b188 | 858 | |
c30df9c8 | 859 | remove_proc_entry("kstat", proc_spl); |
ff449ac4 | 860 | #ifdef DEBUG_KMEM |
861 | remove_proc_entry("slab", proc_spl_kmem); | |
c30df9c8 | 862 | remove_proc_entry("kmem", proc_spl); |
055ffd98 | 863 | #endif |
a02118a8 | 864 | remove_proc_entry("spl", NULL); |
c30df9c8 | 865 | |
57d1b188 | 866 | ASSERT(spl_header != NULL); |
b38bf6a4 | 867 | unregister_sysctl_table(spl_header); |
c30df9c8 | 868 | |
b17edc10 | 869 | SEXIT; |
57d1b188 | 870 | } |