Whamcloud - gitweb
LU-9859 lnet: fold lprocfs_call_handler functionality into lnet_debugfs_*
[fs/lustre-release.git] / libcfs / 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.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, 2017, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  */
31 #include <linux/miscdevice.h>
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 #include <linux/uaccess.h>
42
43 #include <linux/fs.h>
44 #include <linux/file.h>
45 #include <linux/list.h>
46
47 #include <linux/sysctl.h>
48 #include <linux/debugfs.h>
49 #include <asm/div64.h>
50
51 #define DEBUG_SUBSYSTEM S_LNET
52
53 #include <libcfs/libcfs.h>
54 #include <libcfs/libcfs_crypto.h>
55 #include <lnet/lib-lnet.h>
56 #include <libcfs/crypto/llcrypt.h>
57 #include "tracefile.h"
58
59 struct lnet_debugfs_symlink_def {
60         const char *name;
61         const char *target;
62 };
63
64 static struct dentry *lnet_debugfs_root;
65
66 BLOCKING_NOTIFIER_HEAD(libcfs_ioctl_list);
67 EXPORT_SYMBOL(libcfs_ioctl_list);
68
69 static inline size_t libcfs_ioctl_packlen(struct libcfs_ioctl_data *data)
70 {
71         size_t len = sizeof(*data);
72
73         len += (data->ioc_inllen1 + 7) & ~7;
74         len += (data->ioc_inllen2 + 7) & ~7;
75         return len;
76 }
77
78 static bool libcfs_ioctl_is_invalid(struct libcfs_ioctl_data *data)
79 {
80         const int maxlen = 1 << 30;
81         if (data->ioc_hdr.ioc_len > maxlen)
82                 return true;
83
84         if (data->ioc_inllen1 > maxlen)
85                 return true;
86
87         if (data->ioc_inllen2 > maxlen)
88                 return true;
89
90         if (data->ioc_inlbuf1 && !data->ioc_inllen1)
91                 return true;
92
93         if (data->ioc_inlbuf2 && !data->ioc_inllen2)
94                 return true;
95
96         if (data->ioc_pbuf1 && !data->ioc_plen1)
97                 return true;
98
99         if (data->ioc_pbuf2 && !data->ioc_plen2)
100                 return true;
101
102         if (data->ioc_plen1 && !data->ioc_pbuf1)
103                 return true;
104
105         if (data->ioc_plen2 && !data->ioc_pbuf2)
106                 return true;
107
108         if (libcfs_ioctl_packlen(data) != data->ioc_hdr.ioc_len)
109                 return true;
110
111         if (data->ioc_inllen1 &&
112                 data->ioc_bulk[((data->ioc_inllen1 + 7) & ~7) +
113                                data->ioc_inllen2 - 1] != '\0')
114                 return true;
115
116         return false;
117 }
118
119 int libcfs_ioctl_data_adjust(struct libcfs_ioctl_data *data)
120 {
121         ENTRY;
122
123         if (libcfs_ioctl_is_invalid(data)) {
124                 CERROR("libcfs ioctl: parameter not correctly formatted\n");
125                 RETURN(-EINVAL);
126         }
127
128         if (data->ioc_inllen1 != 0)
129                 data->ioc_inlbuf1 = &data->ioc_bulk[0];
130
131         if (data->ioc_inllen2 != 0)
132                 data->ioc_inlbuf2 = &data->ioc_bulk[0] +
133                                     cfs_size_round(data->ioc_inllen1);
134
135         RETURN(0);
136 }
137
138 int libcfs_ioctl_getdata(struct libcfs_ioctl_hdr **hdr_pp,
139                          struct libcfs_ioctl_hdr __user *uhdr)
140 {
141         struct libcfs_ioctl_hdr hdr;
142         int err;
143
144         ENTRY;
145         if (copy_from_user(&hdr, uhdr, sizeof(hdr)))
146                 RETURN(-EFAULT);
147
148         if (hdr.ioc_version != LIBCFS_IOCTL_VERSION &&
149             hdr.ioc_version != LIBCFS_IOCTL_VERSION2) {
150                 CERROR("libcfs ioctl: version mismatch expected %#x, got %#x\n",
151                        LIBCFS_IOCTL_VERSION, hdr.ioc_version);
152                 RETURN(-EINVAL);
153         }
154
155         if (hdr.ioc_len < sizeof(struct libcfs_ioctl_hdr)) {
156                 CERROR("libcfs ioctl: user buffer too small for ioctl\n");
157                 RETURN(-EINVAL);
158         }
159
160         if (hdr.ioc_len > LIBCFS_IOC_DATA_MAX) {
161                 CERROR("libcfs ioctl: user buffer is too large %d/%d\n",
162                        hdr.ioc_len, LIBCFS_IOC_DATA_MAX);
163                 RETURN(-EINVAL);
164         }
165
166         LIBCFS_ALLOC(*hdr_pp, hdr.ioc_len);
167         if (*hdr_pp == NULL)
168                 RETURN(-ENOMEM);
169
170         if (copy_from_user(*hdr_pp, uhdr, hdr.ioc_len))
171                 GOTO(free, err = -EFAULT);
172
173         if ((*hdr_pp)->ioc_version != hdr.ioc_version ||
174                 (*hdr_pp)->ioc_len != hdr.ioc_len) {
175                 GOTO(free, err = -EINVAL);
176         }
177
178         RETURN(0);
179
180 free:
181         LIBCFS_FREE(*hdr_pp, hdr.ioc_len);
182         RETURN(err);
183 }
184
185 static int libcfs_ioctl(unsigned long cmd, void __user *uparam)
186 {
187         struct libcfs_ioctl_data *data = NULL;
188         struct libcfs_ioctl_hdr  *hdr;
189         int                       err;
190         ENTRY;
191
192         /* 'cmd' and permissions get checked in our arch-specific caller */
193         err = libcfs_ioctl_getdata(&hdr, uparam);
194         if (err != 0) {
195                 CDEBUG_LIMIT(D_ERROR,
196                              "libcfs ioctl: data header error %d\n", err);
197                 RETURN(err);
198         }
199
200         if (hdr->ioc_version == LIBCFS_IOCTL_VERSION) {
201                 /* The libcfs_ioctl_data_adjust() function performs adjustment
202                  * operations on the libcfs_ioctl_data structure to make
203                  * it usable by the code.  This doesn't need to be called
204                  * for new data structures added. */
205                 data = container_of(hdr, struct libcfs_ioctl_data, ioc_hdr);
206                 err = libcfs_ioctl_data_adjust(data);
207                 if (err != 0)
208                         GOTO(out, err);
209         }
210
211         CDEBUG(D_IOCTL, "libcfs ioctl cmd %lu\n", cmd);
212         switch (cmd) {
213         case IOC_LIBCFS_CLEAR_DEBUG:
214                 libcfs_debug_clear_buffer();
215                 break;
216         case IOC_LIBCFS_MARK_DEBUG:
217                 if (data == NULL ||
218                     data->ioc_inlbuf1 == NULL ||
219                     data->ioc_inlbuf1[data->ioc_inllen1 - 1] != '\0')
220                         GOTO(out, err = -EINVAL);
221
222                 libcfs_debug_mark_buffer(data->ioc_inlbuf1);
223                 break;
224
225         default:
226                 err = blocking_notifier_call_chain(&libcfs_ioctl_list,
227                                                    cmd, hdr);
228                 if (!(err & NOTIFY_STOP_MASK))
229                         /* No-one claimed the ioctl */
230                         err = -EINVAL;
231                 else
232                         err = notifier_to_errno(err);
233                 if (copy_to_user(uparam, hdr, hdr->ioc_len) && !err)
234                         err = -EFAULT;
235                 break;
236         }
237 out:
238         LIBCFS_FREE(hdr, hdr->ioc_len);
239         RETURN(err);
240 }
241
242 static long
243 libcfs_psdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
244 {
245         if (!capable(CAP_SYS_ADMIN))
246                 return -EACCES;
247
248         if (_IOC_TYPE(cmd) != IOC_LIBCFS_TYPE ||
249             _IOC_NR(cmd) < IOC_LIBCFS_MIN_NR  ||
250             _IOC_NR(cmd) > IOC_LIBCFS_MAX_NR) {
251                 CDEBUG(D_IOCTL, "invalid ioctl ( type %d, nr %d, size %d )\n",
252                        _IOC_TYPE(cmd), _IOC_NR(cmd), _IOC_SIZE(cmd));
253                 return -EINVAL;
254         }
255
256         return libcfs_ioctl(cmd, (void __user *)arg);
257 }
258
259 static const struct file_operations libcfs_fops = {
260         .owner                  = THIS_MODULE,
261         .unlocked_ioctl         = libcfs_psdev_ioctl,
262 };
263
264 static struct miscdevice libcfs_dev = {
265         .minor                  = MISC_DYNAMIC_MINOR,
266         .name                   = "lnet",
267         .fops                   = &libcfs_fops,
268 };
269
270 static int proc_dobitmasks(struct ctl_table *table, int write,
271                            void __user *buffer, size_t *lenp, loff_t *ppos)
272 {
273         const int     tmpstrlen = 512;
274         char         *tmpstr = NULL;
275         int           rc;
276         size_t nob = *lenp;
277         loff_t pos = *ppos;
278         unsigned int *mask = table->data;
279         int           is_subsys = (mask == &libcfs_subsystem_debug) ? 1 : 0;
280         int           is_printk = (mask == &libcfs_printk) ? 1 : 0;
281
282         if (!write) {
283                 tmpstr = kmalloc(tmpstrlen, GFP_KERNEL | __GFP_ZERO);
284                 if (!tmpstr)
285                         return -ENOMEM;
286                 libcfs_debug_mask2str(tmpstr, tmpstrlen, *mask, is_subsys);
287                 rc = strlen(tmpstr);
288
289                 if (pos >= rc) {
290                         rc = 0;
291                 } else {
292                         rc = cfs_trace_copyout_string(buffer, nob,
293                                                       tmpstr + pos, "\n");
294                 }
295         } else {
296                 tmpstr = memdup_user_nul(buffer, nob);
297                 if (IS_ERR(tmpstr))
298                         return PTR_ERR(tmpstr);
299
300                 rc = libcfs_debug_str2mask(mask, strim(tmpstr), is_subsys);
301                 /* Always print LBUG/LASSERT to console, so keep this mask */
302                 if (is_printk)
303                         *mask |= D_EMERG;
304         }
305
306         kfree(tmpstr);
307         return rc;
308 }
309
310 static int min_watchdog_ratelimit;              /* disable ratelimiting */
311 static int max_watchdog_ratelimit = (24*60*60); /* limit to once per day */
312
313 static int proc_dump_kernel(struct ctl_table *table, int write,
314                             void __user *buffer, size_t *lenp, loff_t *ppos)
315 {
316         size_t nob = *lenp;
317
318         if (!write)
319                 return 0;
320
321         return cfs_trace_dump_debug_buffer_usrstr(buffer, nob);
322 }
323
324 static int proc_daemon_file(struct ctl_table *table, int write,
325                             void __user *buffer, size_t *lenp, loff_t *ppos)
326 {
327         size_t nob = *lenp;
328         loff_t pos = *ppos;
329
330         if (!write) {
331                 int len = strlen(cfs_tracefile);
332
333                 if (pos >= len)
334                         return 0;
335
336                 return cfs_trace_copyout_string(buffer, nob,
337                                                 cfs_tracefile + pos, "\n");
338         }
339
340         return cfs_trace_daemon_command_usrstr(buffer, nob);
341 }
342
343 static int libcfs_force_lbug(struct ctl_table *table, int write,
344                              void __user *buffer,
345                              size_t *lenp, loff_t *ppos)
346 {
347         if (write)
348                 LBUG();
349         return 0;
350 }
351
352 static int proc_fail_loc(struct ctl_table *table, int write,
353                          void __user *buffer, size_t *lenp, loff_t *ppos)
354 {
355         int rc;
356         long old_fail_loc = cfs_fail_loc;
357
358         if (!*lenp || *ppos) {
359                 *lenp = 0;
360                 return 0;
361         }
362
363         if (write) {
364                 char *kbuf = memdup_user_nul(buffer, *lenp);
365
366                 if (IS_ERR(kbuf))
367                         return PTR_ERR(kbuf);
368                 rc = kstrtoul(kbuf, 0, &cfs_fail_loc);
369                 kfree(kbuf);
370                 *ppos += *lenp;
371         } else {
372                 char kbuf[64/3+3];
373
374                 rc = scnprintf(kbuf, sizeof(kbuf), "%lu\n", cfs_fail_loc);
375                 if (copy_to_user(buffer, kbuf, rc))
376                         rc = -EFAULT;
377                 else {
378                         *lenp = rc;
379                         *ppos += rc;
380                 }
381         }
382
383         if (old_fail_loc != cfs_fail_loc) {
384                 cfs_race_state = 1;
385                 wake_up(&cfs_race_waitq);
386         }
387         return rc;
388 }
389
390 int debugfs_doint(struct ctl_table *table, int write,
391                   void __user *buffer, size_t *lenp, loff_t *ppos)
392 {
393         int rc;
394
395         if (!*lenp || *ppos) {
396                 *lenp = 0;
397                 return 0;
398         }
399
400         if (write) {
401                 char *kbuf = memdup_user_nul(buffer, *lenp);
402                 int val;
403
404                 if (IS_ERR(kbuf))
405                         return PTR_ERR(kbuf);
406
407                 rc = kstrtoint(kbuf, 0, &val);
408                 kfree(kbuf);
409                 if (!rc) {
410                         if (table->extra1 && val < *(int *)table->extra1)
411                                 val = *(int *)table->extra1;
412                         if (table->extra2 && val > *(int *)table->extra2)
413                                 val = *(int *)table->extra2;
414                         *(int *)table->data = val;
415                 }
416                 *ppos += *lenp;
417         } else {
418                 char kbuf[64/3+3];
419
420                 rc = scnprintf(kbuf, sizeof(kbuf), "%u\n", *(int *)table->data);
421                 if (copy_to_user(buffer, kbuf, rc))
422                         rc = -EFAULT;
423                 else {
424                         *lenp = rc;
425                         *ppos += rc;
426                 }
427         }
428
429         return rc;
430 }
431 EXPORT_SYMBOL(debugfs_doint);
432
433 static int debugfs_dou64(struct ctl_table *table, int write,
434                          void __user *buffer, size_t *lenp, loff_t *ppos)
435 {
436         int rc;
437
438         if (!*lenp || *ppos) {
439                 *lenp = 0;
440                 return 0;
441         }
442
443         if (write) {
444                 char *kbuf = memdup_user_nul(buffer, *lenp);
445                 unsigned long long val;
446
447                 if (IS_ERR(kbuf))
448                         return PTR_ERR(kbuf);
449
450                 rc = kstrtoull(kbuf, 0, &val);
451                 kfree(kbuf);
452                 if (!rc)
453                         *(u64 *)table->data = val;
454                 *ppos += *lenp;
455         } else {
456                 char kbuf[64/3+3];
457
458                 rc = scnprintf(kbuf, sizeof(kbuf), "%llu\n",
459                                (unsigned long long)*(u64 *)table->data);
460                 if (copy_to_user(buffer, kbuf, rc))
461                         rc = -EFAULT;
462                 else {
463                         *lenp = rc;
464                         *ppos += rc;
465                 }
466         }
467
468         return rc;
469 }
470
471 static int debugfs_dostring(struct ctl_table *table, int write,
472                             void __user *buffer, size_t *lenp, loff_t *ppos)
473 {
474         int len = *lenp;
475         char *kbuf = table->data;
476
477         if (!len || *ppos) {
478                 *lenp = 0;
479                 return 0;
480         }
481         if (len > table->maxlen)
482                 len = table->maxlen;
483         if (write) {
484                 if (copy_from_user(kbuf, buffer, len))
485                         return -EFAULT;
486                 memset(kbuf+len, 0, table->maxlen - len);
487                 *ppos = *lenp;
488         } else {
489                 len = strnlen(kbuf, len);
490                 if (copy_to_user(buffer, kbuf, len))
491                         return -EFAULT;
492                 if (len < *lenp) {
493                         if (copy_to_user(buffer+len, "\n", 1))
494                                 return -EFAULT;
495                         len += 1;
496                 }
497                 *ppos += len;
498                 *lenp -= len;
499         }
500         return len;
501 }
502
503 static int proc_cpt_table(struct ctl_table *table, int write,
504                           void __user *buffer, size_t *lenp, loff_t *ppos)
505 {
506         size_t nob = *lenp;
507         loff_t pos = *ppos;
508         char *buf = NULL;
509         int   len = 4096;
510         int   rc  = 0;
511
512         if (write)
513                 return -EPERM;
514
515         while (1) {
516                 LIBCFS_ALLOC(buf, len);
517                 if (buf == NULL)
518                         return -ENOMEM;
519
520                 rc = cfs_cpt_table_print(cfs_cpt_tab, buf, len);
521                 if (rc >= 0)
522                         break;
523
524                 if (rc == -EFBIG) {
525                         LIBCFS_FREE(buf, len);
526                         len <<= 1;
527                         continue;
528                 }
529                 goto out;
530         }
531
532         if (pos >= rc) {
533                 rc = 0;
534                 goto out;
535         }
536
537         rc = cfs_trace_copyout_string(buffer, nob, buf + pos, NULL);
538 out:
539         if (buf != NULL)
540                 LIBCFS_FREE(buf, len);
541         return rc;
542 }
543
544 static int proc_cpt_distance(struct ctl_table *table, int write,
545                              void __user *buffer, size_t *lenp, loff_t *ppos)
546 {
547         size_t nob = *lenp;
548         loff_t pos = *ppos;
549         char *buf = NULL;
550         int   len = 4096;
551         int   rc  = 0;
552
553         if (write)
554                 return -EPERM;
555
556         while (1) {
557                 LIBCFS_ALLOC(buf, len);
558                 if (buf == NULL)
559                         return -ENOMEM;
560
561                 rc = cfs_cpt_distance_print(cfs_cpt_tab, buf, len);
562                 if (rc >= 0)
563                         break;
564
565                 if (rc == -EFBIG) {
566                         LIBCFS_FREE(buf, len);
567                         len <<= 1;
568                         continue;
569                 }
570                 goto out;
571         }
572
573         if (pos >= rc) {
574                 rc = 0;
575                 goto out;
576         }
577
578         rc = cfs_trace_copyout_string(buffer, nob, buf + pos, NULL);
579  out:
580         if (buf != NULL)
581                 LIBCFS_FREE(buf, len);
582         return rc;
583 }
584
585 static struct ctl_table lnet_table[] = {
586         {
587                 .procname       = "debug",
588                 .data           = &libcfs_debug,
589                 .maxlen         = sizeof(int),
590                 .mode           = 0644,
591                 .proc_handler   = &proc_dobitmasks,
592         },
593         {
594                 .procname       = "subsystem_debug",
595                 .data           = &libcfs_subsystem_debug,
596                 .maxlen         = sizeof(int),
597                 .mode           = 0644,
598                 .proc_handler   = &proc_dobitmasks,
599         },
600         {
601                 .procname       = "printk",
602                 .data           = &libcfs_printk,
603                 .maxlen         = sizeof(int),
604                 .mode           = 0644,
605                 .proc_handler   = &proc_dobitmasks,
606         },
607         {
608                 .procname       = "cpu_partition_table",
609                 .maxlen         = 128,
610                 .mode           = 0444,
611                 .proc_handler   = &proc_cpt_table,
612         },
613         {
614                 .procname       = "cpu_partition_distance",
615                 .maxlen         = 128,
616                 .mode           = 0444,
617                 .proc_handler   = &proc_cpt_distance,
618         },
619         {
620                 .procname       = "debug_log_upcall",
621                 .data           = lnet_debug_log_upcall,
622                 .maxlen         = sizeof(lnet_debug_log_upcall),
623                 .mode           = 0644,
624                 .proc_handler   = &debugfs_dostring,
625         },
626         {
627                 .procname       = "lnet_memused",
628                 .data           = (u64 *)&libcfs_kmem.counter,
629                 .maxlen         = sizeof(u64),
630                 .mode           = 0444,
631                 .proc_handler   = &debugfs_dou64,
632         },
633         {
634                 .procname       = "catastrophe",
635                 .data           = &libcfs_catastrophe,
636                 .maxlen         = sizeof(int),
637                 .mode           = 0444,
638                 .proc_handler   = &debugfs_doint,
639         },
640         {
641                 .procname       = "dump_kernel",
642                 .maxlen         = 256,
643                 .mode           = 0200,
644                 .proc_handler   = &proc_dump_kernel,
645         },
646         {
647                 .procname       = "daemon_file",
648                 .mode           = 0644,
649                 .maxlen         = 256,
650                 .proc_handler   = &proc_daemon_file,
651         },
652         {
653                 .procname       = "watchdog_ratelimit",
654                 .data           = &libcfs_watchdog_ratelimit,
655                 .maxlen         = sizeof(int),
656                 .mode           = 0644,
657                 .proc_handler   = &debugfs_doint,
658                 .extra1         = &min_watchdog_ratelimit,
659                 .extra2         = &max_watchdog_ratelimit,
660         },
661         {
662                 .procname       = "force_lbug",
663                 .data           = NULL,
664                 .maxlen         = 0,
665                 .mode           = 0200,
666                 .proc_handler   = &libcfs_force_lbug
667         },
668         {
669                 .procname       = "fail_loc",
670                 .data           = &cfs_fail_loc,
671                 .maxlen         = sizeof(cfs_fail_loc),
672                 .mode           = 0644,
673                 .proc_handler   = &proc_fail_loc
674         },
675         {
676                 .procname       = "fail_val",
677                 .data           = &cfs_fail_val,
678                 .maxlen         = sizeof(int),
679                 .mode           = 0644,
680                 .proc_handler   = &debugfs_doint
681         },
682         {
683                 .procname       = "fail_err",
684                 .data           = &cfs_fail_err,
685                 .maxlen         = sizeof(cfs_fail_err),
686                 .mode           = 0644,
687                 .proc_handler   = &debugfs_doint,
688         },
689         {
690         }
691 };
692
693 static const struct lnet_debugfs_symlink_def lnet_debugfs_symlinks[] = {
694         { .name         = "console_ratelimit",
695           .target       = "../../../module/libcfs/parameters/libcfs_console_ratelimit" },
696         { .name         = "debug_path",
697           .target       = "../../../module/libcfs/parameters/libcfs_debug_file_path" },
698         { .name         = "panic_on_lbug",
699           .target       = "../../../module/libcfs/parameters/libcfs_panic_on_lbug" },
700         { .name         = "console_backoff",
701           .target       = "../../../module/libcfs/parameters/libcfs_console_backoff" },
702         { .name         = "debug_mb",
703           .target       = "../../../module/libcfs/parameters/libcfs_debug_mb" },
704         { .name         = "console_min_delay_centisecs",
705           .target       = "../../../module/libcfs/parameters/libcfs_console_min_delay" },
706         { .name         = "console_max_delay_centisecs",
707           .target       = "../../../module/libcfs/parameters/libcfs_console_max_delay" },
708         { .name         = NULL },
709 };
710
711 static ssize_t lnet_debugfs_read(struct file *filp, char __user *buf,
712                                  size_t count, loff_t *ppos)
713 {
714         struct ctl_table *table = filp->private_data;
715         loff_t old_pos = *ppos;
716         ssize_t rc = -EINVAL;
717
718         if (table)
719                 rc = table->proc_handler(table, 0, (void __user *)buf,
720                                          &count, ppos);
721         /*
722          * On success, the length read is either in error or in count.
723          * If ppos changed, then use count, else use error
724          */
725         if (!rc && *ppos != old_pos)
726                 rc = count;
727         else if (rc > 0)
728                 *ppos += rc;
729
730         return rc;
731 }
732
733 static ssize_t lnet_debugfs_write(struct file *filp, const char __user *buf,
734                                   size_t count, loff_t *ppos)
735 {
736         struct ctl_table *table = filp->private_data;
737         loff_t old_pos = *ppos;
738         ssize_t rc = -EINVAL;
739
740         if (table)
741                 rc = table->proc_handler(table, 1, (void __user *)buf, &count,
742                                          ppos);
743         if (rc)
744                 return rc;
745
746         if (*ppos == old_pos)
747                 *ppos += count;
748
749         return count;
750 }
751
752 static const struct file_operations lnet_debugfs_file_operations_rw = {
753         .open           = simple_open,
754         .read           = lnet_debugfs_read,
755         .write          = lnet_debugfs_write,
756         .llseek         = default_llseek,
757 };
758
759 static const struct file_operations lnet_debugfs_file_operations_ro = {
760         .open           = simple_open,
761         .read           = lnet_debugfs_read,
762         .llseek         = default_llseek,
763 };
764
765 static const struct file_operations lnet_debugfs_file_operations_wo = {
766         .open           = simple_open,
767         .write          = lnet_debugfs_write,
768         .llseek         = default_llseek,
769 };
770
771 static const struct file_operations *lnet_debugfs_fops_select(umode_t mode)
772 {
773         if (!(mode & S_IWUGO))
774                 return &lnet_debugfs_file_operations_ro;
775
776         if (!(mode & S_IRUGO))
777                 return &lnet_debugfs_file_operations_wo;
778
779         return &lnet_debugfs_file_operations_rw;
780 }
781
782 void lnet_insert_debugfs(struct ctl_table *table)
783 {
784         if (!lnet_debugfs_root)
785                 lnet_debugfs_root = debugfs_create_dir("lnet", NULL);
786
787         /* Even if we cannot create, just ignore it altogether) */
788         if (IS_ERR_OR_NULL(lnet_debugfs_root))
789                 return;
790
791         /* We don't save the dentry returned in next two calls, because
792          * we don't call debugfs_remove() but rather remove_recursive()
793          */
794         for (; table && table->procname; table++)
795                 debugfs_create_file(table->procname, table->mode,
796                                     lnet_debugfs_root, table,
797                                     lnet_debugfs_fops_select(table->mode));
798 }
799 EXPORT_SYMBOL_GPL(lnet_insert_debugfs);
800
801 static void lnet_insert_debugfs_links(
802                 const struct lnet_debugfs_symlink_def *symlinks)
803 {
804         for (; symlinks && symlinks->name; symlinks++)
805                 debugfs_create_symlink(symlinks->name, lnet_debugfs_root,
806                                        symlinks->target);
807 }
808
809 void lnet_remove_debugfs(struct ctl_table *table)
810 {
811         for (; table && table->procname; table++) {
812                 struct qstr dname = QSTR_INIT(table->procname,
813                                               strlen(table->procname));
814                 struct dentry *dentry;
815
816                 dentry = d_hash_and_lookup(lnet_debugfs_root, &dname);
817                 debugfs_remove(dentry);
818         }
819 }
820 EXPORT_SYMBOL_GPL(lnet_remove_debugfs);
821
822 static int __init libcfs_init(void)
823 {
824         int rc;
825
826         cfs_arch_init();
827
828         init_libcfs_vfree_atomic();
829
830         rc = libcfs_debug_init(5 * 1024 * 1024);
831         if (rc < 0) {
832                 pr_err("LustreError: libcfs_debug_init: rc = %d\n", rc);
833                 return (rc);
834         }
835
836         cfs_debug_init();
837
838         rc = cfs_cpu_init();
839         if (rc != 0)
840                 goto cleanup_debug;
841
842         rc = misc_register(&libcfs_dev);
843         if (rc) {
844                 CERROR("misc_register: error %d\n", rc);
845                 goto cleanup_cpu;
846         }
847
848         rc = cfs_wi_startup();
849         if (rc) {
850                 CERROR("initialize workitem: error %d\n", rc);
851                 goto cleanup_deregister;
852         }
853
854         cfs_rehash_wq = alloc_workqueue("cfs_rh", WQ_SYSFS, 4);
855         if (!cfs_rehash_wq) {
856                 rc = -ENOMEM;
857                 CERROR("libcfs: failed to start rehash workqueue: rc = %d\n",
858                        rc);
859                 goto cleanup_deregister;
860         }
861
862         rc = cfs_crypto_register();
863         if (rc) {
864                 CERROR("cfs_crypto_regster: error %d\n", rc);
865                 goto cleanup_wi;
866         }
867
868         lnet_insert_debugfs(lnet_table);
869         if (!IS_ERR_OR_NULL(lnet_debugfs_root))
870                 lnet_insert_debugfs_links(lnet_debugfs_symlinks);
871
872         rc = llcrypt_init();
873         if (rc) {
874                 CERROR("llcrypt_init: error %d\n", rc);
875                 goto cleanup_wi;
876         }
877
878         CDEBUG (D_OTHER, "portals setup OK\n");
879         return 0;
880 cleanup_wi:
881         cfs_wi_shutdown();
882 cleanup_deregister:
883         misc_deregister(&libcfs_dev);
884 cleanup_cpu:
885         cfs_cpu_fini();
886 cleanup_debug:
887         libcfs_debug_cleanup();
888         return rc;
889 }
890
891 static void __exit libcfs_exit(void)
892 {
893         int rc;
894
895         /* Remove everthing */
896         debugfs_remove_recursive(lnet_debugfs_root);
897         lnet_debugfs_root = NULL;
898
899         CDEBUG(D_MALLOC, "before Portals cleanup: kmem %lld\n",
900                libcfs_kmem_read());
901
902         llcrypt_exit();
903
904         if (cfs_rehash_wq) {
905                 destroy_workqueue(cfs_rehash_wq);
906                 cfs_rehash_wq = NULL;
907         }
908
909         cfs_crypto_unregister();
910         cfs_wi_shutdown();
911
912         misc_deregister(&libcfs_dev);
913
914         cfs_cpu_fini();
915
916         /* the below message is checked in test-framework.sh check_mem_leak() */
917         if (libcfs_kmem_read() != 0)
918                 CERROR("Portals memory leaked: %lld bytes\n",
919                        libcfs_kmem_read());
920
921         rc = libcfs_debug_cleanup();
922         if (rc)
923                 pr_err("LustreError: libcfs_debug_cleanup: rc = %d\n", rc);
924
925         exit_libcfs_vfree_atomic();
926 }
927
928 MODULE_AUTHOR("OpenSFS, Inc. <http://www.lustre.org/>");
929 MODULE_DESCRIPTION("Lustre helper library");
930 MODULE_VERSION(LIBCFS_VERSION);
931 MODULE_LICENSE("GPL");
932
933 module_init(libcfs_init);
934 module_exit(libcfs_exit);