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