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