Whamcloud - gitweb
b=13990
[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
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         }
146
147         trace_free_string_buffer(tmpstr, tmpstrlen);
148         return rc;
149 }
150
151 DECLARE_PROC_HANDLER(proc_dobitmasks)
152
153 static int __proc_dump_kernel(void *data, int write,
154                               loff_t pos, void *buffer, int nob)
155 {
156         if (!write)
157                 return 0;
158         
159         return trace_dump_debug_buffer_usrstr(buffer, nob);
160 }
161
162 DECLARE_PROC_HANDLER(proc_dump_kernel)
163
164 static int __proc_daemon_file(void *data, int write,
165                               loff_t pos, void *buffer, int nob)
166 {
167         if (!write) {
168                 int len = strlen(tracefile);
169                 
170                 if (pos >= len)
171                         return 0;
172                 
173                 return trace_copyout_string(buffer, nob, 
174                                             tracefile + pos, "\n");
175         }
176         
177         return trace_daemon_command_usrstr(buffer, nob);
178 }
179
180 DECLARE_PROC_HANDLER(proc_daemon_file)
181
182 static int __proc_debug_mb(void *data, int write,
183                            loff_t pos, void *buffer, int nob)
184 {
185         if (!write) {
186                 char tmpstr[32];
187                 int  len = snprintf(tmpstr, sizeof(tmpstr), "%d",
188                                     trace_get_debug_mb());
189
190                 if (pos >= len)
191                         return 0;
192                 
193                 return trace_copyout_string(buffer, nob, tmpstr + pos, "\n");
194         }
195         
196         return trace_set_debug_mb_usrstr(buffer, nob);
197 }
198
199 DECLARE_PROC_HANDLER(proc_debug_mb)
200
201 int LL_PROC_PROTO(proc_console_max_delay_cs)
202 {
203         int rc, max_delay_cs;
204         cfs_sysctl_table_t dummy = *table;
205         cfs_duration_t d;
206
207         dummy.data = &max_delay_cs;
208         dummy.proc_handler = &proc_dointvec;
209
210         if (!write) { /* read */
211                 max_delay_cs = cfs_duration_sec(libcfs_console_max_delay * 100);
212                 rc = ll_proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
213                 return rc;
214         }
215
216         /* write */
217         max_delay_cs = 0;
218         rc = ll_proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
219         if (rc < 0)
220                 return rc;
221         if (max_delay_cs <= 0)
222                 return -EINVAL;
223
224         d = cfs_time_seconds(max_delay_cs) / 100;
225         if (d == 0 || d < libcfs_console_min_delay)
226                 return -EINVAL;
227         libcfs_console_max_delay = d;
228
229         return rc;
230 }
231
232 int LL_PROC_PROTO(proc_console_min_delay_cs)
233 {
234         int rc, min_delay_cs;
235         cfs_sysctl_table_t dummy = *table;
236         cfs_duration_t d;
237
238         dummy.data = &min_delay_cs;
239         dummy.proc_handler = &proc_dointvec;
240
241         if (!write) { /* read */
242                 min_delay_cs = cfs_duration_sec(libcfs_console_min_delay * 100);
243                 rc = ll_proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
244                 return rc;
245         }
246
247         /* write */
248         min_delay_cs = 0;
249         rc = ll_proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
250         if (rc < 0)
251                 return rc;
252         if (min_delay_cs <= 0)
253                 return -EINVAL;
254
255         d = cfs_time_seconds(min_delay_cs) / 100;
256         if (d == 0 || d > libcfs_console_max_delay)
257                 return -EINVAL;
258         libcfs_console_min_delay = d;
259
260         return rc;
261 }
262
263 int LL_PROC_PROTO(proc_console_backoff)
264 {
265         int rc, backoff;
266         cfs_sysctl_table_t dummy = *table;
267
268         dummy.data = &backoff;
269         dummy.proc_handler = &proc_dointvec;
270
271         if (!write) { /* read */
272                 backoff= libcfs_console_backoff;
273                 rc = ll_proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
274                 return rc;
275         }
276
277         /* write */
278         backoff = 0;
279         rc = ll_proc_dointvec(&dummy, write, filp, buffer, lenp, ppos);
280         if (rc < 0)
281                 return rc;
282         if (backoff <= 0)
283                 return -EINVAL;
284
285         libcfs_console_backoff = backoff;
286
287         return rc;
288 }
289
290 static cfs_sysctl_table_t lnet_table[] = {
291         /*
292          * NB No .strategy entries have been provided since sysctl(8) prefers
293          * to go via /proc for portability.
294          */
295         {
296                 .ctl_name = PSDEV_DEBUG,
297                 .procname = "debug",
298                 .data     = &libcfs_debug,
299                 .maxlen   = sizeof(int),
300                 .mode     = 0644,
301                 .proc_handler = &proc_dobitmasks
302         },
303         {
304                 .ctl_name = PSDEV_SUBSYSTEM_DEBUG,
305                 .procname = "subsystem_debug",
306                 .data     = &libcfs_subsystem_debug,
307                 .maxlen   = sizeof(int),
308                 .mode     = 0644,
309                 .proc_handler = &proc_dobitmasks
310         },
311         {
312                 .ctl_name = PSDEV_PRINTK,
313                 .procname = "printk",
314                 .data     = &libcfs_printk,
315                 .maxlen   = sizeof(int),
316                 .mode     = 0644,
317                 .proc_handler = &proc_dobitmasks
318         },
319         {
320                 .ctl_name = PSDEV_CONSOLE_RATELIMIT,
321                 .procname = "console_ratelimit",
322                 .data     = &libcfs_console_ratelimit,
323                 .maxlen   = sizeof(int),
324                 .mode     = 0644,
325                 .proc_handler = &proc_dointvec
326         },
327         {
328                 .ctl_name = PSDEV_CONSOLE_MAX_DELAY_CS,
329                 .procname = "console_max_delay_centisecs",
330                 .maxlen   = sizeof(int),
331                 .mode     = 0644,
332                 .proc_handler = &proc_console_max_delay_cs
333         },
334         {
335                 .ctl_name = PSDEV_CONSOLE_MIN_DELAY_CS,
336                 .procname = "console_min_delay_centisecs",
337                 .maxlen   = sizeof(int),
338                 .mode     = 0644,
339                 .proc_handler = &proc_console_min_delay_cs
340         },
341         {
342                 .ctl_name = PSDEV_CONSOLE_BACKOFF,
343                 .procname = "console_backoff",
344                 .maxlen   = sizeof(int),
345                 .mode     = 0644,
346                 .proc_handler = &proc_console_backoff
347         },
348
349         {
350                 .ctl_name = PSDEV_DEBUG_PATH,
351                 .procname = "debug_path",
352                 .data     = debug_file_path,
353                 .maxlen   = sizeof(debug_file_path),
354                 .mode     = 0644,
355                 .proc_handler = &proc_dostring,
356         },
357
358         {
359                 .ctl_name = PSDEV_LNET_UPCALL,
360                 .procname = "upcall",
361                 .data     = lnet_upcall,
362                 .maxlen   = sizeof(lnet_upcall),
363                 .mode     = 0644,
364                 .proc_handler = &proc_dostring,
365         },
366         {
367                 .ctl_name = PSDEV_LNET_MEMUSED,
368                 .procname = "memused",
369                 .data     = (int *)&libcfs_kmemory.counter,
370                 .maxlen   = sizeof(int),
371                 .mode     = 0444,
372                 .proc_handler = &proc_dointvec
373         },
374         {
375                 .ctl_name = PSDEV_LNET_CATASTROPHE,
376                 .procname = "catastrophe",
377                 .data     = &libcfs_catastrophe,
378                 .maxlen   = sizeof(int),
379                 .mode     = 0444,
380                 .proc_handler = &proc_dointvec
381         },
382         {
383                 .ctl_name = PSDEV_LNET_PANIC_ON_LBUG,
384                 .procname = "panic_on_lbug",
385                 .data     = &libcfs_panic_on_lbug,
386                 .maxlen   = sizeof(int),
387                 .mode     = 0644,
388                 .proc_handler = &proc_dointvec
389         },
390         {
391                 .ctl_name = PSDEV_LNET_DUMP_KERNEL,
392                 .procname = "dump_kernel",
393                 .mode     = 0200,
394                 .proc_handler = &proc_dump_kernel,
395         },
396         {
397                 .ctl_name = PSDEV_LNET_DAEMON_FILE,
398                 .procname = "daemon_file",
399                 .mode     = 0644,
400                 .proc_handler = &proc_daemon_file,
401         },
402         {
403                 .ctl_name = PSDEV_LNET_DEBUG_MB,
404                 .procname = "debug_mb",
405                 .mode     = 0644,
406                 .proc_handler = &proc_debug_mb,
407         },
408         {0}
409 };
410
411 static cfs_sysctl_table_t top_table[2] = {
412         {
413                 .ctl_name = PSDEV_LNET,
414                 .procname = "lnet",
415                 .data     = NULL,
416                 .maxlen   = 0,
417                 .mode     = 0555,
418                 .child    = lnet_table
419         },
420         {0}
421 };
422
423 int insert_proc(void)
424 {
425 #ifdef CONFIG_SYSCTL
426         if (lnet_table_header == NULL)
427                 lnet_table_header = cfs_register_sysctl_table(top_table, 0);
428 #endif
429         return 0;
430 }
431
432 void remove_proc(void)
433 {
434 #ifdef CONFIG_SYSCTL
435         if (lnet_table_header != NULL)
436                 cfs_unregister_sysctl_table(lnet_table_header);
437
438         lnet_table_header = NULL;
439 #endif
440 }