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