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.gnu.org/licenses/gpl-2.0.html
19 *
20 * GPL HEADER END
21 */
22 /*
23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Use is subject to license terms.
25 *
26 * Copyright (c) 2012, 2015 Intel Corporation.
27 */
28 /*
29 * This file is part of Lustre, http://www.lustre.org/
30 * Lustre is a trademark of Sun Microsystems, Inc.
31 */
32 #include <linux/module.h>
33 #include <linux/kernel.h>
34 #include <linux/mm.h>
35 #include <linux/string.h>
36 #include <linux/stat.h>
37 #include <linux/errno.h>
38 #include <linux/unistd.h>
39 #include <net/sock.h>
40 #include <linux/uio.h>
41
42 #include <linux/uaccess.h>
43
44 #include <linux/fs.h>
45 #include <linux/file.h>
46 #include <linux/list.h>
47
48 #include <linux/sysctl.h>
49 #include <linux/debugfs.h>
50
51 # define DEBUG_SUBSYSTEM S_LNET
52
53 #include <linux/libcfs/libcfs.h>
54 #include <asm/div64.h>
55
56 #include <linux/libcfs/libcfs_crypto.h>
57 #include <linux/lnet/lib-lnet.h>
58 #include <uapi/linux/lnet/lnet-dlc.h>
59 #include "tracefile.h"
60
61 static struct dentry *lnet_debugfs_root;
62
63 static DECLARE_RWSEM(ioctl_list_sem);
64 static LIST_HEAD(ioctl_list);
65
libcfs_register_ioctl(struct libcfs_ioctl_handler * hand)66 int libcfs_register_ioctl(struct libcfs_ioctl_handler *hand)
67 {
68 int rc = 0;
69
70 down_write(&ioctl_list_sem);
71 if (!list_empty(&hand->item))
72 rc = -EBUSY;
73 else
74 list_add_tail(&hand->item, &ioctl_list);
75 up_write(&ioctl_list_sem);
76
77 return rc;
78 }
79 EXPORT_SYMBOL(libcfs_register_ioctl);
80
libcfs_deregister_ioctl(struct libcfs_ioctl_handler * hand)81 int libcfs_deregister_ioctl(struct libcfs_ioctl_handler *hand)
82 {
83 int rc = 0;
84
85 down_write(&ioctl_list_sem);
86 if (list_empty(&hand->item))
87 rc = -ENOENT;
88 else
89 list_del_init(&hand->item);
90 up_write(&ioctl_list_sem);
91
92 return rc;
93 }
94 EXPORT_SYMBOL(libcfs_deregister_ioctl);
95
libcfs_ioctl(unsigned long cmd,void __user * uparam)96 int libcfs_ioctl(unsigned long cmd, void __user *uparam)
97 {
98 struct libcfs_ioctl_data *data = NULL;
99 struct libcfs_ioctl_hdr *hdr;
100 int err;
101
102 /* 'cmd' and permissions get checked in our arch-specific caller */
103 err = libcfs_ioctl_getdata(&hdr, uparam);
104 if (err) {
105 CDEBUG_LIMIT(D_ERROR,
106 "libcfs ioctl: data header error %d\n", err);
107 return err;
108 }
109
110 if (hdr->ioc_version == LIBCFS_IOCTL_VERSION) {
111 /*
112 * The libcfs_ioctl_data_adjust() function performs adjustment
113 * operations on the libcfs_ioctl_data structure to make
114 * it usable by the code. This doesn't need to be called
115 * for new data structures added.
116 */
117 data = container_of(hdr, struct libcfs_ioctl_data, ioc_hdr);
118 err = libcfs_ioctl_data_adjust(data);
119 if (err)
120 goto out;
121 }
122
123 CDEBUG(D_IOCTL, "libcfs ioctl cmd %lu\n", cmd);
124 switch (cmd) {
125 case IOC_LIBCFS_CLEAR_DEBUG:
126 libcfs_debug_clear_buffer();
127 break;
128
129 case IOC_LIBCFS_MARK_DEBUG:
130 if (!data || !data->ioc_inlbuf1 ||
131 data->ioc_inlbuf1[data->ioc_inllen1 - 1] != '\0') {
132 err = -EINVAL;
133 goto out;
134 }
135 libcfs_debug_mark_buffer(data->ioc_inlbuf1);
136 break;
137
138 default: {
139 struct libcfs_ioctl_handler *hand;
140
141 err = -EINVAL;
142 down_read(&ioctl_list_sem);
143 list_for_each_entry(hand, &ioctl_list, item) {
144 err = hand->handle_ioctl(cmd, hdr);
145 if (err == -EINVAL)
146 continue;
147
148 if (!err) {
149 if (copy_to_user(uparam, hdr, hdr->ioc_len))
150 err = -EFAULT;
151 }
152 break;
153 }
154 up_read(&ioctl_list_sem);
155 break; }
156 }
157 out:
158 LIBCFS_FREE(hdr, hdr->ioc_len);
159 return err;
160 }
161
lprocfs_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))162 int lprocfs_call_handler(void *data, int write, loff_t *ppos,
163 void __user *buffer, size_t *lenp,
164 int (*handler)(void *data, int write, loff_t pos,
165 void __user *buffer, int len))
166 {
167 int rc = handler(data, write, *ppos, buffer, *lenp);
168
169 if (rc < 0)
170 return rc;
171
172 if (write) {
173 *ppos += *lenp;
174 } else {
175 *lenp = rc;
176 *ppos += rc;
177 }
178 return 0;
179 }
180 EXPORT_SYMBOL(lprocfs_call_handler);
181
__proc_dobitmasks(void * data,int write,loff_t pos,void __user * buffer,int nob)182 static int __proc_dobitmasks(void *data, int write,
183 loff_t pos, void __user *buffer, int nob)
184 {
185 const int tmpstrlen = 512;
186 char *tmpstr;
187 int rc;
188 unsigned int *mask = data;
189 int is_subsys = (mask == &libcfs_subsystem_debug) ? 1 : 0;
190 int is_printk = (mask == &libcfs_printk) ? 1 : 0;
191
192 rc = cfs_trace_allocate_string_buffer(&tmpstr, tmpstrlen);
193 if (rc < 0)
194 return rc;
195
196 if (!write) {
197 libcfs_debug_mask2str(tmpstr, tmpstrlen, *mask, is_subsys);
198 rc = strlen(tmpstr);
199
200 if (pos >= rc) {
201 rc = 0;
202 } else {
203 rc = cfs_trace_copyout_string(buffer, nob,
204 tmpstr + pos, "\n");
205 }
206 } else {
207 rc = cfs_trace_copyin_string(tmpstr, tmpstrlen, buffer, nob);
208 if (rc < 0) {
209 kfree(tmpstr);
210 return rc;
211 }
212
213 rc = libcfs_debug_str2mask(mask, tmpstr, is_subsys);
214 /* Always print LBUG/LASSERT to console, so keep this mask */
215 if (is_printk)
216 *mask |= D_EMERG;
217 }
218
219 kfree(tmpstr);
220 return rc;
221 }
222
proc_dobitmasks(struct ctl_table * table,int write,void __user * buffer,size_t * lenp,loff_t * ppos)223 static int proc_dobitmasks(struct ctl_table *table, int write,
224 void __user *buffer, size_t *lenp, loff_t *ppos)
225 {
226 return lprocfs_call_handler(table->data, write, ppos, buffer, lenp,
227 __proc_dobitmasks);
228 }
229
__proc_dump_kernel(void * data,int write,loff_t pos,void __user * buffer,int nob)230 static int __proc_dump_kernel(void *data, int write,
231 loff_t pos, void __user *buffer, int nob)
232 {
233 if (!write)
234 return 0;
235
236 return cfs_trace_dump_debug_buffer_usrstr(buffer, nob);
237 }
238
proc_dump_kernel(struct ctl_table * table,int write,void __user * buffer,size_t * lenp,loff_t * ppos)239 static int proc_dump_kernel(struct ctl_table *table, int write,
240 void __user *buffer, size_t *lenp, loff_t *ppos)
241 {
242 return lprocfs_call_handler(table->data, write, ppos, buffer, lenp,
243 __proc_dump_kernel);
244 }
245
__proc_daemon_file(void * data,int write,loff_t pos,void __user * buffer,int nob)246 static int __proc_daemon_file(void *data, int write,
247 loff_t pos, void __user *buffer, int nob)
248 {
249 if (!write) {
250 int len = strlen(cfs_tracefile);
251
252 if (pos >= len)
253 return 0;
254
255 return cfs_trace_copyout_string(buffer, nob,
256 cfs_tracefile + pos, "\n");
257 }
258
259 return cfs_trace_daemon_command_usrstr(buffer, nob);
260 }
261
proc_daemon_file(struct ctl_table * table,int write,void __user * buffer,size_t * lenp,loff_t * ppos)262 static int proc_daemon_file(struct ctl_table *table, int write,
263 void __user *buffer, size_t *lenp, loff_t *ppos)
264 {
265 return lprocfs_call_handler(table->data, write, ppos, buffer, lenp,
266 __proc_daemon_file);
267 }
268
libcfs_force_lbug(struct ctl_table * table,int write,void __user * buffer,size_t * lenp,loff_t * ppos)269 static int libcfs_force_lbug(struct ctl_table *table, int write,
270 void __user *buffer,
271 size_t *lenp, loff_t *ppos)
272 {
273 if (write)
274 LBUG();
275 return 0;
276 }
277
proc_fail_loc(struct ctl_table * table,int write,void __user * buffer,size_t * lenp,loff_t * ppos)278 static int proc_fail_loc(struct ctl_table *table, int write,
279 void __user *buffer,
280 size_t *lenp, loff_t *ppos)
281 {
282 int rc;
283 long old_fail_loc = cfs_fail_loc;
284
285 rc = proc_doulongvec_minmax(table, write, buffer, lenp, ppos);
286 if (old_fail_loc != cfs_fail_loc)
287 wake_up(&cfs_race_waitq);
288 return rc;
289 }
290
__proc_cpt_table(void * data,int write,loff_t pos,void __user * buffer,int nob)291 static int __proc_cpt_table(void *data, int write,
292 loff_t pos, void __user *buffer, int nob)
293 {
294 char *buf = NULL;
295 int len = 4096;
296 int rc = 0;
297
298 if (write)
299 return -EPERM;
300
301 LASSERT(cfs_cpt_table);
302
303 while (1) {
304 LIBCFS_ALLOC(buf, len);
305 if (!buf)
306 return -ENOMEM;
307
308 rc = cfs_cpt_table_print(cfs_cpt_table, buf, len);
309 if (rc >= 0)
310 break;
311
312 if (rc == -EFBIG) {
313 LIBCFS_FREE(buf, len);
314 len <<= 1;
315 continue;
316 }
317 goto out;
318 }
319
320 if (pos >= rc) {
321 rc = 0;
322 goto out;
323 }
324
325 rc = cfs_trace_copyout_string(buffer, nob, buf + pos, NULL);
326 out:
327 if (buf)
328 LIBCFS_FREE(buf, len);
329 return rc;
330 }
331
proc_cpt_table(struct ctl_table * table,int write,void __user * buffer,size_t * lenp,loff_t * ppos)332 static int proc_cpt_table(struct ctl_table *table, int write,
333 void __user *buffer, size_t *lenp, loff_t *ppos)
334 {
335 return lprocfs_call_handler(table->data, write, ppos, buffer, lenp,
336 __proc_cpt_table);
337 }
338
339 static struct ctl_table lnet_table[] = {
340 {
341 .procname = "debug",
342 .data = &libcfs_debug,
343 .maxlen = sizeof(int),
344 .mode = 0644,
345 .proc_handler = &proc_dobitmasks,
346 },
347 {
348 .procname = "subsystem_debug",
349 .data = &libcfs_subsystem_debug,
350 .maxlen = sizeof(int),
351 .mode = 0644,
352 .proc_handler = &proc_dobitmasks,
353 },
354 {
355 .procname = "printk",
356 .data = &libcfs_printk,
357 .maxlen = sizeof(int),
358 .mode = 0644,
359 .proc_handler = &proc_dobitmasks,
360 },
361 {
362 .procname = "cpu_partition_table",
363 .maxlen = 128,
364 .mode = 0444,
365 .proc_handler = &proc_cpt_table,
366 },
367 {
368 .procname = "debug_log_upcall",
369 .data = lnet_debug_log_upcall,
370 .maxlen = sizeof(lnet_debug_log_upcall),
371 .mode = 0644,
372 .proc_handler = &proc_dostring,
373 },
374 {
375 .procname = "catastrophe",
376 .data = &libcfs_catastrophe,
377 .maxlen = sizeof(int),
378 .mode = 0444,
379 .proc_handler = &proc_dointvec,
380 },
381 {
382 .procname = "dump_kernel",
383 .maxlen = 256,
384 .mode = 0200,
385 .proc_handler = &proc_dump_kernel,
386 },
387 {
388 .procname = "daemon_file",
389 .mode = 0644,
390 .maxlen = 256,
391 .proc_handler = &proc_daemon_file,
392 },
393 {
394 .procname = "force_lbug",
395 .data = NULL,
396 .maxlen = 0,
397 .mode = 0200,
398 .proc_handler = &libcfs_force_lbug
399 },
400 {
401 .procname = "fail_loc",
402 .data = &cfs_fail_loc,
403 .maxlen = sizeof(cfs_fail_loc),
404 .mode = 0644,
405 .proc_handler = &proc_fail_loc
406 },
407 {
408 .procname = "fail_val",
409 .data = &cfs_fail_val,
410 .maxlen = sizeof(int),
411 .mode = 0644,
412 .proc_handler = &proc_dointvec
413 },
414 {
415 .procname = "fail_err",
416 .data = &cfs_fail_err,
417 .maxlen = sizeof(cfs_fail_err),
418 .mode = 0644,
419 .proc_handler = &proc_dointvec,
420 },
421 {
422 }
423 };
424
425 static const struct lnet_debugfs_symlink_def lnet_debugfs_symlinks[] = {
426 { "console_ratelimit",
427 "/sys/module/libcfs/parameters/libcfs_console_ratelimit"},
428 { "debug_path",
429 "/sys/module/libcfs/parameters/libcfs_debug_file_path"},
430 { "panic_on_lbug",
431 "/sys/module/libcfs/parameters/libcfs_panic_on_lbug"},
432 { "libcfs_console_backoff",
433 "/sys/module/libcfs/parameters/libcfs_console_backoff"},
434 { "debug_mb",
435 "/sys/module/libcfs/parameters/libcfs_debug_mb"},
436 { "console_min_delay_centisecs",
437 "/sys/module/libcfs/parameters/libcfs_console_min_delay"},
438 { "console_max_delay_centisecs",
439 "/sys/module/libcfs/parameters/libcfs_console_max_delay"},
440 {},
441 };
442
lnet_debugfs_read(struct file * filp,char __user * buf,size_t count,loff_t * ppos)443 static ssize_t lnet_debugfs_read(struct file *filp, char __user *buf,
444 size_t count, loff_t *ppos)
445 {
446 struct ctl_table *table = filp->private_data;
447 int error;
448
449 error = table->proc_handler(table, 0, (void __user *)buf, &count, ppos);
450 if (!error)
451 error = count;
452
453 return error;
454 }
455
lnet_debugfs_write(struct file * filp,const char __user * buf,size_t count,loff_t * ppos)456 static ssize_t lnet_debugfs_write(struct file *filp, const char __user *buf,
457 size_t count, loff_t *ppos)
458 {
459 struct ctl_table *table = filp->private_data;
460 int error;
461
462 error = table->proc_handler(table, 1, (void __user *)buf, &count, ppos);
463 if (!error)
464 error = count;
465
466 return error;
467 }
468
469 static const struct file_operations lnet_debugfs_file_operations_rw = {
470 .open = simple_open,
471 .read = lnet_debugfs_read,
472 .write = lnet_debugfs_write,
473 .llseek = default_llseek,
474 };
475
476 static const struct file_operations lnet_debugfs_file_operations_ro = {
477 .open = simple_open,
478 .read = lnet_debugfs_read,
479 .llseek = default_llseek,
480 };
481
482 static const struct file_operations lnet_debugfs_file_operations_wo = {
483 .open = simple_open,
484 .write = lnet_debugfs_write,
485 .llseek = default_llseek,
486 };
487
lnet_debugfs_fops_select(umode_t mode)488 static const struct file_operations *lnet_debugfs_fops_select(umode_t mode)
489 {
490 if (!(mode & 0222))
491 return &lnet_debugfs_file_operations_ro;
492
493 if (!(mode & 0444))
494 return &lnet_debugfs_file_operations_wo;
495
496 return &lnet_debugfs_file_operations_rw;
497 }
498
lustre_insert_debugfs(struct ctl_table * table,const struct lnet_debugfs_symlink_def * symlinks)499 void lustre_insert_debugfs(struct ctl_table *table,
500 const struct lnet_debugfs_symlink_def *symlinks)
501 {
502 if (!lnet_debugfs_root)
503 lnet_debugfs_root = debugfs_create_dir("lnet", NULL);
504
505 /* Even if we cannot create, just ignore it altogether) */
506 if (IS_ERR_OR_NULL(lnet_debugfs_root))
507 return;
508
509 /* We don't save the dentry returned in next two calls, because
510 * we don't call debugfs_remove() but rather remove_recursive()
511 */
512 for (; table->procname; table++)
513 debugfs_create_file(table->procname, table->mode,
514 lnet_debugfs_root, table,
515 lnet_debugfs_fops_select(table->mode));
516
517 for (; symlinks && symlinks->name; symlinks++)
518 debugfs_create_symlink(symlinks->name, lnet_debugfs_root,
519 symlinks->target);
520 }
521 EXPORT_SYMBOL_GPL(lustre_insert_debugfs);
522
lustre_remove_debugfs(void)523 static void lustre_remove_debugfs(void)
524 {
525 debugfs_remove_recursive(lnet_debugfs_root);
526
527 lnet_debugfs_root = NULL;
528 }
529
libcfs_init(void)530 static int libcfs_init(void)
531 {
532 int rc;
533
534 rc = libcfs_debug_init(5 * 1024 * 1024);
535 if (rc < 0) {
536 pr_err("LustreError: libcfs_debug_init: %d\n", rc);
537 return rc;
538 }
539
540 rc = cfs_cpu_init();
541 if (rc)
542 goto cleanup_debug;
543
544 rc = misc_register(&libcfs_dev);
545 if (rc) {
546 CERROR("misc_register: error %d\n", rc);
547 goto cleanup_cpu;
548 }
549
550 rc = cfs_wi_startup();
551 if (rc) {
552 CERROR("initialize workitem: error %d\n", rc);
553 goto cleanup_deregister;
554 }
555
556 /* max to 4 threads, should be enough for rehash */
557 rc = min(cfs_cpt_weight(cfs_cpt_table, CFS_CPT_ANY), 4);
558 rc = cfs_wi_sched_create("cfs_rh", cfs_cpt_table, CFS_CPT_ANY,
559 rc, &cfs_sched_rehash);
560 if (rc) {
561 CERROR("Startup workitem scheduler: error: %d\n", rc);
562 goto cleanup_deregister;
563 }
564
565 rc = cfs_crypto_register();
566 if (rc) {
567 CERROR("cfs_crypto_register: error %d\n", rc);
568 goto cleanup_wi;
569 }
570
571 lustre_insert_debugfs(lnet_table, lnet_debugfs_symlinks);
572
573 CDEBUG(D_OTHER, "portals setup OK\n");
574 return 0;
575 cleanup_wi:
576 cfs_wi_shutdown();
577 cleanup_deregister:
578 misc_deregister(&libcfs_dev);
579 cleanup_cpu:
580 cfs_cpu_fini();
581 cleanup_debug:
582 libcfs_debug_cleanup();
583 return rc;
584 }
585
libcfs_exit(void)586 static void libcfs_exit(void)
587 {
588 int rc;
589
590 lustre_remove_debugfs();
591
592 if (cfs_sched_rehash) {
593 cfs_wi_sched_destroy(cfs_sched_rehash);
594 cfs_sched_rehash = NULL;
595 }
596
597 cfs_crypto_unregister();
598 cfs_wi_shutdown();
599
600 misc_deregister(&libcfs_dev);
601
602 cfs_cpu_fini();
603
604 rc = libcfs_debug_cleanup();
605 if (rc)
606 pr_err("LustreError: libcfs_debug_cleanup: %d\n", rc);
607 }
608
609 MODULE_AUTHOR("OpenSFS, Inc. <http://www.lustre.org/>");
610 MODULE_DESCRIPTION("Lustre helper library");
611 MODULE_VERSION(LIBCFS_VERSION);
612 MODULE_LICENSE("GPL");
613
614 module_init(libcfs_init);
615 module_exit(libcfs_exit);
616