]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/staging/lustre/lustre/libcfs/linux/linux-proc.c
Merge remote-tracking branch 'usb-gadget/next'
[karo-tx-linux.git] / drivers / staging / lustre / lustre / 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, 2012, Intel Corporation.
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 #include <linux/module.h>
44 #include <linux/kernel.h>
45 #include <linux/mm.h>
46 #include <linux/string.h>
47 #include <linux/stat.h>
48 #include <linux/errno.h>
49 #include <linux/unistd.h>
50 #include <net/sock.h>
51 #include <linux/uio.h>
52
53 #include <asm/uaccess.h>
54
55 #include <linux/fs.h>
56 #include <linux/file.h>
57 #include <linux/list.h>
58
59 #include <linux/proc_fs.h>
60 #include <linux/sysctl.h>
61
62 # define DEBUG_SUBSYSTEM S_LNET
63
64 #include "../../../include/linux/libcfs/libcfs.h"
65 #include <asm/div64.h>
66 #include "../tracefile.h"
67
68 static struct ctl_table_header *lnet_table_header = NULL;
69 extern char lnet_upcall[1024];
70 /**
71  * The path of debug log dump upcall script.
72  */
73 extern char lnet_debug_log_upcall[1024];
74
75 #define CTL_LNET        (0x100)
76 enum {
77         PSDEV_DEBUG = 1,          /* control debugging */
78         PSDEV_SUBSYSTEM_DEBUG,    /* control debugging */
79         PSDEV_PRINTK,        /* force all messages to console */
80         PSDEV_CONSOLE_RATELIMIT,  /* ratelimit console messages */
81         PSDEV_CONSOLE_MAX_DELAY_CS, /* maximum delay over which we skip messages */
82         PSDEV_CONSOLE_MIN_DELAY_CS, /* initial delay over which we skip messages */
83         PSDEV_CONSOLE_BACKOFF,    /* delay increase factor */
84         PSDEV_DEBUG_PATH,        /* crashdump log location */
85         PSDEV_DEBUG_DUMP_PATH,    /* crashdump tracelog location */
86         PSDEV_CPT_TABLE,          /* information about cpu partitions */
87         PSDEV_LNET_UPCALL,      /* User mode upcall script  */
88         PSDEV_LNET_MEMUSED,       /* bytes currently PORTAL_ALLOCated */
89         PSDEV_LNET_CATASTROPHE,   /* if we have LBUGged or panic'd */
90         PSDEV_LNET_PANIC_ON_LBUG, /* flag to panic on LBUG */
91         PSDEV_LNET_DUMP_KERNEL,   /* snapshot kernel debug buffer to file */
92         PSDEV_LNET_DAEMON_FILE,   /* spool kernel debug buffer to file */
93         PSDEV_LNET_DEBUG_MB,      /* size of debug buffer */
94         PSDEV_LNET_DEBUG_LOG_UPCALL, /* debug log upcall script */
95         PSDEV_LNET_WATCHDOG_RATELIMIT,  /* ratelimit watchdog messages  */
96         PSDEV_LNET_FORCE_LBUG,    /* hook to force an LBUG */
97         PSDEV_LNET_FAIL_LOC,      /* control test failures instrumentation */
98         PSDEV_LNET_FAIL_VAL,      /* userdata for fail loc */
99 };
100
101 static int proc_call_handler(void *data, int write, loff_t *ppos,
102                 void __user *buffer, size_t *lenp,
103                 int (*handler)(void *data, int write,
104                 loff_t pos, void __user *buffer, int len))
105 {
106         int rc = handler(data, write, *ppos, buffer, *lenp);
107
108         if (rc < 0)
109                 return rc;
110
111         if (write) {
112                 *ppos += *lenp;
113         } else {
114                 *lenp = rc;
115                 *ppos += rc;
116         }
117         return 0;
118 }
119
120 static int __proc_dobitmasks(void *data, int write,
121                              loff_t pos, void __user *buffer, int nob)
122 {
123         const int     tmpstrlen = 512;
124         char     *tmpstr;
125         int        rc;
126         unsigned int *mask = data;
127         int        is_subsys = (mask == &libcfs_subsystem_debug) ? 1 : 0;
128         int        is_printk = (mask == &libcfs_printk) ? 1 : 0;
129
130         rc = cfs_trace_allocate_string_buffer(&tmpstr, tmpstrlen);
131         if (rc < 0)
132                 return rc;
133
134         if (!write) {
135                 libcfs_debug_mask2str(tmpstr, tmpstrlen, *mask, is_subsys);
136                 rc = strlen(tmpstr);
137
138                 if (pos >= rc) {
139                         rc = 0;
140                 } else {
141                         rc = cfs_trace_copyout_string(buffer, nob,
142                                                       tmpstr + pos, "\n");
143                 }
144         } else {
145                 rc = cfs_trace_copyin_string(tmpstr, tmpstrlen, buffer, nob);
146                 if (rc < 0) {
147                         cfs_trace_free_string_buffer(tmpstr, tmpstrlen);
148                         return rc;
149                 }
150
151                 rc = libcfs_debug_str2mask(mask, tmpstr, is_subsys);
152                 /* Always print LBUG/LASSERT to console, so keep this mask */
153                 if (is_printk)
154                         *mask |= D_EMERG;
155         }
156
157         cfs_trace_free_string_buffer(tmpstr, tmpstrlen);
158         return rc;
159 }
160
161 static int proc_dobitmasks(struct ctl_table *table, int write,
162                            void __user *buffer, size_t *lenp, loff_t *ppos)
163 {
164         return proc_call_handler(table->data, write, ppos, buffer, lenp,
165                                  __proc_dobitmasks);
166 }
167
168 static int min_watchdog_ratelimit = 0;    /* disable ratelimiting */
169 static int max_watchdog_ratelimit = (24*60*60); /* limit to once per day */
170
171 static int __proc_dump_kernel(void *data, int write,
172                               loff_t pos, void __user *buffer, int nob)
173 {
174         if (!write)
175                 return 0;
176
177         return cfs_trace_dump_debug_buffer_usrstr(buffer, nob);
178 }
179
180 static int proc_dump_kernel(struct ctl_table *table, int write,
181                             void __user *buffer, size_t *lenp, loff_t *ppos)
182 {
183         return proc_call_handler(table->data, write, ppos, buffer, lenp,
184                                  __proc_dump_kernel);
185 }
186
187 static int __proc_daemon_file(void *data, int write,
188                               loff_t pos, void __user *buffer, int nob)
189 {
190         if (!write) {
191                 int len = strlen(cfs_tracefile);
192
193                 if (pos >= len)
194                         return 0;
195
196                 return cfs_trace_copyout_string(buffer, nob,
197                                                 cfs_tracefile + pos, "\n");
198         }
199
200         return cfs_trace_daemon_command_usrstr(buffer, nob);
201 }
202
203 static int proc_daemon_file(struct ctl_table *table, int write,
204                             void __user *buffer, size_t *lenp, loff_t *ppos)
205 {
206         return proc_call_handler(table->data, write, ppos, buffer, lenp,
207                                  __proc_daemon_file);
208 }
209
210 static int __proc_debug_mb(void *data, int write,
211                            loff_t pos, void __user *buffer, int nob)
212 {
213         if (!write) {
214                 char tmpstr[32];
215                 int  len = snprintf(tmpstr, sizeof(tmpstr), "%d",
216                                     cfs_trace_get_debug_mb());
217
218                 if (pos >= len)
219                         return 0;
220
221                 return cfs_trace_copyout_string(buffer, nob, tmpstr + pos,
222                        "\n");
223         }
224
225         return cfs_trace_set_debug_mb_usrstr(buffer, nob);
226 }
227
228 static int proc_debug_mb(struct ctl_table *table, int write,
229                          void __user *buffer, size_t *lenp, loff_t *ppos)
230 {
231         return proc_call_handler(table->data, write, ppos, buffer, lenp,
232                                  __proc_debug_mb);
233 }
234
235 static int proc_console_max_delay_cs(struct ctl_table *table, int write,
236                                      void __user *buffer, size_t *lenp,
237                                      loff_t *ppos)
238 {
239         int rc, max_delay_cs;
240         struct ctl_table dummy = *table;
241         long d;
242
243         dummy.data = &max_delay_cs;
244         dummy.proc_handler = &proc_dointvec;
245
246         if (!write) { /* read */
247                 max_delay_cs = cfs_duration_sec(libcfs_console_max_delay * 100);
248                 rc = proc_dointvec(&dummy, write, buffer, lenp, ppos);
249                 return rc;
250         }
251
252         /* write */
253         max_delay_cs = 0;
254         rc = proc_dointvec(&dummy, write, buffer, lenp, ppos);
255         if (rc < 0)
256                 return rc;
257         if (max_delay_cs <= 0)
258                 return -EINVAL;
259
260         d = cfs_time_seconds(max_delay_cs) / 100;
261         if (d == 0 || d < libcfs_console_min_delay)
262                 return -EINVAL;
263         libcfs_console_max_delay = d;
264
265         return rc;
266 }
267
268 static int proc_console_min_delay_cs(struct ctl_table *table, int write,
269                                      void __user *buffer, size_t *lenp,
270                                      loff_t *ppos)
271 {
272         int rc, min_delay_cs;
273         struct ctl_table dummy = *table;
274         long d;
275
276         dummy.data = &min_delay_cs;
277         dummy.proc_handler = &proc_dointvec;
278
279         if (!write) { /* read */
280                 min_delay_cs = cfs_duration_sec(libcfs_console_min_delay * 100);
281                 rc = proc_dointvec(&dummy, write, buffer, lenp, ppos);
282                 return rc;
283         }
284
285         /* write */
286         min_delay_cs = 0;
287         rc = proc_dointvec(&dummy, write, buffer, lenp, ppos);
288         if (rc < 0)
289                 return rc;
290         if (min_delay_cs <= 0)
291                 return -EINVAL;
292
293         d = cfs_time_seconds(min_delay_cs) / 100;
294         if (d == 0 || d > libcfs_console_max_delay)
295                 return -EINVAL;
296         libcfs_console_min_delay = d;
297
298         return rc;
299 }
300
301 static int proc_console_backoff(struct ctl_table *table, int write,
302                                 void __user *buffer, size_t *lenp, loff_t *ppos)
303 {
304         int rc, backoff;
305         struct ctl_table dummy = *table;
306
307         dummy.data = &backoff;
308         dummy.proc_handler = &proc_dointvec;
309
310         if (!write) { /* read */
311                 backoff= libcfs_console_backoff;
312                 rc = proc_dointvec(&dummy, write, buffer, lenp, ppos);
313                 return rc;
314         }
315
316         /* write */
317         backoff = 0;
318         rc = proc_dointvec(&dummy, write, buffer, lenp, ppos);
319         if (rc < 0)
320                 return rc;
321         if (backoff <= 0)
322                 return -EINVAL;
323
324         libcfs_console_backoff = backoff;
325
326         return rc;
327 }
328
329 static int libcfs_force_lbug(struct ctl_table *table, int write,
330                              void __user *buffer,
331                              size_t *lenp, loff_t *ppos)
332 {
333         if (write)
334                 LBUG();
335         return 0;
336 }
337
338 static int proc_fail_loc(struct ctl_table *table, int write,
339                          void __user *buffer,
340                          size_t *lenp, loff_t *ppos)
341 {
342         int rc;
343         long old_fail_loc = cfs_fail_loc;
344
345         rc = proc_doulongvec_minmax(table, write, buffer, lenp, ppos);
346         if (old_fail_loc != cfs_fail_loc)
347                 wake_up(&cfs_race_waitq);
348         return rc;
349 }
350
351 static int __proc_cpt_table(void *data, int write,
352                             loff_t pos, void __user *buffer, int nob)
353 {
354         char *buf = NULL;
355         int   len = 4096;
356         int   rc  = 0;
357
358         if (write)
359                 return -EPERM;
360
361         LASSERT(cfs_cpt_table != NULL);
362
363         while (1) {
364                 LIBCFS_ALLOC(buf, len);
365                 if (buf == NULL)
366                         return -ENOMEM;
367
368                 rc = cfs_cpt_table_print(cfs_cpt_table, buf, len);
369                 if (rc >= 0)
370                         break;
371
372                 if (rc == -EFBIG) {
373                         LIBCFS_FREE(buf, len);
374                         len <<= 1;
375                         continue;
376                 }
377                 goto out;
378         }
379
380         if (pos >= rc) {
381                 rc = 0;
382                 goto out;
383         }
384
385         rc = cfs_trace_copyout_string(buffer, nob, buf + pos, NULL);
386  out:
387         if (buf != NULL)
388                 LIBCFS_FREE(buf, len);
389         return rc;
390 }
391
392 static int proc_cpt_table(struct ctl_table *table, int write,
393                            void __user *buffer, size_t *lenp, loff_t *ppos)
394 {
395         return proc_call_handler(table->data, write, ppos, buffer, lenp,
396                                  __proc_cpt_table);
397 }
398
399 static struct ctl_table 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                 .procname = "debug",
406                 .data     = &libcfs_debug,
407                 .maxlen   = sizeof(int),
408                 .mode     = 0644,
409                 .proc_handler = &proc_dobitmasks,
410         },
411         {
412                 .procname = "subsystem_debug",
413                 .data     = &libcfs_subsystem_debug,
414                 .maxlen   = sizeof(int),
415                 .mode     = 0644,
416                 .proc_handler = &proc_dobitmasks,
417         },
418         {
419                 .procname = "printk",
420                 .data     = &libcfs_printk,
421                 .maxlen   = sizeof(int),
422                 .mode     = 0644,
423                 .proc_handler = &proc_dobitmasks,
424         },
425         {
426                 .procname = "console_ratelimit",
427                 .data     = &libcfs_console_ratelimit,
428                 .maxlen   = sizeof(int),
429                 .mode     = 0644,
430                 .proc_handler = &proc_dointvec
431         },
432         {
433                 .procname = "console_max_delay_centisecs",
434                 .maxlen   = sizeof(int),
435                 .mode     = 0644,
436                 .proc_handler = &proc_console_max_delay_cs
437         },
438         {
439                 .procname = "console_min_delay_centisecs",
440                 .maxlen   = sizeof(int),
441                 .mode     = 0644,
442                 .proc_handler = &proc_console_min_delay_cs
443         },
444         {
445                 .procname = "console_backoff",
446                 .maxlen   = sizeof(int),
447                 .mode     = 0644,
448                 .proc_handler = &proc_console_backoff
449         },
450
451         {
452                 .procname = "debug_path",
453                 .data     = libcfs_debug_file_path_arr,
454                 .maxlen   = sizeof(libcfs_debug_file_path_arr),
455                 .mode     = 0644,
456                 .proc_handler = &proc_dostring,
457         },
458
459         {
460                 .procname = "cpu_partition_table",
461                 .maxlen   = 128,
462                 .mode     = 0444,
463                 .proc_handler = &proc_cpt_table,
464         },
465
466         {
467                 .procname = "upcall",
468                 .data     = lnet_upcall,
469                 .maxlen   = sizeof(lnet_upcall),
470                 .mode     = 0644,
471                 .proc_handler = &proc_dostring,
472         },
473         {
474                 .procname = "debug_log_upcall",
475                 .data     = lnet_debug_log_upcall,
476                 .maxlen   = sizeof(lnet_debug_log_upcall),
477                 .mode     = 0644,
478                 .proc_handler = &proc_dostring,
479         },
480         {
481                 .procname = "lnet_memused",
482                 .data     = (int *)&libcfs_kmemory.counter,
483                 .maxlen   = sizeof(int),
484                 .mode     = 0444,
485                 .proc_handler = &proc_dointvec,
486         },
487         {
488                 .procname = "catastrophe",
489                 .data     = &libcfs_catastrophe,
490                 .maxlen   = sizeof(int),
491                 .mode     = 0444,
492                 .proc_handler = &proc_dointvec,
493         },
494         {
495                 .procname = "panic_on_lbug",
496                 .data     = &libcfs_panic_on_lbug,
497                 .maxlen   = sizeof(int),
498                 .mode     = 0644,
499                 .proc_handler = &proc_dointvec,
500         },
501         {
502                 .procname = "dump_kernel",
503                 .maxlen   = 256,
504                 .mode     = 0200,
505                 .proc_handler = &proc_dump_kernel,
506         },
507         {
508                 .procname = "daemon_file",
509                 .mode     = 0644,
510                 .maxlen   = 256,
511                 .proc_handler = &proc_daemon_file,
512         },
513         {
514                 .procname = "debug_mb",
515                 .mode     = 0644,
516                 .proc_handler = &proc_debug_mb,
517         },
518         {
519                 .procname = "watchdog_ratelimit",
520                 .data     = &libcfs_watchdog_ratelimit,
521                 .maxlen   = sizeof(int),
522                 .mode     = 0644,
523                 .proc_handler = &proc_dointvec_minmax,
524                 .extra1   = &min_watchdog_ratelimit,
525                 .extra2   = &max_watchdog_ratelimit,
526         },
527         {
528                 .procname = "force_lbug",
529                 .data     = NULL,
530                 .maxlen   = 0,
531                 .mode     = 0200,
532                 .proc_handler = &libcfs_force_lbug
533         },
534         {
535                 .procname = "fail_loc",
536                 .data     = &cfs_fail_loc,
537                 .maxlen   = sizeof(cfs_fail_loc),
538                 .mode     = 0644,
539                 .proc_handler = &proc_fail_loc
540         },
541         {
542                 .procname = "fail_val",
543                 .data     = &cfs_fail_val,
544                 .maxlen   = sizeof(int),
545                 .mode     = 0644,
546                 .proc_handler = &proc_dointvec
547         },
548         {
549         }
550 };
551
552 static struct ctl_table top_table[] = {
553         {
554                 .procname = "lnet",
555                 .mode     = 0555,
556                 .data     = NULL,
557                 .maxlen   = 0,
558                 .child    = lnet_table,
559         },
560         {
561         }
562 };
563
564 int insert_proc(void)
565 {
566         if (lnet_table_header == NULL)
567                 lnet_table_header = register_sysctl_table(top_table);
568         return 0;
569 }
570
571 void remove_proc(void)
572 {
573         if (lnet_table_header != NULL)
574                 unregister_sysctl_table(lnet_table_header);
575
576         lnet_table_header = NULL;
577 }