Whamcloud - gitweb
Branch b1_6
[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 #include <asm/segment.h>
52
53 #include <linux/proc_fs.h>
54 #include <linux/sysctl.h>
55
56 # define DEBUG_SUBSYSTEM S_LNET
57
58 #include <libcfs/kp30.h>
59 #include <asm/div64.h>
60 #include "tracefile.h"
61
62 static cfs_sysctl_table_header_t *lnet_table_header = NULL;
63 extern char lnet_upcall[1024];
64
65 #define PSDEV_LNET  (0x100)
66 enum {
67         PSDEV_DEBUG = 1,          /* control debugging */
68         PSDEV_SUBSYSTEM_DEBUG,    /* control debugging */
69         PSDEV_PRINTK,             /* force all messages to console */
70         PSDEV_CONSOLE_RATELIMIT,  /* ratelimit console messages */
71         PSDEV_CONSOLE_MAX_DELAY_CS, /* maximum delay over which we skip messages */
72         PSDEV_CONSOLE_MIN_DELAY_CS, /* initial delay over which we skip messages */
73         PSDEV_CONSOLE_BACKOFF,    /* delay increase factor */
74         PSDEV_DEBUG_PATH,         /* crashdump log location */
75         PSDEV_DEBUG_DUMP_PATH,    /* crashdump tracelog location */
76         PSDEV_LNET_UPCALL,        /* User mode upcall script  */
77         PSDEV_LNET_MEMUSED,       /* bytes currently PORTAL_ALLOCated */
78         PSDEV_LNET_CATASTROPHE,   /* if we have LBUGged or panic'd */
79         PSDEV_LNET_PANIC_ON_LBUG, /* flag to panic on LBUG */
80         PSDEV_LNET_DUMP_KERNEL,   /* snapshot kernel debug buffer to file */
81         PSDEV_LNET_DAEMON_FILE,   /* spool kernel debug buffer to file */
82         PSDEV_LNET_DEBUG_MB,      /* size of debug buffer */
83 };
84
85 static int 
86 proc_call_handler(void *data, int write, 
87                   loff_t *ppos, void *buffer, size_t *lenp, 
88                   int (*handler)(void *data, int write,
89                                  loff_t pos, void *buffer, int len))
90 {
91         int rc = handler(data, write, *ppos, buffer, *lenp);
92
93         if (rc < 0)
94                 return rc;
95
96         if (write) {
97                 *ppos += *lenp;
98         } else {
99                 *lenp = rc;
100                 *ppos += rc;
101         }
102         return 0;
103 }
104
105 #define DECLARE_PROC_HANDLER(name)                      \
106 static int                                              \
107 LL_PROC_PROTO(name)                                     \
108 {                                                       \
109         DECLARE_LL_PROC_PPOS_DECL;                      \
110                                                         \
111         return proc_call_handler(table->data, write,    \
112                                  ppos, buffer, lenp,    \
113                                  __##name);             \
114 }
115
116 static int __proc_dobitmasks(void *data, int write, 
117                              loff_t pos, void *buffer, int nob)
118 {
119         const int     tmpstrlen = 512;
120         char         *tmpstr;
121         int           rc;
122         unsigned int *mask = data;
123         int           is_subsys = (mask == &libcfs_subsystem_debug) ? 1 : 0;
124         int           is_printk = (mask == &libcfs_printk) ? 1 : 0;
125
126         rc = trace_allocate_string_buffer(&tmpstr, tmpstrlen);
127         if (rc < 0)
128                 return rc;
129
130         if (!write) {
131                 libcfs_debug_mask2str(tmpstr, tmpstrlen, *mask, is_subsys);
132                 rc = strlen(tmpstr);
133
134                 if (pos >= rc) {
135                         rc = 0;
136                 } else {
137                         rc = trace_copyout_string(buffer, nob,
138                                                   tmpstr + pos, "\n");
139                 }
140         } else {
141                 rc = trace_copyin_string(tmpstr, tmpstrlen, buffer, nob);
142                 if (rc < 0)
143                         return rc;
144
145                 rc = libcfs_debug_str2mask(mask, tmpstr, is_subsys);
146                 /* Always print LBUG/LASSERT to console, so keep this mask */
147                 if (is_printk)
148                         *mask |= D_EMERG;
149         }
150
151         trace_free_string_buffer(tmpstr, tmpstrlen);
152         return rc;
153 }
154
155 DECLARE_PROC_HANDLER(proc_dobitmasks)
156
157 static int __proc_dump_kernel(void *data, int write,
158                               loff_t pos, void *buffer, int nob)
159 {
160         if (!write)
161                 return 0;
162         
163         return trace_dump_debug_buffer_usrstr(buffer, nob);
164 }
165
166 DECLARE_PROC_HANDLER(proc_dump_kernel)
167
168 static int __proc_daemon_file(void *data, int write,
169                               loff_t pos, void *buffer, int nob)
170 {
171         if (!write) {
172                 int len = strlen(tracefile);
173                 
174                 if (pos >= len)
175                         return 0;
176                 
177                 return trace_copyout_string(buffer, nob, 
178                                             tracefile + pos, "\n");
179         }
180         
181         return trace_daemon_command_usrstr(buffer, nob);
182 }
183
184 DECLARE_PROC_HANDLER(proc_daemon_file)
185
186 static int __proc_debug_mb(void *data, int write,
187                            loff_t pos, void *buffer, int nob)
188 {
189         if (!write) {
190                 char tmpstr[32];
191                 int  len = snprintf(tmpstr, sizeof(tmpstr), "%d",
192                                     trace_get_debug_mb());
193
194                 if (pos >= len)
195                         return 0;
196                 
197                 return trace_copyout_string(buffer, nob, tmpstr + pos, "\n");
198         }
199         
200         return trace_set_debug_mb_usrstr(buffer, nob);
201 }
202
203 DECLARE_PROC_HANDLER(proc_debug_mb)
204
205 int LL_PROC_PROTO(proc_console_max_delay_cs)
206 {
207         int rc, max_delay_cs;
208         cfs_sysctl_table_t dummy = *table;
209         cfs_duration_t d;
210
211         dummy.data = &max_delay_cs;
212         dummy.proc_handler = &proc_dointvec;
213
214         if (!write) { /* read */
215                 max_delay_cs = cfs_duration_sec(libcfs_console_max_delay * 100);
216                 rc = ll_proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
217                 return rc;
218         }
219
220         /* write */
221         max_delay_cs = 0;
222         rc = ll_proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
223         if (rc < 0)
224                 return rc;
225         if (max_delay_cs <= 0)
226                 return -EINVAL;
227
228         d = cfs_time_seconds(max_delay_cs) / 100;
229         if (d == 0 || d < libcfs_console_min_delay)
230                 return -EINVAL;
231         libcfs_console_max_delay = d;
232
233         return rc;
234 }
235
236 int LL_PROC_PROTO(proc_console_min_delay_cs)
237 {
238         int rc, min_delay_cs;
239         cfs_sysctl_table_t dummy = *table;
240         cfs_duration_t d;
241
242         dummy.data = &min_delay_cs;
243         dummy.proc_handler = &proc_dointvec;
244
245         if (!write) { /* read */
246                 min_delay_cs = cfs_duration_sec(libcfs_console_min_delay * 100);
247                 rc = ll_proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
248                 return rc;
249         }
250
251         /* write */
252         min_delay_cs = 0;
253         rc = ll_proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
254         if (rc < 0)
255                 return rc;
256         if (min_delay_cs <= 0)
257                 return -EINVAL;
258
259         d = cfs_time_seconds(min_delay_cs) / 100;
260         if (d == 0 || d > libcfs_console_max_delay)
261                 return -EINVAL;
262         libcfs_console_min_delay = d;
263
264         return rc;
265 }
266
267 int LL_PROC_PROTO(proc_console_backoff)
268 {
269         int rc, backoff;
270         cfs_sysctl_table_t dummy = *table;
271
272         dummy.data = &backoff;
273         dummy.proc_handler = &proc_dointvec;
274
275         if (!write) { /* read */
276                 backoff= libcfs_console_backoff;
277                 rc = ll_proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
278                 return rc;
279         }
280
281         /* write */
282         backoff = 0;
283         rc = ll_proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
284         if (rc < 0)
285                 return rc;
286         if (backoff <= 0)
287                 return -EINVAL;
288
289         libcfs_console_backoff = backoff;
290
291         return rc;
292 }
293
294 static cfs_sysctl_table_t lnet_table[] = {
295         /*
296          * NB No .strategy entries have been provided since sysctl(8) prefers
297          * to go via /proc for portability.
298          */
299         {
300                 .ctl_name = PSDEV_DEBUG,
301                 .procname = "debug",
302                 .data     = &libcfs_debug,
303                 .maxlen   = sizeof(int),
304                 .mode     = 0644,
305                 .proc_handler = &proc_dobitmasks
306         },
307         {
308                 .ctl_name = PSDEV_SUBSYSTEM_DEBUG,
309                 .procname = "subsystem_debug",
310                 .data     = &libcfs_subsystem_debug,
311                 .maxlen   = sizeof(int),
312                 .mode     = 0644,
313                 .proc_handler = &proc_dobitmasks
314         },
315         {
316                 .ctl_name = PSDEV_PRINTK,
317                 .procname = "printk",
318                 .data     = &libcfs_printk,
319                 .maxlen   = sizeof(int),
320                 .mode     = 0644,
321                 .proc_handler = &proc_dobitmasks
322         },
323         {
324                 .ctl_name = PSDEV_CONSOLE_RATELIMIT,
325                 .procname = "console_ratelimit",
326                 .data     = &libcfs_console_ratelimit,
327                 .maxlen   = sizeof(int),
328                 .mode     = 0644,
329                 .proc_handler = &proc_dointvec
330         },
331         {
332                 .ctl_name = PSDEV_CONSOLE_MAX_DELAY_CS,
333                 .procname = "console_max_delay_centisecs",
334                 .maxlen   = sizeof(int),
335                 .mode     = 0644,
336                 .proc_handler = &proc_console_max_delay_cs
337         },
338         {
339                 .ctl_name = PSDEV_CONSOLE_MIN_DELAY_CS,
340                 .procname = "console_min_delay_centisecs",
341                 .maxlen   = sizeof(int),
342                 .mode     = 0644,
343                 .proc_handler = &proc_console_min_delay_cs
344         },
345         {
346                 .ctl_name = PSDEV_CONSOLE_BACKOFF,
347                 .procname = "console_backoff",
348                 .maxlen   = sizeof(int),
349                 .mode     = 0644,
350                 .proc_handler = &proc_console_backoff
351         },
352
353         {
354                 .ctl_name = PSDEV_DEBUG_PATH,
355                 .procname = "debug_path",
356                 .data     = debug_file_path,
357                 .maxlen   = sizeof(debug_file_path),
358                 .mode     = 0644,
359                 .proc_handler = &proc_dostring,
360         },
361
362         {
363                 .ctl_name = PSDEV_LNET_UPCALL,
364                 .procname = "upcall",
365                 .data     = lnet_upcall,
366                 .maxlen   = sizeof(lnet_upcall),
367                 .mode     = 0644,
368                 .proc_handler = &proc_dostring,
369         },
370         {
371                 .ctl_name = PSDEV_LNET_MEMUSED,
372                 .procname = "memused",
373                 .data     = (int *)&libcfs_kmemory.counter,
374                 .maxlen   = sizeof(int),
375                 .mode     = 0444,
376                 .proc_handler = &proc_dointvec
377         },
378         {
379                 .ctl_name = PSDEV_LNET_CATASTROPHE,
380                 .procname = "catastrophe",
381                 .data     = &libcfs_catastrophe,
382                 .maxlen   = sizeof(int),
383                 .mode     = 0444,
384                 .proc_handler = &proc_dointvec
385         },
386         {
387                 .ctl_name = PSDEV_LNET_PANIC_ON_LBUG,
388                 .procname = "panic_on_lbug",
389                 .data     = &libcfs_panic_on_lbug,
390                 .maxlen   = sizeof(int),
391                 .mode     = 0644,
392                 .proc_handler = &proc_dointvec
393         },
394         {
395                 .ctl_name = PSDEV_LNET_DUMP_KERNEL,
396                 .procname = "dump_kernel",
397                 .mode     = 0200,
398                 .proc_handler = &proc_dump_kernel,
399         },
400         {
401                 .ctl_name = PSDEV_LNET_DAEMON_FILE,
402                 .procname = "daemon_file",
403                 .mode     = 0644,
404                 .proc_handler = &proc_daemon_file,
405         },
406         {
407                 .ctl_name = PSDEV_LNET_DEBUG_MB,
408                 .procname = "debug_mb",
409                 .mode     = 0644,
410                 .proc_handler = &proc_debug_mb,
411         },
412         {0}
413 };
414
415 static cfs_sysctl_table_t top_table[2] = {
416         {
417                 .ctl_name = PSDEV_LNET,
418                 .procname = "lnet",
419                 .data     = NULL,
420                 .maxlen   = 0,
421                 .mode     = 0555,
422                 .child    = lnet_table
423         },
424         {0}
425 };
426
427 int insert_proc(void)
428 {
429 #ifdef CONFIG_SYSCTL
430         if (lnet_table_header == NULL)
431                 lnet_table_header = cfs_register_sysctl_table(top_table, 0);
432 #endif
433         return 0;
434 }
435
436 void remove_proc(void)
437 {
438 #ifdef CONFIG_SYSCTL
439         if (lnet_table_header != NULL)
440                 cfs_unregister_sysctl_table(lnet_table_header);
441
442         lnet_table_header = NULL;
443 #endif
444 }