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