Whamcloud - gitweb
Branch HEAD
[fs/lustre-release.git] / lnet / libcfs / linux / linux-proc.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * Copyright (C) 2001, 2002 Cluster File Systems, Inc.
5  *   Author: Zach Brown <zab@zabbo.net>
6  *   Author: Peter J. Braam <braam@clusterfs.com>
7  *   Author: Phil Schwan <phil@clusterfs.com>
8  *
9  *   This file is part of Lustre, http://www.lustre.org.
10  *
11  *   Lustre is free software; you can redistribute it and/or
12  *   modify it under the terms of version 2 of the GNU General Public
13  *   License as published by the Free Software Foundation.
14  *
15  *   Lustre is distributed in the hope that it will be useful,
16  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *   GNU General Public License for more details.
19  *
20  *   You should have received a copy of the GNU General Public License
21  *   along with Lustre; if not, write to the Free Software
22  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23  */
24
25 #ifndef EXPORT_SYMTAB
26 # define EXPORT_SYMTAB
27 #endif
28
29 #ifndef AUTOCONF_INCLUDED
30 #include <linux/config.h>
31 #endif
32 #include <linux/module.h>
33 #include <linux/kernel.h>
34 #include <linux/mm.h>
35 #include <linux/string.h>
36 #include <linux/stat.h>
37 #include <linux/errno.h>
38 #include <linux/smp_lock.h>
39 #include <linux/unistd.h>
40 #include <net/sock.h>
41 #include <linux/uio.h>
42
43 #include <asm/system.h>
44 #include <asm/uaccess.h>
45
46 #include <linux/fs.h>
47 #include <linux/file.h>
48 #include <linux/stat.h>
49 #include <linux/list.h>
50 #include <asm/uaccess.h>
51
52 #include <linux/proc_fs.h>
53 #include <linux/sysctl.h>
54
55 # define DEBUG_SUBSYSTEM S_LNET
56
57 #include <libcfs/kp30.h>
58 #include <asm/div64.h>
59 #include "tracefile.h"
60
61 static cfs_sysctl_table_header_t *lnet_table_header = NULL;
62 extern char lnet_upcall[1024];
63
64 #define PSDEV_LNET  (0x100)
65 enum {
66         PSDEV_DEBUG = 1,          /* control debugging */
67         PSDEV_SUBSYSTEM_DEBUG,    /* control debugging */
68         PSDEV_PRINTK,             /* force all messages to console */
69         PSDEV_CONSOLE_RATELIMIT,  /* ratelimit console messages */
70         PSDEV_CONSOLE_MAX_DELAY_CS, /* maximum delay over which we skip messages */
71         PSDEV_CONSOLE_MIN_DELAY_CS, /* initial delay over which we skip messages */
72         PSDEV_CONSOLE_BACKOFF,    /* delay increase factor */
73         PSDEV_DEBUG_PATH,         /* crashdump log location */
74         PSDEV_DEBUG_DUMP_PATH,    /* crashdump tracelog location */
75         PSDEV_LNET_UPCALL,        /* User mode upcall script  */
76         PSDEV_LNET_MEMUSED,       /* bytes currently PORTAL_ALLOCated */
77         PSDEV_LNET_CATASTROPHE,   /* if we have LBUGged or panic'd */
78         PSDEV_LNET_PANIC_ON_LBUG, /* flag to panic on LBUG */
79         PSDEV_LNET_DUMP_KERNEL,   /* snapshot kernel debug buffer to file */
80         PSDEV_LNET_DAEMON_FILE,   /* spool kernel debug buffer to file */
81         PSDEV_LNET_DEBUG_MB,      /* size of debug buffer */
82 };
83
84 static int 
85 proc_call_handler(void *data, int write, 
86                   loff_t *ppos, void *buffer, size_t *lenp, 
87                   int (*handler)(void *data, int write,
88                                  loff_t pos, void *buffer, int len))
89 {
90         int rc = handler(data, write, *ppos, buffer, *lenp);
91
92         if (rc < 0)
93                 return rc;
94
95         if (write) {
96                 *ppos += *lenp;
97         } else {
98                 *lenp = rc;
99                 *ppos += rc;
100         }
101         return 0;
102 }
103
104 #define DECLARE_PROC_HANDLER(name)                      \
105 static int                                              \
106 LL_PROC_PROTO(name)                                     \
107 {                                                       \
108         DECLARE_LL_PROC_PPOS_DECL;                      \
109                                                         \
110         return proc_call_handler(table->data, write,    \
111                                  ppos, buffer, lenp,    \
112                                  __##name);             \
113 }
114
115 static int __proc_dobitmasks(void *data, int write, 
116                              loff_t pos, void *buffer, int nob)
117 {
118         const int     tmpstrlen = 512;
119         char         *tmpstr;
120         int           rc;
121         unsigned int *mask = data;
122         int           is_subsys = (mask == &libcfs_subsystem_debug) ? 1 : 0;
123         int           is_printk = (mask == &libcfs_printk) ? 1 : 0;
124
125         rc = trace_allocate_string_buffer(&tmpstr, tmpstrlen);
126         if (rc < 0)
127                 return rc;
128
129         if (!write) {
130                 libcfs_debug_mask2str(tmpstr, tmpstrlen, *mask, is_subsys);
131                 rc = strlen(tmpstr);
132
133                 if (pos >= rc) {
134                         rc = 0;
135                 } else {
136                         rc = trace_copyout_string(buffer, nob,
137                                                   tmpstr + pos, "\n");
138                 }
139         } else {
140                 rc = trace_copyin_string(tmpstr, tmpstrlen, buffer, nob);
141                 if (rc < 0)
142                         return rc;
143
144                 rc = libcfs_debug_str2mask(mask, tmpstr, is_subsys);
145                 /* Always print LBUG/LASSERT to console, so keep this mask */
146                 if (is_printk)
147                         *mask |= D_EMERG;
148         }
149
150         trace_free_string_buffer(tmpstr, tmpstrlen);
151         return rc;
152 }
153
154 DECLARE_PROC_HANDLER(proc_dobitmasks)
155
156 static int __proc_dump_kernel(void *data, int write,
157                               loff_t pos, void *buffer, int nob)
158 {
159         if (!write)
160                 return 0;
161         
162         return trace_dump_debug_buffer_usrstr(buffer, nob);
163 }
164
165 DECLARE_PROC_HANDLER(proc_dump_kernel)
166
167 static int __proc_daemon_file(void *data, int write,
168                               loff_t pos, void *buffer, int nob)
169 {
170         if (!write) {
171                 int len = strlen(tracefile);
172                 
173                 if (pos >= len)
174                         return 0;
175                 
176                 return trace_copyout_string(buffer, nob, 
177                                             tracefile + pos, "\n");
178         }
179         
180         return trace_daemon_command_usrstr(buffer, nob);
181 }
182
183 DECLARE_PROC_HANDLER(proc_daemon_file)
184
185 static int __proc_debug_mb(void *data, int write,
186                            loff_t pos, void *buffer, int nob)
187 {
188         if (!write) {
189                 char tmpstr[32];
190                 int  len = snprintf(tmpstr, sizeof(tmpstr), "%d",
191                                     trace_get_debug_mb());
192
193                 if (pos >= len)
194                         return 0;
195                 
196                 return trace_copyout_string(buffer, nob, tmpstr + pos, "\n");
197         }
198         
199         return trace_set_debug_mb_usrstr(buffer, nob);
200 }
201
202 DECLARE_PROC_HANDLER(proc_debug_mb)
203
204 int LL_PROC_PROTO(proc_console_max_delay_cs)
205 {
206         int rc, max_delay_cs;
207         cfs_sysctl_table_t dummy = *table;
208         cfs_duration_t d;
209
210         dummy.data = &max_delay_cs;
211         dummy.proc_handler = &proc_dointvec;
212
213         if (!write) { /* read */
214                 max_delay_cs = cfs_duration_sec(libcfs_console_max_delay * 100);
215                 rc = ll_proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
216                 return rc;
217         }
218
219         /* write */
220         max_delay_cs = 0;
221         rc = ll_proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
222         if (rc < 0)
223                 return rc;
224         if (max_delay_cs <= 0)
225                 return -EINVAL;
226
227         d = cfs_time_seconds(max_delay_cs) / 100;
228         if (d == 0 || d < libcfs_console_min_delay)
229                 return -EINVAL;
230         libcfs_console_max_delay = d;
231
232         return rc;
233 }
234
235 int LL_PROC_PROTO(proc_console_min_delay_cs)
236 {
237         int rc, min_delay_cs;
238         cfs_sysctl_table_t dummy = *table;
239         cfs_duration_t d;
240
241         dummy.data = &min_delay_cs;
242         dummy.proc_handler = &proc_dointvec;
243
244         if (!write) { /* read */
245                 min_delay_cs = cfs_duration_sec(libcfs_console_min_delay * 100);
246                 rc = ll_proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
247                 return rc;
248         }
249
250         /* write */
251         min_delay_cs = 0;
252         rc = ll_proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
253         if (rc < 0)
254                 return rc;
255         if (min_delay_cs <= 0)
256                 return -EINVAL;
257
258         d = cfs_time_seconds(min_delay_cs) / 100;
259         if (d == 0 || d > libcfs_console_max_delay)
260                 return -EINVAL;
261         libcfs_console_min_delay = d;
262
263         return rc;
264 }
265
266 int LL_PROC_PROTO(proc_console_backoff)
267 {
268         int rc, backoff;
269         cfs_sysctl_table_t dummy = *table;
270
271         dummy.data = &backoff;
272         dummy.proc_handler = &proc_dointvec;
273
274         if (!write) { /* read */
275                 backoff= libcfs_console_backoff;
276                 rc = ll_proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
277                 return rc;
278         }
279
280         /* write */
281         backoff = 0;
282         rc = ll_proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
283         if (rc < 0)
284                 return rc;
285         if (backoff <= 0)
286                 return -EINVAL;
287
288         libcfs_console_backoff = backoff;
289
290         return rc;
291 }
292
293 static cfs_sysctl_table_t lnet_table[] = {
294         /*
295          * NB No .strategy entries have been provided since sysctl(8) prefers
296          * to go via /proc for portability.
297          */
298         {
299                 .ctl_name = PSDEV_DEBUG,
300                 .procname = "debug",
301                 .data     = &libcfs_debug,
302                 .maxlen   = sizeof(int),
303                 .mode     = 0644,
304                 .proc_handler = &proc_dobitmasks
305         },
306         {
307                 .ctl_name = PSDEV_SUBSYSTEM_DEBUG,
308                 .procname = "subsystem_debug",
309                 .data     = &libcfs_subsystem_debug,
310                 .maxlen   = sizeof(int),
311                 .mode     = 0644,
312                 .proc_handler = &proc_dobitmasks
313         },
314         {
315                 .ctl_name = PSDEV_PRINTK,
316                 .procname = "printk",
317                 .data     = &libcfs_printk,
318                 .maxlen   = sizeof(int),
319                 .mode     = 0644,
320                 .proc_handler = &proc_dobitmasks
321         },
322         {
323                 .ctl_name = PSDEV_CONSOLE_RATELIMIT,
324                 .procname = "console_ratelimit",
325                 .data     = &libcfs_console_ratelimit,
326                 .maxlen   = sizeof(int),
327                 .mode     = 0644,
328                 .proc_handler = &proc_dointvec
329         },
330         {
331                 .ctl_name = PSDEV_CONSOLE_MAX_DELAY_CS,
332                 .procname = "console_max_delay_centisecs",
333                 .maxlen   = sizeof(int),
334                 .mode     = 0644,
335                 .proc_handler = &proc_console_max_delay_cs
336         },
337         {
338                 .ctl_name = PSDEV_CONSOLE_MIN_DELAY_CS,
339                 .procname = "console_min_delay_centisecs",
340                 .maxlen   = sizeof(int),
341                 .mode     = 0644,
342                 .proc_handler = &proc_console_min_delay_cs
343         },
344         {
345                 .ctl_name = PSDEV_CONSOLE_BACKOFF,
346                 .procname = "console_backoff",
347                 .maxlen   = sizeof(int),
348                 .mode     = 0644,
349                 .proc_handler = &proc_console_backoff
350         },
351
352         {
353                 .ctl_name = PSDEV_DEBUG_PATH,
354                 .procname = "debug_path",
355                 .data     = debug_file_path,
356                 .maxlen   = sizeof(debug_file_path),
357                 .mode     = 0644,
358                 .proc_handler = &proc_dostring,
359         },
360
361         {
362                 .ctl_name = PSDEV_LNET_UPCALL,
363                 .procname = "upcall",
364                 .data     = lnet_upcall,
365                 .maxlen   = sizeof(lnet_upcall),
366                 .mode     = 0644,
367                 .proc_handler = &proc_dostring,
368         },
369         {
370                 .ctl_name = PSDEV_LNET_MEMUSED,
371                 .procname = "memused",
372                 .data     = (int *)&libcfs_kmemory.counter,
373                 .maxlen   = sizeof(int),
374                 .mode     = 0444,
375                 .proc_handler = &proc_dointvec
376         },
377         {
378                 .ctl_name = PSDEV_LNET_CATASTROPHE,
379                 .procname = "catastrophe",
380                 .data     = &libcfs_catastrophe,
381                 .maxlen   = sizeof(int),
382                 .mode     = 0444,
383                 .proc_handler = &proc_dointvec
384         },
385         {
386                 .ctl_name = PSDEV_LNET_PANIC_ON_LBUG,
387                 .procname = "panic_on_lbug",
388                 .data     = &libcfs_panic_on_lbug,
389                 .maxlen   = sizeof(int),
390                 .mode     = 0644,
391                 .proc_handler = &proc_dointvec
392         },
393         {
394                 .ctl_name = PSDEV_LNET_DUMP_KERNEL,
395                 .procname = "dump_kernel",
396                 .mode     = 0200,
397                 .proc_handler = &proc_dump_kernel,
398         },
399         {
400                 .ctl_name = PSDEV_LNET_DAEMON_FILE,
401                 .procname = "daemon_file",
402                 .mode     = 0644,
403                 .proc_handler = &proc_daemon_file,
404         },
405         {
406                 .ctl_name = PSDEV_LNET_DEBUG_MB,
407                 .procname = "debug_mb",
408                 .mode     = 0644,
409                 .proc_handler = &proc_debug_mb,
410         },
411         {0}
412 };
413
414 static cfs_sysctl_table_t top_table[2] = {
415         {
416                 .ctl_name = PSDEV_LNET,
417                 .procname = "lnet",
418                 .data     = NULL,
419                 .maxlen   = 0,
420                 .mode     = 0555,
421                 .child    = lnet_table
422         },
423         {0}
424 };
425
426 int insert_proc(void)
427 {
428 #ifdef CONFIG_SYSCTL
429         if (lnet_table_header == NULL)
430                 lnet_table_header = cfs_register_sysctl_table(top_table, 0);
431 #endif
432         return 0;
433 }
434
435 void remove_proc(void)
436 {
437 #ifdef CONFIG_SYSCTL
438         if (lnet_table_header != NULL)
439                 cfs_unregister_sysctl_table(lnet_table_header);
440
441         lnet_table_header = NULL;
442 #endif
443 }