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