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) 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 #include <linux/module.h>
37 #include <linux/kernel.h>
38 #include <linux/mm.h>
39 #include <linux/string.h>
40 #include <linux/stat.h>
41 #include <linux/errno.h>
42 #include <linux/unistd.h>
43 #include <net/sock.h>
44 #include <linux/uio.h>
45
46 #include <linux/uaccess.h>
47
48 #include <linux/fs.h>
49 #include <linux/file.h>
50 #include <linux/list.h>
51
52 #include <linux/proc_fs.h>
53 #include <linux/sysctl.h>
54
55 # define DEBUG_SUBSYSTEM S_LNET
56
57 #include "../../include/linux/libcfs/libcfs.h"
58 #include <asm/div64.h>
59
60 #include "../../include/linux/libcfs/libcfs_crypto.h"
61 #include "../../include/linux/lnet/lib-lnet.h"
62 #include "../../include/linux/lnet/lnet.h"
63 #include "tracefile.h"
64
65 MODULE_AUTHOR("Peter J. Braam <braam@clusterfs.com>");
66 MODULE_DESCRIPTION("Portals v3.1");
67 MODULE_LICENSE("GPL");
68
69 extern struct miscdevice libcfs_dev;
70 extern struct rw_semaphore cfs_tracefile_sem;
71 extern struct mutex cfs_trace_thread_mutex;
72 extern struct cfs_wi_sched *cfs_sched_rehash;
73 extern void libcfs_init_nidstrings(void);
74
75 static int insert_proc(void);
76 static void remove_proc(void);
77
78 static struct ctl_table_header *lnet_table_header;
79 extern char lnet_upcall[1024];
80 /**
81 * The path of debug log dump upcall script.
82 */
83 extern char lnet_debug_log_upcall[1024];
84
85 #define CTL_LNET (0x100)
86
87 enum {
88 PSDEV_DEBUG = 1, /* control debugging */
89 PSDEV_SUBSYSTEM_DEBUG, /* control debugging */
90 PSDEV_PRINTK, /* force all messages to console */
91 PSDEV_CONSOLE_RATELIMIT, /* ratelimit console messages */
92 PSDEV_CONSOLE_MAX_DELAY_CS, /* maximum delay over which we skip messages */
93 PSDEV_CONSOLE_MIN_DELAY_CS, /* initial delay over which we skip messages */
94 PSDEV_CONSOLE_BACKOFF, /* delay increase factor */
95 PSDEV_DEBUG_PATH, /* crashdump log location */
96 PSDEV_DEBUG_DUMP_PATH, /* crashdump tracelog location */
97 PSDEV_CPT_TABLE, /* information about cpu partitions */
98 PSDEV_LNET_UPCALL, /* User mode upcall script */
99 PSDEV_LNET_MEMUSED, /* bytes currently PORTAL_ALLOCated */
100 PSDEV_LNET_CATASTROPHE, /* if we have LBUGged or panic'd */
101 PSDEV_LNET_PANIC_ON_LBUG, /* flag to panic on LBUG */
102 PSDEV_LNET_DUMP_KERNEL, /* snapshot kernel debug buffer to file */
103 PSDEV_LNET_DAEMON_FILE, /* spool kernel debug buffer to file */
104 PSDEV_LNET_DEBUG_MB, /* size of debug buffer */
105 PSDEV_LNET_DEBUG_LOG_UPCALL, /* debug log upcall script */
106 PSDEV_LNET_WATCHDOG_RATELIMIT, /* ratelimit watchdog messages */
107 PSDEV_LNET_FORCE_LBUG, /* hook to force an LBUG */
108 PSDEV_LNET_FAIL_LOC, /* control test failures instrumentation */
109 PSDEV_LNET_FAIL_VAL, /* userdata for fail loc */
110 };
111
kportal_memhog_free(struct libcfs_device_userstate * ldu)112 static void kportal_memhog_free (struct libcfs_device_userstate *ldu)
113 {
114 struct page **level0p = &ldu->ldu_memhog_root_page;
115 struct page **level1p;
116 struct page **level2p;
117 int count1;
118 int count2;
119
120 if (*level0p != NULL) {
121
122 level1p = (struct page **)page_address(*level0p);
123 count1 = 0;
124
125 while (count1 < PAGE_CACHE_SIZE/sizeof(struct page *) &&
126 *level1p != NULL) {
127
128 level2p = (struct page **)page_address(*level1p);
129 count2 = 0;
130
131 while (count2 < PAGE_CACHE_SIZE/sizeof(struct page *) &&
132 *level2p != NULL) {
133
134 __free_page(*level2p);
135 ldu->ldu_memhog_pages--;
136 level2p++;
137 count2++;
138 }
139
140 __free_page(*level1p);
141 ldu->ldu_memhog_pages--;
142 level1p++;
143 count1++;
144 }
145
146 __free_page(*level0p);
147 ldu->ldu_memhog_pages--;
148
149 *level0p = NULL;
150 }
151
152 LASSERT (ldu->ldu_memhog_pages == 0);
153 }
154
kportal_memhog_alloc(struct libcfs_device_userstate * ldu,int npages,gfp_t flags)155 static int kportal_memhog_alloc(struct libcfs_device_userstate *ldu, int npages,
156 gfp_t flags)
157 {
158 struct page **level0p;
159 struct page **level1p;
160 struct page **level2p;
161 int count1;
162 int count2;
163
164 LASSERT (ldu->ldu_memhog_pages == 0);
165 LASSERT (ldu->ldu_memhog_root_page == NULL);
166
167 if (npages < 0)
168 return -EINVAL;
169
170 if (npages == 0)
171 return 0;
172
173 level0p = &ldu->ldu_memhog_root_page;
174 *level0p = alloc_page(flags);
175 if (*level0p == NULL)
176 return -ENOMEM;
177 ldu->ldu_memhog_pages++;
178
179 level1p = (struct page **)page_address(*level0p);
180 count1 = 0;
181 memset(level1p, 0, PAGE_CACHE_SIZE);
182
183 while (ldu->ldu_memhog_pages < npages &&
184 count1 < PAGE_CACHE_SIZE/sizeof(struct page *)) {
185
186 if (cfs_signal_pending())
187 return -EINTR;
188
189 *level1p = alloc_page(flags);
190 if (*level1p == NULL)
191 return -ENOMEM;
192 ldu->ldu_memhog_pages++;
193
194 level2p = (struct page **)page_address(*level1p);
195 count2 = 0;
196 memset(level2p, 0, PAGE_CACHE_SIZE);
197
198 while (ldu->ldu_memhog_pages < npages &&
199 count2 < PAGE_CACHE_SIZE/sizeof(struct page *)) {
200
201 if (cfs_signal_pending())
202 return -EINTR;
203
204 *level2p = alloc_page(flags);
205 if (*level2p == NULL)
206 return -ENOMEM;
207 ldu->ldu_memhog_pages++;
208
209 level2p++;
210 count2++;
211 }
212
213 level1p++;
214 count1++;
215 }
216
217 return 0;
218 }
219
220 /* called when opening /dev/device */
libcfs_psdev_open(unsigned long flags,void * args)221 static int libcfs_psdev_open(unsigned long flags, void *args)
222 {
223 struct libcfs_device_userstate *ldu;
224
225 try_module_get(THIS_MODULE);
226
227 LIBCFS_ALLOC(ldu, sizeof(*ldu));
228 if (ldu != NULL) {
229 ldu->ldu_memhog_pages = 0;
230 ldu->ldu_memhog_root_page = NULL;
231 }
232 *(struct libcfs_device_userstate **)args = ldu;
233
234 return 0;
235 }
236
237 /* called when closing /dev/device */
libcfs_psdev_release(unsigned long flags,void * args)238 static int libcfs_psdev_release(unsigned long flags, void *args)
239 {
240 struct libcfs_device_userstate *ldu;
241
242 ldu = (struct libcfs_device_userstate *)args;
243 if (ldu != NULL) {
244 kportal_memhog_free(ldu);
245 LIBCFS_FREE(ldu, sizeof(*ldu));
246 }
247
248 module_put(THIS_MODULE);
249 return 0;
250 }
251
252 static struct rw_semaphore ioctl_list_sem;
253 static struct list_head ioctl_list;
254
libcfs_register_ioctl(struct libcfs_ioctl_handler * hand)255 int libcfs_register_ioctl(struct libcfs_ioctl_handler *hand)
256 {
257 int rc = 0;
258
259 down_write(&ioctl_list_sem);
260 if (!list_empty(&hand->item))
261 rc = -EBUSY;
262 else
263 list_add_tail(&hand->item, &ioctl_list);
264 up_write(&ioctl_list_sem);
265
266 return rc;
267 }
268 EXPORT_SYMBOL(libcfs_register_ioctl);
269
libcfs_deregister_ioctl(struct libcfs_ioctl_handler * hand)270 int libcfs_deregister_ioctl(struct libcfs_ioctl_handler *hand)
271 {
272 int rc = 0;
273
274 down_write(&ioctl_list_sem);
275 if (list_empty(&hand->item))
276 rc = -ENOENT;
277 else
278 list_del_init(&hand->item);
279 up_write(&ioctl_list_sem);
280
281 return rc;
282 }
283 EXPORT_SYMBOL(libcfs_deregister_ioctl);
284
libcfs_ioctl_int(struct cfs_psdev_file * pfile,unsigned long cmd,void * arg,struct libcfs_ioctl_data * data)285 static int libcfs_ioctl_int(struct cfs_psdev_file *pfile, unsigned long cmd,
286 void *arg, struct libcfs_ioctl_data *data)
287 {
288 int err = -EINVAL;
289
290 switch (cmd) {
291 case IOC_LIBCFS_CLEAR_DEBUG:
292 libcfs_debug_clear_buffer();
293 return 0;
294 /*
295 * case IOC_LIBCFS_PANIC:
296 * Handled in arch/cfs_module.c
297 */
298 case IOC_LIBCFS_MARK_DEBUG:
299 if (data->ioc_inlbuf1 == NULL ||
300 data->ioc_inlbuf1[data->ioc_inllen1 - 1] != '\0')
301 return -EINVAL;
302 libcfs_debug_mark_buffer(data->ioc_inlbuf1);
303 return 0;
304 case IOC_LIBCFS_MEMHOG:
305 if (pfile->private_data == NULL) {
306 err = -EINVAL;
307 } else {
308 kportal_memhog_free(pfile->private_data);
309 /* XXX The ioc_flags is not GFP flags now, need to be fixed */
310 err = kportal_memhog_alloc(pfile->private_data,
311 data->ioc_count,
312 data->ioc_flags);
313 if (err != 0)
314 kportal_memhog_free(pfile->private_data);
315 }
316 break;
317
318 case IOC_LIBCFS_PING_TEST: {
319 extern void (kping_client)(struct libcfs_ioctl_data *);
320 void (*ping)(struct libcfs_ioctl_data *);
321
322 CDEBUG(D_IOCTL, "doing %d pings to nid %s (%s)\n",
323 data->ioc_count, libcfs_nid2str(data->ioc_nid),
324 libcfs_nid2str(data->ioc_nid));
325 ping = symbol_get(kping_client);
326 if (!ping)
327 CERROR("symbol_get failed\n");
328 else {
329 ping(data);
330 symbol_put(kping_client);
331 }
332 return 0;
333 }
334
335 default: {
336 struct libcfs_ioctl_handler *hand;
337 err = -EINVAL;
338 down_read(&ioctl_list_sem);
339 list_for_each_entry(hand, &ioctl_list, item) {
340 err = hand->handle_ioctl(cmd, data);
341 if (err != -EINVAL) {
342 if (err == 0)
343 err = libcfs_ioctl_popdata(arg,
344 data, sizeof (*data));
345 break;
346 }
347 }
348 up_read(&ioctl_list_sem);
349 break;
350 }
351 }
352
353 return err;
354 }
355
libcfs_ioctl(struct cfs_psdev_file * pfile,unsigned long cmd,void * arg)356 static int libcfs_ioctl(struct cfs_psdev_file *pfile, unsigned long cmd, void *arg)
357 {
358 char *buf;
359 struct libcfs_ioctl_data *data;
360 int err = 0;
361
362 LIBCFS_ALLOC_GFP(buf, 1024, GFP_IOFS);
363 if (buf == NULL)
364 return -ENOMEM;
365
366 /* 'cmd' and permissions get checked in our arch-specific caller */
367 if (libcfs_ioctl_getdata(buf, buf + 800, (void *)arg)) {
368 CERROR("PORTALS ioctl: data error\n");
369 err = -EINVAL;
370 goto out;
371 }
372 data = (struct libcfs_ioctl_data *)buf;
373
374 err = libcfs_ioctl_int(pfile, cmd, arg, data);
375
376 out:
377 LIBCFS_FREE(buf, 1024);
378 return err;
379 }
380
381
382 struct cfs_psdev_ops libcfs_psdev_ops = {
383 libcfs_psdev_open,
384 libcfs_psdev_release,
385 NULL,
386 NULL,
387 libcfs_ioctl
388 };
389
init_libcfs_module(void)390 static int init_libcfs_module(void)
391 {
392 int rc;
393
394 libcfs_arch_init();
395 libcfs_init_nidstrings();
396 init_rwsem(&cfs_tracefile_sem);
397 mutex_init(&cfs_trace_thread_mutex);
398 init_rwsem(&ioctl_list_sem);
399 INIT_LIST_HEAD(&ioctl_list);
400 init_waitqueue_head(&cfs_race_waitq);
401
402 rc = libcfs_debug_init(5 * 1024 * 1024);
403 if (rc < 0) {
404 pr_err("LustreError: libcfs_debug_init: %d\n", rc);
405 return rc;
406 }
407
408 rc = cfs_cpu_init();
409 if (rc != 0)
410 goto cleanup_debug;
411
412 rc = misc_register(&libcfs_dev);
413 if (rc) {
414 CERROR("misc_register: error %d\n", rc);
415 goto cleanup_cpu;
416 }
417
418 rc = cfs_wi_startup();
419 if (rc) {
420 CERROR("initialize workitem: error %d\n", rc);
421 goto cleanup_deregister;
422 }
423
424 /* max to 4 threads, should be enough for rehash */
425 rc = min(cfs_cpt_weight(cfs_cpt_table, CFS_CPT_ANY), 4);
426 rc = cfs_wi_sched_create("cfs_rh", cfs_cpt_table, CFS_CPT_ANY,
427 rc, &cfs_sched_rehash);
428 if (rc != 0) {
429 CERROR("Startup workitem scheduler: error: %d\n", rc);
430 goto cleanup_deregister;
431 }
432
433 rc = cfs_crypto_register();
434 if (rc) {
435 CERROR("cfs_crypto_register: error %d\n", rc);
436 goto cleanup_wi;
437 }
438
439
440 rc = insert_proc();
441 if (rc) {
442 CERROR("insert_proc: error %d\n", rc);
443 goto cleanup_crypto;
444 }
445
446 CDEBUG (D_OTHER, "portals setup OK\n");
447 return 0;
448 cleanup_crypto:
449 cfs_crypto_unregister();
450 cleanup_wi:
451 cfs_wi_shutdown();
452 cleanup_deregister:
453 misc_deregister(&libcfs_dev);
454 cleanup_cpu:
455 cfs_cpu_fini();
456 cleanup_debug:
457 libcfs_debug_cleanup();
458 return rc;
459 }
460
exit_libcfs_module(void)461 static void exit_libcfs_module(void)
462 {
463 int rc;
464
465 remove_proc();
466
467 CDEBUG(D_MALLOC, "before Portals cleanup: kmem %d\n",
468 atomic_read(&libcfs_kmemory));
469
470 if (cfs_sched_rehash != NULL) {
471 cfs_wi_sched_destroy(cfs_sched_rehash);
472 cfs_sched_rehash = NULL;
473 }
474
475 cfs_crypto_unregister();
476 cfs_wi_shutdown();
477
478 rc = misc_deregister(&libcfs_dev);
479 if (rc)
480 CERROR("misc_deregister error %d\n", rc);
481
482 cfs_cpu_fini();
483
484 if (atomic_read(&libcfs_kmemory) != 0)
485 CERROR("Portals memory leaked: %d bytes\n",
486 atomic_read(&libcfs_kmemory));
487
488 rc = libcfs_debug_cleanup();
489 if (rc)
490 pr_err("LustreError: libcfs_debug_cleanup: %d\n", rc);
491
492 libcfs_arch_cleanup();
493 }
494
proc_call_handler(void * data,int write,loff_t * ppos,void __user * buffer,size_t * lenp,int (* handler)(void * data,int write,loff_t pos,void __user * buffer,int len))495 static int proc_call_handler(void *data, int write, loff_t *ppos,
496 void __user *buffer, size_t *lenp,
497 int (*handler)(void *data, int write,
498 loff_t pos, void __user *buffer, int len))
499 {
500 int rc = handler(data, write, *ppos, buffer, *lenp);
501
502 if (rc < 0)
503 return rc;
504
505 if (write) {
506 *ppos += *lenp;
507 } else {
508 *lenp = rc;
509 *ppos += rc;
510 }
511 return 0;
512 }
513
__proc_dobitmasks(void * data,int write,loff_t pos,void __user * buffer,int nob)514 static int __proc_dobitmasks(void *data, int write,
515 loff_t pos, void __user *buffer, int nob)
516 {
517 const int tmpstrlen = 512;
518 char *tmpstr;
519 int rc;
520 unsigned int *mask = data;
521 int is_subsys = (mask == &libcfs_subsystem_debug) ? 1 : 0;
522 int is_printk = (mask == &libcfs_printk) ? 1 : 0;
523
524 rc = cfs_trace_allocate_string_buffer(&tmpstr, tmpstrlen);
525 if (rc < 0)
526 return rc;
527
528 if (!write) {
529 libcfs_debug_mask2str(tmpstr, tmpstrlen, *mask, is_subsys);
530 rc = strlen(tmpstr);
531
532 if (pos >= rc) {
533 rc = 0;
534 } else {
535 rc = cfs_trace_copyout_string(buffer, nob,
536 tmpstr + pos, "\n");
537 }
538 } else {
539 rc = cfs_trace_copyin_string(tmpstr, tmpstrlen, buffer, nob);
540 if (rc < 0) {
541 cfs_trace_free_string_buffer(tmpstr, tmpstrlen);
542 return rc;
543 }
544
545 rc = libcfs_debug_str2mask(mask, tmpstr, is_subsys);
546 /* Always print LBUG/LASSERT to console, so keep this mask */
547 if (is_printk)
548 *mask |= D_EMERG;
549 }
550
551 cfs_trace_free_string_buffer(tmpstr, tmpstrlen);
552 return rc;
553 }
554
proc_dobitmasks(struct ctl_table * table,int write,void __user * buffer,size_t * lenp,loff_t * ppos)555 static int proc_dobitmasks(struct ctl_table *table, int write,
556 void __user *buffer, size_t *lenp, loff_t *ppos)
557 {
558 return proc_call_handler(table->data, write, ppos, buffer, lenp,
559 __proc_dobitmasks);
560 }
561
562 static int min_watchdog_ratelimit; /* disable ratelimiting */
563 static int max_watchdog_ratelimit = (24*60*60); /* limit to once per day */
564
__proc_dump_kernel(void * data,int write,loff_t pos,void __user * buffer,int nob)565 static int __proc_dump_kernel(void *data, int write,
566 loff_t pos, void __user *buffer, int nob)
567 {
568 if (!write)
569 return 0;
570
571 return cfs_trace_dump_debug_buffer_usrstr(buffer, nob);
572 }
573
proc_dump_kernel(struct ctl_table * table,int write,void __user * buffer,size_t * lenp,loff_t * ppos)574 static int proc_dump_kernel(struct ctl_table *table, int write,
575 void __user *buffer, size_t *lenp, loff_t *ppos)
576 {
577 return proc_call_handler(table->data, write, ppos, buffer, lenp,
578 __proc_dump_kernel);
579 }
580
__proc_daemon_file(void * data,int write,loff_t pos,void __user * buffer,int nob)581 static int __proc_daemon_file(void *data, int write,
582 loff_t pos, void __user *buffer, int nob)
583 {
584 if (!write) {
585 int len = strlen(cfs_tracefile);
586
587 if (pos >= len)
588 return 0;
589
590 return cfs_trace_copyout_string(buffer, nob,
591 cfs_tracefile + pos, "\n");
592 }
593
594 return cfs_trace_daemon_command_usrstr(buffer, nob);
595 }
596
proc_daemon_file(struct ctl_table * table,int write,void __user * buffer,size_t * lenp,loff_t * ppos)597 static int proc_daemon_file(struct ctl_table *table, int write,
598 void __user *buffer, size_t *lenp, loff_t *ppos)
599 {
600 return proc_call_handler(table->data, write, ppos, buffer, lenp,
601 __proc_daemon_file);
602 }
603
__proc_debug_mb(void * data,int write,loff_t pos,void __user * buffer,int nob)604 static int __proc_debug_mb(void *data, int write,
605 loff_t pos, void __user *buffer, int nob)
606 {
607 if (!write) {
608 char tmpstr[32];
609 int len = snprintf(tmpstr, sizeof(tmpstr), "%d",
610 cfs_trace_get_debug_mb());
611
612 if (pos >= len)
613 return 0;
614
615 return cfs_trace_copyout_string(buffer, nob, tmpstr + pos,
616 "\n");
617 }
618
619 return cfs_trace_set_debug_mb_usrstr(buffer, nob);
620 }
621
proc_debug_mb(struct ctl_table * table,int write,void __user * buffer,size_t * lenp,loff_t * ppos)622 static int proc_debug_mb(struct ctl_table *table, int write,
623 void __user *buffer, size_t *lenp, loff_t *ppos)
624 {
625 return proc_call_handler(table->data, write, ppos, buffer, lenp,
626 __proc_debug_mb);
627 }
628
proc_console_max_delay_cs(struct ctl_table * table,int write,void __user * buffer,size_t * lenp,loff_t * ppos)629 static int proc_console_max_delay_cs(struct ctl_table *table, int write,
630 void __user *buffer, size_t *lenp,
631 loff_t *ppos)
632 {
633 int rc, max_delay_cs;
634 struct ctl_table dummy = *table;
635 long d;
636
637 dummy.data = &max_delay_cs;
638 dummy.proc_handler = &proc_dointvec;
639
640 if (!write) { /* read */
641 max_delay_cs = cfs_duration_sec(libcfs_console_max_delay * 100);
642 rc = proc_dointvec(&dummy, write, buffer, lenp, ppos);
643 return rc;
644 }
645
646 /* write */
647 max_delay_cs = 0;
648 rc = proc_dointvec(&dummy, write, buffer, lenp, ppos);
649 if (rc < 0)
650 return rc;
651 if (max_delay_cs <= 0)
652 return -EINVAL;
653
654 d = cfs_time_seconds(max_delay_cs) / 100;
655 if (d == 0 || d < libcfs_console_min_delay)
656 return -EINVAL;
657 libcfs_console_max_delay = d;
658
659 return rc;
660 }
661
proc_console_min_delay_cs(struct ctl_table * table,int write,void __user * buffer,size_t * lenp,loff_t * ppos)662 static int proc_console_min_delay_cs(struct ctl_table *table, int write,
663 void __user *buffer, size_t *lenp,
664 loff_t *ppos)
665 {
666 int rc, min_delay_cs;
667 struct ctl_table dummy = *table;
668 long d;
669
670 dummy.data = &min_delay_cs;
671 dummy.proc_handler = &proc_dointvec;
672
673 if (!write) { /* read */
674 min_delay_cs = cfs_duration_sec(libcfs_console_min_delay * 100);
675 rc = proc_dointvec(&dummy, write, buffer, lenp, ppos);
676 return rc;
677 }
678
679 /* write */
680 min_delay_cs = 0;
681 rc = proc_dointvec(&dummy, write, buffer, lenp, ppos);
682 if (rc < 0)
683 return rc;
684 if (min_delay_cs <= 0)
685 return -EINVAL;
686
687 d = cfs_time_seconds(min_delay_cs) / 100;
688 if (d == 0 || d > libcfs_console_max_delay)
689 return -EINVAL;
690 libcfs_console_min_delay = d;
691
692 return rc;
693 }
694
proc_console_backoff(struct ctl_table * table,int write,void __user * buffer,size_t * lenp,loff_t * ppos)695 static int proc_console_backoff(struct ctl_table *table, int write,
696 void __user *buffer, size_t *lenp, loff_t *ppos)
697 {
698 int rc, backoff;
699 struct ctl_table dummy = *table;
700
701 dummy.data = &backoff;
702 dummy.proc_handler = &proc_dointvec;
703
704 if (!write) { /* read */
705 backoff = libcfs_console_backoff;
706 rc = proc_dointvec(&dummy, write, buffer, lenp, ppos);
707 return rc;
708 }
709
710 /* write */
711 backoff = 0;
712 rc = proc_dointvec(&dummy, write, buffer, lenp, ppos);
713 if (rc < 0)
714 return rc;
715 if (backoff <= 0)
716 return -EINVAL;
717
718 libcfs_console_backoff = backoff;
719
720 return rc;
721 }
722
libcfs_force_lbug(struct ctl_table * table,int write,void __user * buffer,size_t * lenp,loff_t * ppos)723 static int libcfs_force_lbug(struct ctl_table *table, int write,
724 void __user *buffer,
725 size_t *lenp, loff_t *ppos)
726 {
727 if (write)
728 LBUG();
729 return 0;
730 }
731
proc_fail_loc(struct ctl_table * table,int write,void __user * buffer,size_t * lenp,loff_t * ppos)732 static int proc_fail_loc(struct ctl_table *table, int write,
733 void __user *buffer,
734 size_t *lenp, loff_t *ppos)
735 {
736 int rc;
737 long old_fail_loc = cfs_fail_loc;
738
739 rc = proc_doulongvec_minmax(table, write, buffer, lenp, ppos);
740 if (old_fail_loc != cfs_fail_loc)
741 wake_up(&cfs_race_waitq);
742 return rc;
743 }
744
__proc_cpt_table(void * data,int write,loff_t pos,void __user * buffer,int nob)745 static int __proc_cpt_table(void *data, int write,
746 loff_t pos, void __user *buffer, int nob)
747 {
748 char *buf = NULL;
749 int len = 4096;
750 int rc = 0;
751
752 if (write)
753 return -EPERM;
754
755 LASSERT(cfs_cpt_table != NULL);
756
757 while (1) {
758 LIBCFS_ALLOC(buf, len);
759 if (buf == NULL)
760 return -ENOMEM;
761
762 rc = cfs_cpt_table_print(cfs_cpt_table, buf, len);
763 if (rc >= 0)
764 break;
765
766 if (rc == -EFBIG) {
767 LIBCFS_FREE(buf, len);
768 len <<= 1;
769 continue;
770 }
771 goto out;
772 }
773
774 if (pos >= rc) {
775 rc = 0;
776 goto out;
777 }
778
779 rc = cfs_trace_copyout_string(buffer, nob, buf + pos, NULL);
780 out:
781 if (buf != NULL)
782 LIBCFS_FREE(buf, len);
783 return rc;
784 }
785
proc_cpt_table(struct ctl_table * table,int write,void __user * buffer,size_t * lenp,loff_t * ppos)786 static int proc_cpt_table(struct ctl_table *table, int write,
787 void __user *buffer, size_t *lenp, loff_t *ppos)
788 {
789 return proc_call_handler(table->data, write, ppos, buffer, lenp,
790 __proc_cpt_table);
791 }
792
793 static struct ctl_table lnet_table[] = {
794 /*
795 * NB No .strategy entries have been provided since sysctl(8) prefers
796 * to go via /proc for portability.
797 */
798 {
799 .procname = "debug",
800 .data = &libcfs_debug,
801 .maxlen = sizeof(int),
802 .mode = 0644,
803 .proc_handler = &proc_dobitmasks,
804 },
805 {
806 .procname = "subsystem_debug",
807 .data = &libcfs_subsystem_debug,
808 .maxlen = sizeof(int),
809 .mode = 0644,
810 .proc_handler = &proc_dobitmasks,
811 },
812 {
813 .procname = "printk",
814 .data = &libcfs_printk,
815 .maxlen = sizeof(int),
816 .mode = 0644,
817 .proc_handler = &proc_dobitmasks,
818 },
819 {
820 .procname = "console_ratelimit",
821 .data = &libcfs_console_ratelimit,
822 .maxlen = sizeof(int),
823 .mode = 0644,
824 .proc_handler = &proc_dointvec
825 },
826 {
827 .procname = "console_max_delay_centisecs",
828 .maxlen = sizeof(int),
829 .mode = 0644,
830 .proc_handler = &proc_console_max_delay_cs
831 },
832 {
833 .procname = "console_min_delay_centisecs",
834 .maxlen = sizeof(int),
835 .mode = 0644,
836 .proc_handler = &proc_console_min_delay_cs
837 },
838 {
839 .procname = "console_backoff",
840 .maxlen = sizeof(int),
841 .mode = 0644,
842 .proc_handler = &proc_console_backoff
843 },
844
845 {
846 .procname = "debug_path",
847 .data = libcfs_debug_file_path_arr,
848 .maxlen = sizeof(libcfs_debug_file_path_arr),
849 .mode = 0644,
850 .proc_handler = &proc_dostring,
851 },
852
853 {
854 .procname = "cpu_partition_table",
855 .maxlen = 128,
856 .mode = 0444,
857 .proc_handler = &proc_cpt_table,
858 },
859
860 {
861 .procname = "upcall",
862 .data = lnet_upcall,
863 .maxlen = sizeof(lnet_upcall),
864 .mode = 0644,
865 .proc_handler = &proc_dostring,
866 },
867 {
868 .procname = "debug_log_upcall",
869 .data = lnet_debug_log_upcall,
870 .maxlen = sizeof(lnet_debug_log_upcall),
871 .mode = 0644,
872 .proc_handler = &proc_dostring,
873 },
874 {
875 .procname = "lnet_memused",
876 .data = (int *)&libcfs_kmemory.counter,
877 .maxlen = sizeof(int),
878 .mode = 0444,
879 .proc_handler = &proc_dointvec,
880 },
881 {
882 .procname = "catastrophe",
883 .data = &libcfs_catastrophe,
884 .maxlen = sizeof(int),
885 .mode = 0444,
886 .proc_handler = &proc_dointvec,
887 },
888 {
889 .procname = "panic_on_lbug",
890 .data = &libcfs_panic_on_lbug,
891 .maxlen = sizeof(int),
892 .mode = 0644,
893 .proc_handler = &proc_dointvec,
894 },
895 {
896 .procname = "dump_kernel",
897 .maxlen = 256,
898 .mode = 0200,
899 .proc_handler = &proc_dump_kernel,
900 },
901 {
902 .procname = "daemon_file",
903 .mode = 0644,
904 .maxlen = 256,
905 .proc_handler = &proc_daemon_file,
906 },
907 {
908 .procname = "debug_mb",
909 .mode = 0644,
910 .proc_handler = &proc_debug_mb,
911 },
912 {
913 .procname = "watchdog_ratelimit",
914 .data = &libcfs_watchdog_ratelimit,
915 .maxlen = sizeof(int),
916 .mode = 0644,
917 .proc_handler = &proc_dointvec_minmax,
918 .extra1 = &min_watchdog_ratelimit,
919 .extra2 = &max_watchdog_ratelimit,
920 },
921 {
922 .procname = "force_lbug",
923 .data = NULL,
924 .maxlen = 0,
925 .mode = 0200,
926 .proc_handler = &libcfs_force_lbug
927 },
928 {
929 .procname = "fail_loc",
930 .data = &cfs_fail_loc,
931 .maxlen = sizeof(cfs_fail_loc),
932 .mode = 0644,
933 .proc_handler = &proc_fail_loc
934 },
935 {
936 .procname = "fail_val",
937 .data = &cfs_fail_val,
938 .maxlen = sizeof(int),
939 .mode = 0644,
940 .proc_handler = &proc_dointvec
941 },
942 {
943 }
944 };
945
946 static struct ctl_table top_table[] = {
947 {
948 .procname = "lnet",
949 .mode = 0555,
950 .data = NULL,
951 .maxlen = 0,
952 .child = lnet_table,
953 },
954 {
955 }
956 };
957
insert_proc(void)958 static int insert_proc(void)
959 {
960 if (lnet_table_header == NULL)
961 lnet_table_header = register_sysctl_table(top_table);
962 return 0;
963 }
964
remove_proc(void)965 static void remove_proc(void)
966 {
967 if (lnet_table_header != NULL)
968 unregister_sysctl_table(lnet_table_header);
969
970 lnet_table_header = NULL;
971 }
972
973 MODULE_VERSION("1.0.0");
974
975 module_init(init_libcfs_module);
976 module_exit(exit_libcfs_module);
977