Staging: lustre: libcfs: Remove unnecessary cast on void*
[pandora-kernel.git] / drivers / staging / lustre / lustre / libcfs / module.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) 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/sysctl.h>
53 #include <linux/debugfs.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 cfs_wi_sched *cfs_sched_rehash;
71 extern void libcfs_init_nidstrings(void);
72
73 static void insert_debugfs(void);
74 static void remove_debugfs(void);
75
76 static struct dentry *lnet_debugfs_root;
77 extern char lnet_upcall[1024];
78 /**
79  * The path of debug log dump upcall script.
80  */
81 extern char lnet_debug_log_upcall[1024];
82
83 static void kportal_memhog_free(struct libcfs_device_userstate *ldu)
84 {
85         struct page **level0p = &ldu->ldu_memhog_root_page;
86         struct page **level1p;
87         struct page **level2p;
88         int        count1;
89         int        count2;
90
91         if (*level0p != NULL) {
92
93                 level1p = (struct page **)page_address(*level0p);
94                 count1 = 0;
95
96                 while (count1 < PAGE_CACHE_SIZE/sizeof(struct page *) &&
97                        *level1p != NULL) {
98
99                         level2p = (struct page **)page_address(*level1p);
100                         count2 = 0;
101
102                         while (count2 < PAGE_CACHE_SIZE/sizeof(struct page *) &&
103                                *level2p != NULL) {
104
105                                 __free_page(*level2p);
106                                 ldu->ldu_memhog_pages--;
107                                 level2p++;
108                                 count2++;
109                         }
110
111                         __free_page(*level1p);
112                         ldu->ldu_memhog_pages--;
113                         level1p++;
114                         count1++;
115                 }
116
117                 __free_page(*level0p);
118                 ldu->ldu_memhog_pages--;
119
120                 *level0p = NULL;
121         }
122
123         LASSERT(ldu->ldu_memhog_pages == 0);
124 }
125
126 static int kportal_memhog_alloc(struct libcfs_device_userstate *ldu, int npages,
127                      gfp_t flags)
128 {
129         struct page **level0p;
130         struct page **level1p;
131         struct page **level2p;
132         int        count1;
133         int        count2;
134
135         LASSERT(ldu->ldu_memhog_pages == 0);
136         LASSERT(ldu->ldu_memhog_root_page == NULL);
137
138         if (npages < 0)
139                 return -EINVAL;
140
141         if (npages == 0)
142                 return 0;
143
144         level0p = &ldu->ldu_memhog_root_page;
145         *level0p = alloc_page(flags);
146         if (*level0p == NULL)
147                 return -ENOMEM;
148         ldu->ldu_memhog_pages++;
149
150         level1p = (struct page **)page_address(*level0p);
151         count1 = 0;
152         memset(level1p, 0, PAGE_CACHE_SIZE);
153
154         while (ldu->ldu_memhog_pages < npages &&
155                count1 < PAGE_CACHE_SIZE/sizeof(struct page *)) {
156
157                 if (cfs_signal_pending())
158                         return -EINTR;
159
160                 *level1p = alloc_page(flags);
161                 if (*level1p == NULL)
162                         return -ENOMEM;
163                 ldu->ldu_memhog_pages++;
164
165                 level2p = (struct page **)page_address(*level1p);
166                 count2 = 0;
167                 memset(level2p, 0, PAGE_CACHE_SIZE);
168
169                 while (ldu->ldu_memhog_pages < npages &&
170                        count2 < PAGE_CACHE_SIZE/sizeof(struct page *)) {
171
172                         if (cfs_signal_pending())
173                                 return -EINTR;
174
175                         *level2p = alloc_page(flags);
176                         if (*level2p == NULL)
177                                 return -ENOMEM;
178                         ldu->ldu_memhog_pages++;
179
180                         level2p++;
181                         count2++;
182                 }
183
184                 level1p++;
185                 count1++;
186         }
187
188         return 0;
189 }
190
191 /* called when opening /dev/device */
192 static int libcfs_psdev_open(unsigned long flags, void *args)
193 {
194         struct libcfs_device_userstate *ldu;
195
196         try_module_get(THIS_MODULE);
197
198         LIBCFS_ALLOC(ldu, sizeof(*ldu));
199         if (ldu != NULL) {
200                 ldu->ldu_memhog_pages = 0;
201                 ldu->ldu_memhog_root_page = NULL;
202         }
203         *(struct libcfs_device_userstate **)args = ldu;
204
205         return 0;
206 }
207
208 /* called when closing /dev/device */
209 static int libcfs_psdev_release(unsigned long flags, void *args)
210 {
211         struct libcfs_device_userstate *ldu;
212
213         ldu = (struct libcfs_device_userstate *)args;
214         if (ldu != NULL) {
215                 kportal_memhog_free(ldu);
216                 LIBCFS_FREE(ldu, sizeof(*ldu));
217         }
218
219         module_put(THIS_MODULE);
220         return 0;
221 }
222
223 static DECLARE_RWSEM(ioctl_list_sem);
224 static LIST_HEAD(ioctl_list);
225
226 int libcfs_register_ioctl(struct libcfs_ioctl_handler *hand)
227 {
228         int rc = 0;
229
230         down_write(&ioctl_list_sem);
231         if (!list_empty(&hand->item))
232                 rc = -EBUSY;
233         else
234                 list_add_tail(&hand->item, &ioctl_list);
235         up_write(&ioctl_list_sem);
236
237         return rc;
238 }
239 EXPORT_SYMBOL(libcfs_register_ioctl);
240
241 int libcfs_deregister_ioctl(struct libcfs_ioctl_handler *hand)
242 {
243         int rc = 0;
244
245         down_write(&ioctl_list_sem);
246         if (list_empty(&hand->item))
247                 rc = -ENOENT;
248         else
249                 list_del_init(&hand->item);
250         up_write(&ioctl_list_sem);
251
252         return rc;
253 }
254 EXPORT_SYMBOL(libcfs_deregister_ioctl);
255
256 static int libcfs_ioctl_int(struct cfs_psdev_file *pfile, unsigned long cmd,
257                             void *arg, struct libcfs_ioctl_data *data)
258 {
259         int err = -EINVAL;
260
261         switch (cmd) {
262         case IOC_LIBCFS_CLEAR_DEBUG:
263                 libcfs_debug_clear_buffer();
264                 return 0;
265         /*
266          * case IOC_LIBCFS_PANIC:
267          * Handled in arch/cfs_module.c
268          */
269         case IOC_LIBCFS_MARK_DEBUG:
270                 if (data->ioc_inlbuf1 == NULL ||
271                     data->ioc_inlbuf1[data->ioc_inllen1 - 1] != '\0')
272                         return -EINVAL;
273                 libcfs_debug_mark_buffer(data->ioc_inlbuf1);
274                 return 0;
275         case IOC_LIBCFS_MEMHOG:
276                 if (pfile->private_data == NULL) {
277                         err = -EINVAL;
278                 } else {
279                         kportal_memhog_free(pfile->private_data);
280                         /* XXX The ioc_flags is not GFP flags now, need to be fixed */
281                         err = kportal_memhog_alloc(pfile->private_data,
282                                                    data->ioc_count,
283                                                    data->ioc_flags);
284                         if (err != 0)
285                                 kportal_memhog_free(pfile->private_data);
286                 }
287                 break;
288
289         case IOC_LIBCFS_PING_TEST: {
290                 extern void (kping_client)(struct libcfs_ioctl_data *);
291                 void (*ping)(struct libcfs_ioctl_data *);
292
293                 CDEBUG(D_IOCTL, "doing %d pings to nid %s (%s)\n",
294                        data->ioc_count, libcfs_nid2str(data->ioc_nid),
295                        libcfs_nid2str(data->ioc_nid));
296                 ping = symbol_get(kping_client);
297                 if (!ping)
298                         CERROR("symbol_get failed\n");
299                 else {
300                         ping(data);
301                         symbol_put(kping_client);
302                 }
303                 return 0;
304         }
305
306         default: {
307                 struct libcfs_ioctl_handler *hand;
308                 err = -EINVAL;
309                 down_read(&ioctl_list_sem);
310                 list_for_each_entry(hand, &ioctl_list, item) {
311                         err = hand->handle_ioctl(cmd, data);
312                         if (err != -EINVAL) {
313                                 if (err == 0)
314                                         err = libcfs_ioctl_popdata(arg,
315                                                         data, sizeof(*data));
316                                 break;
317                         }
318                 }
319                 up_read(&ioctl_list_sem);
320                 break;
321         }
322         }
323
324         return err;
325 }
326
327 static int libcfs_ioctl(struct cfs_psdev_file *pfile, unsigned long cmd, void *arg)
328 {
329         char    *buf;
330         struct libcfs_ioctl_data *data;
331         int err = 0;
332
333         LIBCFS_ALLOC_GFP(buf, 1024, GFP_IOFS);
334         if (buf == NULL)
335                 return -ENOMEM;
336
337         /* 'cmd' and permissions get checked in our arch-specific caller */
338         if (libcfs_ioctl_getdata(buf, buf + 800, arg)) {
339                 CERROR("PORTALS ioctl: data error\n");
340                 err = -EINVAL;
341                 goto out;
342         }
343         data = (struct libcfs_ioctl_data *)buf;
344
345         err = libcfs_ioctl_int(pfile, cmd, arg, data);
346
347 out:
348         LIBCFS_FREE(buf, 1024);
349         return err;
350 }
351
352
353 struct cfs_psdev_ops libcfs_psdev_ops = {
354         libcfs_psdev_open,
355         libcfs_psdev_release,
356         NULL,
357         NULL,
358         libcfs_ioctl
359 };
360
361 static int init_libcfs_module(void)
362 {
363         int rc;
364
365         libcfs_arch_init();
366         libcfs_init_nidstrings();
367
368         rc = libcfs_debug_init(5 * 1024 * 1024);
369         if (rc < 0) {
370                 pr_err("LustreError: libcfs_debug_init: %d\n", rc);
371                 return rc;
372         }
373
374         rc = cfs_cpu_init();
375         if (rc != 0)
376                 goto cleanup_debug;
377
378         rc = misc_register(&libcfs_dev);
379         if (rc) {
380                 CERROR("misc_register: error %d\n", rc);
381                 goto cleanup_cpu;
382         }
383
384         rc = cfs_wi_startup();
385         if (rc) {
386                 CERROR("initialize workitem: error %d\n", rc);
387                 goto cleanup_deregister;
388         }
389
390         /* max to 4 threads, should be enough for rehash */
391         rc = min(cfs_cpt_weight(cfs_cpt_table, CFS_CPT_ANY), 4);
392         rc = cfs_wi_sched_create("cfs_rh", cfs_cpt_table, CFS_CPT_ANY,
393                                  rc, &cfs_sched_rehash);
394         if (rc != 0) {
395                 CERROR("Startup workitem scheduler: error: %d\n", rc);
396                 goto cleanup_deregister;
397         }
398
399         rc = cfs_crypto_register();
400         if (rc) {
401                 CERROR("cfs_crypto_register: error %d\n", rc);
402                 goto cleanup_wi;
403         }
404
405         insert_debugfs();
406
407         CDEBUG(D_OTHER, "portals setup OK\n");
408         return 0;
409  cleanup_wi:
410         cfs_wi_shutdown();
411  cleanup_deregister:
412         misc_deregister(&libcfs_dev);
413 cleanup_cpu:
414         cfs_cpu_fini();
415  cleanup_debug:
416         libcfs_debug_cleanup();
417         return rc;
418 }
419
420 static void exit_libcfs_module(void)
421 {
422         int rc;
423
424         remove_debugfs();
425
426         if (cfs_sched_rehash != NULL) {
427                 cfs_wi_sched_destroy(cfs_sched_rehash);
428                 cfs_sched_rehash = NULL;
429         }
430
431         cfs_crypto_unregister();
432         cfs_wi_shutdown();
433
434         rc = misc_deregister(&libcfs_dev);
435         if (rc)
436                 CERROR("misc_deregister error %d\n", rc);
437
438         cfs_cpu_fini();
439
440         rc = libcfs_debug_cleanup();
441         if (rc)
442                 pr_err("LustreError: libcfs_debug_cleanup: %d\n", rc);
443
444         libcfs_arch_cleanup();
445 }
446
447 static int proc_call_handler(void *data, int write, loff_t *ppos,
448                 void __user *buffer, size_t *lenp,
449                 int (*handler)(void *data, int write,
450                 loff_t pos, void __user *buffer, int len))
451 {
452         int rc = handler(data, write, *ppos, buffer, *lenp);
453
454         if (rc < 0)
455                 return rc;
456
457         if (write) {
458                 *ppos += *lenp;
459         } else {
460                 *lenp = rc;
461                 *ppos += rc;
462         }
463         return 0;
464 }
465
466 static int __proc_dobitmasks(void *data, int write,
467                              loff_t pos, void __user *buffer, int nob)
468 {
469         const int     tmpstrlen = 512;
470         char     *tmpstr;
471         int        rc;
472         unsigned int *mask = data;
473         int        is_subsys = (mask == &libcfs_subsystem_debug) ? 1 : 0;
474         int        is_printk = (mask == &libcfs_printk) ? 1 : 0;
475
476         rc = cfs_trace_allocate_string_buffer(&tmpstr, tmpstrlen);
477         if (rc < 0)
478                 return rc;
479
480         if (!write) {
481                 libcfs_debug_mask2str(tmpstr, tmpstrlen, *mask, is_subsys);
482                 rc = strlen(tmpstr);
483
484                 if (pos >= rc) {
485                         rc = 0;
486                 } else {
487                         rc = cfs_trace_copyout_string(buffer, nob,
488                                                       tmpstr + pos, "\n");
489                 }
490         } else {
491                 rc = cfs_trace_copyin_string(tmpstr, tmpstrlen, buffer, nob);
492                 if (rc < 0) {
493                         cfs_trace_free_string_buffer(tmpstr, tmpstrlen);
494                         return rc;
495                 }
496
497                 rc = libcfs_debug_str2mask(mask, tmpstr, is_subsys);
498                 /* Always print LBUG/LASSERT to console, so keep this mask */
499                 if (is_printk)
500                         *mask |= D_EMERG;
501         }
502
503         cfs_trace_free_string_buffer(tmpstr, tmpstrlen);
504         return rc;
505 }
506
507 static int proc_dobitmasks(struct ctl_table *table, int write,
508                            void __user *buffer, size_t *lenp, loff_t *ppos)
509 {
510         return proc_call_handler(table->data, write, ppos, buffer, lenp,
511                                  __proc_dobitmasks);
512 }
513
514 static int __proc_dump_kernel(void *data, int write,
515                               loff_t pos, void __user *buffer, int nob)
516 {
517         if (!write)
518                 return 0;
519
520         return cfs_trace_dump_debug_buffer_usrstr(buffer, nob);
521 }
522
523 static int proc_dump_kernel(struct ctl_table *table, int write,
524                             void __user *buffer, size_t *lenp, loff_t *ppos)
525 {
526         return proc_call_handler(table->data, write, ppos, buffer, lenp,
527                                  __proc_dump_kernel);
528 }
529
530 static int __proc_daemon_file(void *data, int write,
531                               loff_t pos, void __user *buffer, int nob)
532 {
533         if (!write) {
534                 int len = strlen(cfs_tracefile);
535
536                 if (pos >= len)
537                         return 0;
538
539                 return cfs_trace_copyout_string(buffer, nob,
540                                                 cfs_tracefile + pos, "\n");
541         }
542
543         return cfs_trace_daemon_command_usrstr(buffer, nob);
544 }
545
546 static int proc_daemon_file(struct ctl_table *table, int write,
547                             void __user *buffer, size_t *lenp, loff_t *ppos)
548 {
549         return proc_call_handler(table->data, write, ppos, buffer, lenp,
550                                  __proc_daemon_file);
551 }
552
553 static int libcfs_force_lbug(struct ctl_table *table, int write,
554                              void __user *buffer,
555                              size_t *lenp, loff_t *ppos)
556 {
557         if (write)
558                 LBUG();
559         return 0;
560 }
561
562 static int proc_fail_loc(struct ctl_table *table, int write,
563                          void __user *buffer,
564                          size_t *lenp, loff_t *ppos)
565 {
566         int rc;
567         long old_fail_loc = cfs_fail_loc;
568
569         rc = proc_doulongvec_minmax(table, write, buffer, lenp, ppos);
570         if (old_fail_loc != cfs_fail_loc)
571                 wake_up(&cfs_race_waitq);
572         return rc;
573 }
574
575 static int __proc_cpt_table(void *data, int write,
576                             loff_t pos, void __user *buffer, int nob)
577 {
578         char *buf = NULL;
579         int   len = 4096;
580         int   rc  = 0;
581
582         if (write)
583                 return -EPERM;
584
585         LASSERT(cfs_cpt_table != NULL);
586
587         while (1) {
588                 LIBCFS_ALLOC(buf, len);
589                 if (buf == NULL)
590                         return -ENOMEM;
591
592                 rc = cfs_cpt_table_print(cfs_cpt_table, buf, len);
593                 if (rc >= 0)
594                         break;
595
596                 if (rc == -EFBIG) {
597                         LIBCFS_FREE(buf, len);
598                         len <<= 1;
599                         continue;
600                 }
601                 goto out;
602         }
603
604         if (pos >= rc) {
605                 rc = 0;
606                 goto out;
607         }
608
609         rc = cfs_trace_copyout_string(buffer, nob, buf + pos, NULL);
610  out:
611         if (buf != NULL)
612                 LIBCFS_FREE(buf, len);
613         return rc;
614 }
615
616 static int proc_cpt_table(struct ctl_table *table, int write,
617                            void __user *buffer, size_t *lenp, loff_t *ppos)
618 {
619         return proc_call_handler(table->data, write, ppos, buffer, lenp,
620                                  __proc_cpt_table);
621 }
622
623 static struct ctl_table lnet_table[] = {
624         /*
625          * NB No .strategy entries have been provided since sysctl(8) prefers
626          * to go via /proc for portability.
627          */
628         {
629                 .procname = "debug",
630                 .data     = &libcfs_debug,
631                 .maxlen   = sizeof(int),
632                 .mode     = 0644,
633                 .proc_handler = &proc_dobitmasks,
634         },
635         {
636                 .procname = "subsystem_debug",
637                 .data     = &libcfs_subsystem_debug,
638                 .maxlen   = sizeof(int),
639                 .mode     = 0644,
640                 .proc_handler = &proc_dobitmasks,
641         },
642         {
643                 .procname = "printk",
644                 .data     = &libcfs_printk,
645                 .maxlen   = sizeof(int),
646                 .mode     = 0644,
647                 .proc_handler = &proc_dobitmasks,
648         },
649         {
650                 .procname = "cpu_partition_table",
651                 .maxlen   = 128,
652                 .mode     = 0444,
653                 .proc_handler = &proc_cpt_table,
654         },
655
656         {
657                 .procname = "upcall",
658                 .data     = lnet_upcall,
659                 .maxlen   = sizeof(lnet_upcall),
660                 .mode     = 0644,
661                 .proc_handler = &proc_dostring,
662         },
663         {
664                 .procname = "debug_log_upcall",
665                 .data     = lnet_debug_log_upcall,
666                 .maxlen   = sizeof(lnet_debug_log_upcall),
667                 .mode     = 0644,
668                 .proc_handler = &proc_dostring,
669         },
670         {
671                 .procname = "catastrophe",
672                 .data     = &libcfs_catastrophe,
673                 .maxlen   = sizeof(int),
674                 .mode     = 0444,
675                 .proc_handler = &proc_dointvec,
676         },
677         {
678                 .procname = "dump_kernel",
679                 .maxlen   = 256,
680                 .mode     = 0200,
681                 .proc_handler = &proc_dump_kernel,
682         },
683         {
684                 .procname = "daemon_file",
685                 .mode     = 0644,
686                 .maxlen   = 256,
687                 .proc_handler = &proc_daemon_file,
688         },
689         {
690                 .procname = "force_lbug",
691                 .data     = NULL,
692                 .maxlen   = 0,
693                 .mode     = 0200,
694                 .proc_handler = &libcfs_force_lbug
695         },
696         {
697                 .procname = "fail_loc",
698                 .data     = &cfs_fail_loc,
699                 .maxlen   = sizeof(cfs_fail_loc),
700                 .mode     = 0644,
701                 .proc_handler = &proc_fail_loc
702         },
703         {
704                 .procname = "fail_val",
705                 .data     = &cfs_fail_val,
706                 .maxlen   = sizeof(int),
707                 .mode     = 0644,
708                 .proc_handler = &proc_dointvec
709         },
710         {
711         }
712 };
713
714 struct lnet_debugfs_symlink_def {
715         char *name;
716         char *target;
717 };
718
719 struct lnet_debugfs_symlink_def lnet_debugfs_symlinks[] = {
720         { "console_ratelimit",
721           "/sys/module/libcfs/parameters/libcfs_console_ratelimit"},
722         { "debug_path",
723           "/sys/module/libcfs/parameters/libcfs_debug_file_path"},
724         { "panic_on_lbug",
725           "/sys/module/libcfs/parameters/libcfs_panic_on_lbug"},
726         { "libcfs_console_backoff",
727           "/sys/module/libcfs/parameters/libcfs_console_backoff"},
728         { "debug_mb",
729           "/sys/module/libcfs/parameters/libcfs_debug_mb"},
730         { "console_min_delay_centisecs",
731           "/sys/module/libcfs/parameters/libcfs_console_min_delay"},
732         { "console_max_delay_centisecs",
733           "/sys/module/libcfs/parameters/libcfs_console_max_delay"},
734         {},
735 };
736
737 static ssize_t lnet_debugfs_read(struct file *filp, char __user *buf,
738                                  size_t count, loff_t *ppos)
739 {
740         struct ctl_table *table = filp->private_data;
741         int error;
742
743         error = table->proc_handler(table, 0, (void __user *)buf, &count, ppos);
744         if (!error)
745                 error = count;
746
747         return error;
748 }
749
750 static ssize_t lnet_debugfs_write(struct file *filp, const char __user *buf,
751                                   size_t count, loff_t *ppos)
752 {
753         struct ctl_table *table = filp->private_data;
754         int error;
755
756         error = table->proc_handler(table, 1, (void __user *)buf, &count, ppos);
757         if (!error)
758                 error = count;
759
760         return error;
761 }
762
763 static const struct file_operations lnet_debugfs_file_operations = {
764         .open           = simple_open,
765         .read           = lnet_debugfs_read,
766         .write          = lnet_debugfs_write,
767         .llseek         = default_llseek,
768 };
769
770 static void insert_debugfs(void)
771 {
772         struct ctl_table *table;
773         struct dentry *entry;
774         struct lnet_debugfs_symlink_def *symlinks;
775
776         if (lnet_debugfs_root == NULL)
777                 lnet_debugfs_root = debugfs_create_dir("lnet", NULL);
778
779         /* Even if we cannot create, just ignore it altogether) */
780         if (IS_ERR_OR_NULL(lnet_debugfs_root))
781                 return;
782
783         for (table = lnet_table; table->procname; table++)
784                 entry = debugfs_create_file(table->procname, table->mode,
785                                             lnet_debugfs_root, table,
786                                             &lnet_debugfs_file_operations);
787
788         for (symlinks = lnet_debugfs_symlinks; symlinks->name; symlinks++)
789                 entry = debugfs_create_symlink(symlinks->name,
790                                                lnet_debugfs_root,
791                                                symlinks->target);
792
793 }
794
795 static void remove_debugfs(void)
796 {
797         if (lnet_debugfs_root != NULL)
798                 debugfs_remove_recursive(lnet_debugfs_root);
799
800         lnet_debugfs_root = NULL;
801 }
802
803 MODULE_VERSION("1.0.0");
804
805 module_init(init_libcfs_module);
806 module_exit(exit_libcfs_module);