Whamcloud - gitweb
7612c60e9f9f5fcd0932d12416033a72f761b856
[fs/lustre-release.git] / libcfs / libcfs / linux / linux-proc.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  *
30  * Copyright (c) 2011, Whamcloud, Inc.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  *
36  * libcfs/libcfs/linux/linux-proc.c
37  *
38  * Author: Zach Brown <zab@zabbo.net>
39  * Author: Peter J. Braam <braam@clusterfs.com>
40  * Author: Phil Schwan <phil@clusterfs.com>
41  */
42
43 #ifndef AUTOCONF_INCLUDED
44 #include <linux/config.h>
45 #endif
46 #include <linux/module.h>
47 #include <linux/kernel.h>
48 #include <linux/mm.h>
49 #include <linux/string.h>
50 #include <linux/stat.h>
51 #include <linux/errno.h>
52 #include <linux/smp_lock.h>
53 #include <linux/unistd.h>
54 #include <net/sock.h>
55 #include <linux/uio.h>
56
57 #include <asm/system.h>
58 #include <asm/uaccess.h>
59
60 #include <linux/fs.h>
61 #include <linux/file.h>
62 #include <linux/stat.h>
63 #include <linux/list.h>
64 #include <asm/uaccess.h>
65
66 #include <linux/proc_fs.h>
67 #include <linux/sysctl.h>
68
69 # define DEBUG_SUBSYSTEM S_LNET
70
71 #include <libcfs/libcfs.h>
72 #include <asm/div64.h>
73 #include "tracefile.h"
74
75 #ifdef CONFIG_SYSCTL
76 static cfs_sysctl_table_header_t *lnet_table_header = NULL;
77 #endif
78 extern char lnet_upcall[1024];
79 /**
80  * The path of debug log dump upcall script.
81  */
82 extern char lnet_debug_log_upcall[1024];
83
84 #ifndef HAVE_SYSCTL_UNNUMBERED
85 #define CTL_LNET        (0x100)
86 enum {
87         PSDEV_DEBUG = 1,          /* control debugging */
88         PSDEV_SUBSYSTEM_DEBUG,    /* control debugging */
89         PSDEV_PRINTK,             /* force all messages to console */
90         PSDEV_CONSOLE_RATELIMIT,  /* ratelimit console messages */
91         PSDEV_CONSOLE_MAX_DELAY_CS, /* maximum delay over which we skip messages */
92         PSDEV_CONSOLE_MIN_DELAY_CS, /* initial delay over which we skip messages */
93         PSDEV_CONSOLE_BACKOFF,    /* delay increase factor */
94         PSDEV_DEBUG_PATH,         /* crashdump log location */
95         PSDEV_DEBUG_DUMP_PATH,    /* crashdump tracelog location */
96         PSDEV_CPT_TABLE,          /* information about cpu partitions */
97         PSDEV_LNET_UPCALL,        /* User mode upcall script  */
98         PSDEV_LNET_MEMUSED,       /* bytes currently PORTAL_ALLOCated */
99         PSDEV_LNET_CATASTROPHE,   /* if we have LBUGged or panic'd */
100         PSDEV_LNET_PANIC_ON_LBUG, /* flag to panic on LBUG */
101         PSDEV_LNET_DUMP_KERNEL,   /* snapshot kernel debug buffer to file */
102         PSDEV_LNET_DAEMON_FILE,   /* spool kernel debug buffer to file */
103         PSDEV_LNET_DEBUG_MB,      /* size of debug buffer */
104         PSDEV_LNET_DEBUG_LOG_UPCALL, /* debug log upcall script */
105         PSDEV_LNET_WATCHDOG_RATELIMIT,  /* ratelimit watchdog messages  */
106         PSDEV_LNET_FORCE_LBUG,    /* hook to force an LBUG */
107         PSDEV_LNET_FAIL_LOC,      /* control test failures instrumentation */
108         PSDEV_LNET_FAIL_VAL,      /* userdata for fail loc */
109 };
110 #else
111 #define CTL_LNET                        CTL_UNNUMBERED
112 #define PSDEV_DEBUG                     CTL_UNNUMBERED
113 #define PSDEV_SUBSYSTEM_DEBUG           CTL_UNNUMBERED
114 #define PSDEV_PRINTK                    CTL_UNNUMBERED
115 #define PSDEV_CONSOLE_RATELIMIT         CTL_UNNUMBERED
116 #define PSDEV_CONSOLE_MAX_DELAY_CS      CTL_UNNUMBERED
117 #define PSDEV_CONSOLE_MIN_DELAY_CS      CTL_UNNUMBERED
118 #define PSDEV_CONSOLE_BACKOFF           CTL_UNNUMBERED
119 #define PSDEV_DEBUG_PATH                CTL_UNNUMBERED
120 #define PSDEV_DEBUG_DUMP_PATH           CTL_UNNUMBERED
121 #define PSDEV_CPT_TABLE                 CTL_UNNUMBERED
122 #define PSDEV_LNET_UPCALL               CTL_UNNUMBERED
123 #define PSDEV_LNET_MEMUSED              CTL_UNNUMBERED
124 #define PSDEV_LNET_CATASTROPHE          CTL_UNNUMBERED
125 #define PSDEV_LNET_PANIC_ON_LBUG        CTL_UNNUMBERED
126 #define PSDEV_LNET_DUMP_KERNEL          CTL_UNNUMBERED
127 #define PSDEV_LNET_DAEMON_FILE          CTL_UNNUMBERED
128 #define PSDEV_LNET_DEBUG_MB             CTL_UNNUMBERED
129 #define PSDEV_LNET_DEBUG_LOG_UPCALL     CTL_UNNUMBERED
130 #define PSDEV_LNET_WATCHDOG_RATELIMIT   CTL_UNNUMBERED
131 #define PSDEV_LNET_FORCE_LBUG           CTL_UNNUMBERED
132 #define PSDEV_LNET_FAIL_LOC             CTL_UNNUMBERED
133 #define PSDEV_LNET_FAIL_VAL             CTL_UNNUMBERED
134 #endif
135
136 int
137 proc_call_handler(void *data, int write,
138                   loff_t *ppos, void *buffer, size_t *lenp,
139                   int (*handler)(void *data, int write,
140                                  loff_t pos, void *buffer, int len))
141 {
142         int rc = handler(data, write, *ppos, buffer, *lenp);
143
144         if (rc < 0)
145                 return rc;
146
147         if (write) {
148                 *ppos += *lenp;
149         } else {
150                 *lenp = rc;
151                 *ppos += rc;
152         }
153         return 0;
154 }
155 EXPORT_SYMBOL(proc_call_handler);
156
157 static int __proc_dobitmasks(void *data, int write,
158                              loff_t pos, void *buffer, int nob)
159 {
160         const int     tmpstrlen = 512;
161         char         *tmpstr;
162         int           rc;
163         unsigned int *mask = data;
164         int           is_subsys = (mask == &libcfs_subsystem_debug) ? 1 : 0;
165         int           is_printk = (mask == &libcfs_printk) ? 1 : 0;
166
167         rc = cfs_trace_allocate_string_buffer(&tmpstr, tmpstrlen);
168         if (rc < 0)
169                 return rc;
170
171         if (!write) {
172                 libcfs_debug_mask2str(tmpstr, tmpstrlen, *mask, is_subsys);
173                 rc = strlen(tmpstr);
174
175                 if (pos >= rc) {
176                         rc = 0;
177                 } else {
178                         rc = cfs_trace_copyout_string(buffer, nob,
179                                                       tmpstr + pos, "\n");
180                 }
181         } else {
182                 rc = cfs_trace_copyin_string(tmpstr, tmpstrlen, buffer, nob);
183                 if (rc < 0)
184                         return rc;
185
186                 rc = libcfs_debug_str2mask(mask, tmpstr, is_subsys);
187                 /* Always print LBUG/LASSERT to console, so keep this mask */
188                 if (is_printk)
189                         *mask |= D_EMERG;
190         }
191
192         cfs_trace_free_string_buffer(tmpstr, tmpstrlen);
193         return rc;
194 }
195
196 DECLARE_PROC_HANDLER(proc_dobitmasks)
197
198 static int min_watchdog_ratelimit = 0;          /* disable ratelimiting */
199 static int max_watchdog_ratelimit = (24*60*60); /* limit to once per day */
200
201 static int __proc_dump_kernel(void *data, int write,
202                               loff_t pos, void *buffer, int nob)
203 {
204         if (!write)
205                 return 0;
206
207         return cfs_trace_dump_debug_buffer_usrstr(buffer, nob);
208 }
209
210 DECLARE_PROC_HANDLER(proc_dump_kernel)
211
212 static int __proc_daemon_file(void *data, int write,
213                               loff_t pos, void *buffer, int nob)
214 {
215         if (!write) {
216                 int len = strlen(cfs_tracefile);
217
218                 if (pos >= len)
219                         return 0;
220
221                 return cfs_trace_copyout_string(buffer, nob,
222                                                 cfs_tracefile + pos, "\n");
223         }
224
225         return cfs_trace_daemon_command_usrstr(buffer, nob);
226 }
227
228 DECLARE_PROC_HANDLER(proc_daemon_file)
229
230 static int __proc_debug_mb(void *data, int write,
231                            loff_t pos, void *buffer, int nob)
232 {
233         if (!write) {
234                 char tmpstr[32];
235                 int  len = snprintf(tmpstr, sizeof(tmpstr), "%d",
236                                     cfs_trace_get_debug_mb());
237
238                 if (pos >= len)
239                         return 0;
240
241                 return cfs_trace_copyout_string(buffer, nob, tmpstr + pos,
242                        "\n");
243         }
244
245         return cfs_trace_set_debug_mb_usrstr(buffer, nob);
246 }
247
248 DECLARE_PROC_HANDLER(proc_debug_mb)
249
250 int LL_PROC_PROTO(proc_console_max_delay_cs)
251 {
252         int rc, max_delay_cs;
253         cfs_sysctl_table_t dummy = *table;
254         cfs_duration_t d;
255
256         dummy.data = &max_delay_cs;
257         dummy.proc_handler = &proc_dointvec;
258
259         if (!write) { /* read */
260                 max_delay_cs = cfs_duration_sec(libcfs_console_max_delay * 100);
261                 rc = ll_proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
262                 return rc;
263         }
264
265         /* write */
266         max_delay_cs = 0;
267         rc = ll_proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
268         if (rc < 0)
269                 return rc;
270         if (max_delay_cs <= 0)
271                 return -EINVAL;
272
273         d = cfs_time_seconds(max_delay_cs) / 100;
274         if (d == 0 || d < libcfs_console_min_delay)
275                 return -EINVAL;
276         libcfs_console_max_delay = d;
277
278         return rc;
279 }
280
281 int LL_PROC_PROTO(proc_console_min_delay_cs)
282 {
283         int rc, min_delay_cs;
284         cfs_sysctl_table_t dummy = *table;
285         cfs_duration_t d;
286
287         dummy.data = &min_delay_cs;
288         dummy.proc_handler = &proc_dointvec;
289
290         if (!write) { /* read */
291                 min_delay_cs = cfs_duration_sec(libcfs_console_min_delay * 100);
292                 rc = ll_proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
293                 return rc;
294         }
295
296         /* write */
297         min_delay_cs = 0;
298         rc = ll_proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
299         if (rc < 0)
300                 return rc;
301         if (min_delay_cs <= 0)
302                 return -EINVAL;
303
304         d = cfs_time_seconds(min_delay_cs) / 100;
305         if (d == 0 || d > libcfs_console_max_delay)
306                 return -EINVAL;
307         libcfs_console_min_delay = d;
308
309         return rc;
310 }
311
312 int LL_PROC_PROTO(proc_console_backoff)
313 {
314         int rc, backoff;
315         cfs_sysctl_table_t dummy = *table;
316
317         dummy.data = &backoff;
318         dummy.proc_handler = &proc_dointvec;
319
320         if (!write) { /* read */
321                 backoff= libcfs_console_backoff;
322                 rc = ll_proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
323                 return rc;
324         }
325
326         /* write */
327         backoff = 0;
328         rc = ll_proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
329         if (rc < 0)
330                 return rc;
331         if (backoff <= 0)
332                 return -EINVAL;
333
334         libcfs_console_backoff = backoff;
335
336         return rc;
337 }
338
339 int LL_PROC_PROTO(libcfs_force_lbug)
340 {
341         if (write)
342                 LBUG();
343         return 0;
344 }
345
346 int LL_PROC_PROTO(proc_fail_loc)
347 {
348         int rc;
349         long old_fail_loc = cfs_fail_loc;
350
351         rc = ll_proc_dolongvec(table, write, filp, buffer, lenp, ppos);
352         if (old_fail_loc != cfs_fail_loc)
353                 cfs_waitq_signal(&cfs_race_waitq);
354         return rc;
355 }
356
357 static int __proc_cpt_table(void *data, int write,
358                             loff_t pos, void *buffer, int nob)
359 {
360         char *buf = NULL;
361         int   len = 4096;
362         int   rc  = 0;
363
364         if (write)
365                 return -EPERM;
366
367         LASSERT(cfs_cpt_table != NULL);
368
369         while (1) {
370                 LIBCFS_ALLOC(buf, len);
371                 if (buf == NULL)
372                         return -ENOMEM;
373
374                 rc = cfs_cpt_table_print(cfs_cpt_table, buf, len);
375                 if (rc >= 0)
376                         break;
377
378                 LIBCFS_FREE(buf, len);
379                 if (rc == -EFBIG) {
380                         len <<= 1;
381                         continue;
382                 }
383                 goto out;
384         }
385
386         if (pos >= rc) {
387                 rc = 0;
388                 goto out;
389         }
390
391         rc = cfs_trace_copyout_string(buffer, nob, buf + pos, NULL);
392  out:
393         if (buf != NULL)
394                 LIBCFS_FREE(buf, len);
395         return rc;
396 }
397 DECLARE_PROC_HANDLER(proc_cpt_table)
398
399 static cfs_sysctl_table_t lnet_table[] = {
400         /*
401          * NB No .strategy entries have been provided since sysctl(8) prefers
402          * to go via /proc for portability.
403          */
404         {
405                 INIT_CTL_NAME(PSDEV_DEBUG)
406                 .procname = "debug",
407                 .data     = &libcfs_debug,
408                 .maxlen   = sizeof(int),
409                 .mode     = 0644,
410                 .proc_handler = &proc_dobitmasks,
411         },
412         {
413                 INIT_CTL_NAME(PSDEV_SUBSYSTEM_DEBUG)
414                 .procname = "subsystem_debug",
415                 .data     = &libcfs_subsystem_debug,
416                 .maxlen   = sizeof(int),
417                 .mode     = 0644,
418                 .proc_handler = &proc_dobitmasks,
419         },
420         {
421                 INIT_CTL_NAME(PSDEV_PRINTK)
422                 .procname = "printk",
423                 .data     = &libcfs_printk,
424                 .maxlen   = sizeof(int),
425                 .mode     = 0644,
426                 .proc_handler = &proc_dobitmasks,
427         },
428         {
429                 INIT_CTL_NAME(PSDEV_CONSOLE_RATELIMIT)
430                 .procname = "console_ratelimit",
431                 .data     = &libcfs_console_ratelimit,
432                 .maxlen   = sizeof(int),
433                 .mode     = 0644,
434                 .proc_handler = &proc_dointvec
435         },
436         {
437                 INIT_CTL_NAME(PSDEV_CONSOLE_MAX_DELAY_CS)
438                 .procname = "console_max_delay_centisecs",
439                 .maxlen   = sizeof(int),
440                 .mode     = 0644,
441                 .proc_handler = &proc_console_max_delay_cs
442         },
443         {
444                 INIT_CTL_NAME(PSDEV_CONSOLE_MIN_DELAY_CS)
445                 .procname = "console_min_delay_centisecs",
446                 .maxlen   = sizeof(int),
447                 .mode     = 0644,
448                 .proc_handler = &proc_console_min_delay_cs
449         },
450         {
451                 INIT_CTL_NAME(PSDEV_CONSOLE_BACKOFF)
452                 .procname = "console_backoff",
453                 .maxlen   = sizeof(int),
454                 .mode     = 0644,
455                 .proc_handler = &proc_console_backoff
456         },
457
458         {
459                 INIT_CTL_NAME(PSDEV_DEBUG_PATH)
460                 .procname = "debug_path",
461                 .data     = libcfs_debug_file_path_arr,
462                 .maxlen   = sizeof(libcfs_debug_file_path_arr),
463                 .mode     = 0644,
464                 .proc_handler = &proc_dostring,
465         },
466
467         {
468                 .ctl_name = PSDEV_CPT_TABLE,
469                 .procname = "cpu_partition_table",
470                 .maxlen   = 128,
471                 .mode     = 0444,
472                 .proc_handler = &proc_cpt_table,
473         },
474
475         {
476                 INIT_CTL_NAME(PSDEV_LNET_UPCALL)
477                 .procname = "upcall",
478                 .data     = lnet_upcall,
479                 .maxlen   = sizeof(lnet_upcall),
480                 .mode     = 0644,
481                 .proc_handler = &proc_dostring,
482         },
483         {
484                 INIT_CTL_NAME(PSDEV_LNET_DEBUG_LOG_UPCALL)
485                 .procname = "debug_log_upcall",
486                 .data     = lnet_debug_log_upcall,
487                 .maxlen   = sizeof(lnet_debug_log_upcall),
488                 .mode     = 0644,
489                 .proc_handler = &proc_dostring,
490         },
491         {
492                 INIT_CTL_NAME(PSDEV_LNET_MEMUSED)
493                 .procname = "lnet_memused",
494                 .data     = (int *)&libcfs_kmemory.counter,
495                 .maxlen   = sizeof(int),
496                 .mode     = 0444,
497                 .proc_handler = &proc_dointvec,
498                 INIT_STRATEGY(&sysctl_intvec)
499         },
500         {
501                 INIT_CTL_NAME(PSDEV_LNET_CATASTROPHE)
502                 .procname = "catastrophe",
503                 .data     = &libcfs_catastrophe,
504                 .maxlen   = sizeof(int),
505                 .mode     = 0444,
506                 .proc_handler = &proc_dointvec,
507                 INIT_STRATEGY(&sysctl_intvec)
508         },
509         {
510                 INIT_CTL_NAME(PSDEV_LNET_PANIC_ON_LBUG)
511                 .procname = "panic_on_lbug",
512                 .data     = &libcfs_panic_on_lbug,
513                 .maxlen   = sizeof(int),
514                 .mode     = 0644,
515                 .proc_handler = &proc_dointvec,
516                 INIT_STRATEGY(&sysctl_intvec)
517         },
518         {
519                 INIT_CTL_NAME(PSDEV_LNET_DUMP_KERNEL)
520                 .procname = "dump_kernel",
521                 .maxlen   = 256,
522                 .mode     = 0200,
523                 .proc_handler = &proc_dump_kernel,
524         },
525         {
526                 INIT_CTL_NAME(PSDEV_LNET_DAEMON_FILE)
527                 .procname = "daemon_file",
528                 .mode     = 0644,
529                 .maxlen   = 256,
530                 .proc_handler = &proc_daemon_file,
531         },
532         {
533                 INIT_CTL_NAME(PSDEV_LNET_DEBUG_MB)
534                 .procname = "debug_mb",
535                 .mode     = 0644,
536                 .proc_handler = &proc_debug_mb,
537         },
538         {
539                 INIT_CTL_NAME(PSDEV_LNET_WATCHDOG_RATELIMIT)
540                 .procname = "watchdog_ratelimit",
541                 .data     = &libcfs_watchdog_ratelimit,
542                 .maxlen   = sizeof(int),
543                 .mode     = 0644,
544                 .proc_handler = &proc_dointvec_minmax,
545                 .extra1   = &min_watchdog_ratelimit,
546                 .extra2   = &max_watchdog_ratelimit,
547         },
548         {       INIT_CTL_NAME(PSDEV_LNET_FORCE_LBUG)
549                 .procname = "force_lbug",
550                 .data     = NULL,
551                 .maxlen   = 0,
552                 .mode     = 0200,
553                 .proc_handler = &libcfs_force_lbug
554         },
555         {
556                 INIT_CTL_NAME(PSDEV_LNET_FAIL_LOC)
557                 .procname = "fail_loc",
558                 .data     = &cfs_fail_loc,
559                 .maxlen   = sizeof(cfs_fail_loc),
560                 .mode     = 0644,
561                 .proc_handler = &proc_fail_loc
562         },
563         {
564                 INIT_CTL_NAME(PSDEV_LNET_FAIL_VAL)
565                 .procname = "fail_val",
566                 .data     = &cfs_fail_val,
567                 .maxlen   = sizeof(int),
568                 .mode     = 0644,
569                 .proc_handler = &proc_dointvec
570         },
571         {
572                 INIT_CTL_NAME(0)
573         }
574 };
575
576 #ifdef CONFIG_SYSCTL
577 static cfs_sysctl_table_t top_table[] = {
578         {
579                 INIT_CTL_NAME(CTL_LNET)
580                 .procname = "lnet",
581                 .mode     = 0555,
582                 .data     = NULL,
583                 .maxlen   = 0,
584                 .child    = lnet_table,
585         },
586         {
587                 INIT_CTL_NAME(0)
588         }
589 };
590
591 int insert_proc(void)
592 {
593         if (lnet_table_header == NULL)
594                 lnet_table_header = cfs_register_sysctl_table(top_table, 0);
595 #endif
596         return 0;
597 }
598
599 void remove_proc(void)
600 {
601 #ifdef CONFIG_SYSCTL
602         if (lnet_table_header != NULL)
603                 cfs_unregister_sysctl_table(lnet_table_header);
604
605         lnet_table_header = NULL;
606 #endif
607 }