Whamcloud - gitweb
770a45241c40d942b88642a2641a8aadb21b785a
[fs/lustre-release.git] / libcfs / libcfs / winnt / winnt-proc.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
37 # define DEBUG_SUBSYSTEM S_LNET
38
39 #include <libcfs/libcfs.h>
40 #include "tracefile.h"
41 #include <lustre_lib.h>
42
43 #ifdef __KERNEL__
44
45
46 /*
47  *  /proc emulator routines ...
48  */
49
50 /* The root node of the proc fs emulation: / */
51 cfs_proc_entry_t *              cfs_proc_root = NULL;
52
53 /* The root node of the proc fs emulation: /proc */
54 cfs_proc_entry_t *              cfs_proc_proc = NULL;
55
56 /* The fs sys directory: /proc/fs */
57 cfs_proc_entry_t *              cfs_proc_fs = NULL;
58
59 /* The sys root: /proc/sys */
60 cfs_proc_entry_t *              cfs_proc_sys = NULL;
61
62 /* The sys root: /proc/dev | to implement misc device */
63 cfs_proc_entry_t *              cfs_proc_dev = NULL;
64
65
66 /* SLAB object for cfs_proc_entry_t allocation */
67 struct kmem_cache *proc_entry_cache;
68
69 /* root node for sysctl table */
70 cfs_sysctl_table_header_t       root_table_header;
71
72 /* The global lock to protect all the access */
73
74 #if LIBCFS_PROCFS_SPINLOCK
75 spinlock_t                      proc_fs_lock;
76
77 #define INIT_PROCFS_LOCK()      spin_lock_init(&proc_fs_lock)
78 #define LOCK_PROCFS()           spin_lock(&proc_fs_lock)
79 #define UNLOCK_PROCFS()         spin_unlock(&proc_fs_lock)
80
81 #else
82
83 struct mutex                            proc_fs_lock;
84
85 #define INIT_PROCFS_LOCK()      cfs_init_mutex(&proc_fs_lock)
86 #define LOCK_PROCFS()           cfs_mutex_down(&proc_fs_lock)
87 #define UNLOCK_PROCFS()         cfs_mutex_up(&proc_fs_lock)
88
89 #endif
90
91 static ssize_t
92 proc_file_read(struct file * file, const char * buf, size_t nbytes, loff_t *ppos)
93 {
94     char    *page;
95     ssize_t retval=0;
96     int eof=0;
97     ssize_t n, count;
98     char    *start;
99     cfs_proc_entry_t * dp;
100
101         dp = (cfs_proc_entry_t  *) file->f_inode->i_priv;
102         page = (char *) kmalloc(PAGE_CACHE_SIZE, 0);
103         if (page == NULL)
104                 return -ENOMEM;
105
106     while ((nbytes > 0) && !eof) {
107
108         count = min_t(size_t, PROC_BLOCK_SIZE, nbytes);
109
110         start = NULL;
111         if (dp->read_proc) {
112             n = dp->read_proc( page, &start, (long)*ppos,
113                                count, &eof, dp->data);
114         } else
115             break;
116
117         if (!start) {
118             /*
119              * For proc files that are less than 4k
120              */
121             start = page + *ppos;
122             n -= (ssize_t)(*ppos);
123             if (n <= 0)
124                 break;
125             if (n > count)
126                 n = count;
127         }
128         if (n == 0)
129             break;  /* End of file */
130         if (n < 0) {
131             if (retval == 0)
132                 retval = n;
133             break;
134         }
135         
136         n -= copy_to_user((void *)buf, start, n);
137         if (n == 0) {
138             if (retval == 0)
139                 retval = -EFAULT;
140             break;
141         }
142
143         *ppos += n;
144         nbytes -= n;
145         buf += n;
146         retval += n;
147     }
148         kfree(page);
149
150         return retval;
151 }
152
153 static ssize_t
154 proc_file_write(struct file * file, const char * buffer,
155                 size_t count, loff_t *ppos)
156 {
157     cfs_proc_entry_t  * dp;
158     
159     dp = (cfs_proc_entry_t *) file->f_inode->i_priv;
160
161     if (!dp->write_proc)
162         return -EIO;
163
164     /* FIXME: does this routine need ppos?  probably... */
165     return dp->write_proc(file, buffer, count, dp->data);
166 }
167
168 struct file_operations proc_file_operations = {
169     /*owner*/       THIS_MODULE,
170     /*lseek:*/      NULL, //proc_file_lseek,
171     /*read:*/       proc_file_read,
172     /*write:*/      proc_file_write,
173     /*ioctl:*/      NULL,
174     /*open:*/       NULL,
175     /*release:*/    NULL
176 };
177
178 /* allocate proc entry block */
179
180 cfs_proc_entry_t *
181 proc_alloc_entry()
182 {
183     cfs_proc_entry_t * entry = NULL;
184
185         entry = kmem_cache_alloc(proc_entry_cache, 0);
186         if (!entry)
187                 return NULL;
188
189     memset(entry, 0, sizeof(cfs_proc_entry_t));
190
191     entry->magic = CFS_PROC_ENTRY_MAGIC;
192     RtlInitializeSplayLinks(&(entry->s_link));
193     entry->proc_fops = &proc_file_operations;
194
195     return entry;
196 }
197
198 /* free the proc entry block */
199
200 void
201 proc_free_entry(cfs_proc_entry_t * entry)
202 {
203         ASSERT(entry->magic == CFS_PROC_ENTRY_MAGIC);
204         kmem_cache_free(proc_entry_cache, entry);
205 }
206
207 /* dissect the path string for a given full proc path */
208
209 void
210 proc_dissect_name(
211     const char *path,
212     char **first,
213     int  *first_len,
214     char **remain
215     )
216 {
217     int i = 0, j = 0, len = 0;
218
219     *first = *remain = NULL;
220     *first_len = 0;
221
222     len = strlen(path);
223
224     while (i < len && (path[i] == '/')) i++;
225
226     if (i < len) {
227
228         *first = (char *)path + i;
229         while (i < len && (path[i] != '/')) i++;
230         *first_len = (int)(path + i - *first);
231
232         if (i + 1 < len) {
233             *remain = (char *)path + i + 1;
234         }
235     }
236 }
237
238 /* search the children entries of the parent entry */
239
240 cfs_proc_entry_t *
241 proc_search_splay (
242     cfs_proc_entry_t *  parent,
243     char *              name
244     )
245 {
246     cfs_proc_entry_t *  node;
247     PRTL_SPLAY_LINKS    link;
248
249     ASSERT(parent->magic == CFS_PROC_ENTRY_MAGIC);
250     ASSERT(cfs_is_flag_set(parent->flags, CFS_PROC_FLAG_DIRECTORY));
251
252     link = parent->root;
253
254     while (link) {
255
256         ANSI_STRING ename,nname;
257         long        result;
258
259         node = CONTAINING_RECORD(link, cfs_proc_entry_t, s_link);
260
261         ASSERT(node->magic == CFS_PROC_ENTRY_MAGIC);
262
263         /*  Compare the prefix in the tree with the full name */
264
265         RtlInitAnsiString(&ename, name);
266         RtlInitAnsiString(&nname, node->name);
267
268         result = RtlCompareString(&nname, &ename,TRUE);
269
270         if (result > 0) {
271
272             /*  The prefix is greater than the full name
273                 so we go down the left child          */
274
275             link = RtlLeftChild(link);
276
277         } else if (result < 0) {
278
279             /*  The prefix is less than the full name
280                 so we go down the right child      */
281
282             link = RtlRightChild(link);
283
284         } else {
285
286             /*  We got the entry in the splay tree and
287                 make it root node instead           */
288
289             parent->root = RtlSplay(link);
290
291             return node;
292         }
293
294         /* we need continue searching down the tree ... */
295     }
296
297     /*  There's no the exptected entry in the splay tree */
298
299     return NULL;
300 }
301
302 int
303 proc_insert_splay (
304     cfs_proc_entry_t * parent,
305     cfs_proc_entry_t * child
306     )
307 {
308     cfs_proc_entry_t * entry;
309
310     ASSERT(parent != NULL && child != NULL);
311     ASSERT(parent->magic == CFS_PROC_ENTRY_MAGIC);
312     ASSERT(child->magic == CFS_PROC_ENTRY_MAGIC);
313     ASSERT(cfs_is_flag_set(parent->flags, CFS_PROC_FLAG_DIRECTORY));
314
315     if (!parent->root) {
316         parent->root = &(child->s_link);
317     } else {
318         entry = CONTAINING_RECORD(parent->root, cfs_proc_entry_t, s_link);
319         while (TRUE) {
320             long        result;
321             ANSI_STRING ename, cname;
322
323             ASSERT(entry->magic == CFS_PROC_ENTRY_MAGIC);
324
325             RtlInitAnsiString(&ename, entry->name);
326             RtlInitAnsiString(&cname, child->name);
327
328             result = RtlCompareString(&ename, &cname,TRUE);
329
330             if (result == 0) {
331                 cfs_enter_debugger();
332                 if (entry == child) {
333                     break;
334                 }
335                 return FALSE;
336             }
337
338             if (result > 0) {
339                 if (RtlLeftChild(&entry->s_link) == NULL) {
340                     RtlInsertAsLeftChild(&entry->s_link, &child->s_link);
341                     break;
342                 } else {
343                     entry = CONTAINING_RECORD( RtlLeftChild(&entry->s_link),
344                                                cfs_proc_entry_t, s_link);
345                 }
346             } else {
347                 if (RtlRightChild(&entry->s_link) == NULL) {
348                     RtlInsertAsRightChild(&entry->s_link, &child->s_link);
349                     break;
350                 } else {
351                     entry = CONTAINING_RECORD( RtlRightChild(&entry->s_link),
352                                                cfs_proc_entry_t, s_link );
353                 }
354             }
355         }
356     }
357
358     cfs_set_flag(child->flags, CFS_PROC_FLAG_ATTACHED);
359     parent->nlink++;
360     child->parent = parent;
361
362     return TRUE;
363 }
364
365
366 /* remove a child entry from the splay tree */
367 int
368 proc_remove_splay (
369     cfs_proc_entry_t *  parent,
370     cfs_proc_entry_t *  child
371     )
372 {
373     cfs_proc_entry_t * entry = NULL;
374
375     ASSERT(parent != NULL && child != NULL);
376     ASSERT(parent->magic == CFS_PROC_ENTRY_MAGIC);
377     ASSERT(child->magic == CFS_PROC_ENTRY_MAGIC);
378     ASSERT(cfs_is_flag_set(parent->flags, CFS_PROC_FLAG_DIRECTORY));
379     ASSERT(cfs_is_flag_set(child->flags, CFS_PROC_FLAG_ATTACHED));
380     ASSERT(child->parent == parent);
381
382     entry = proc_search_splay(parent, child->name);
383
384     if (entry) {
385         ASSERT(entry == child);
386         parent->root = RtlDelete(&(entry->s_link));
387         parent->nlink--;
388     } else {
389         cfs_enter_debugger();
390         return FALSE;
391     }
392
393     return TRUE;
394 }
395
396
397 /* search a node inside the proc fs tree */
398
399 cfs_proc_entry_t *
400 proc_search_entry(
401     const char *        name,
402     cfs_proc_entry_t *  root
403     )
404 {
405     cfs_proc_entry_t *  entry;
406     cfs_proc_entry_t *  parent;
407     char *first, *remain;
408     int   flen;
409     char *ename = NULL;
410
411     parent = root;
412     entry = NULL;
413
414         ename = kmalloc(0x21, __GFP_ZERO);
415
416         if (ename == NULL)
417                 goto errorout;
418
419 again:
420
421     /* dissect the file name string */
422     proc_dissect_name(name, &first, &flen, &remain);
423
424     if (first) {
425
426         if (flen >= 0x20) {
427             cfs_enter_debugger();
428             entry = NULL;
429             goto errorout;
430         }
431
432         memset(ename, 0, 0x20);
433         memcpy(ename, first, flen);
434
435         entry = proc_search_splay(parent, ename);
436
437         if (!entry) {
438             goto errorout;
439         }
440
441         if (remain) {
442             name = remain;
443             parent = entry;
444
445             goto again;
446         }
447     }
448
449 errorout:
450
451     if (ename) {
452         kfree(ename);
453     }
454
455     return entry;   
456 }
457
458 /* insert the path nodes to the proc fs tree */
459
460 cfs_proc_entry_t *
461 proc_insert_entry(
462     const char *        name,
463     cfs_proc_entry_t *  root
464     )
465 {
466     cfs_proc_entry_t *entry;
467     cfs_proc_entry_t *parent;
468     char *first, *remain;
469     int flen;
470     char ename[0x20];
471
472     parent = root;
473     entry = NULL;
474
475 again:
476
477     proc_dissect_name(name, &first, &flen, &remain);
478
479     if (first) {
480
481         if (flen >= 0x20) {
482             return NULL;
483         }
484
485         memset(ename, 0, 0x20);
486         memcpy(ename, first, flen);
487
488         entry = proc_search_splay(parent, ename);
489
490         if (!entry) {
491             entry = proc_alloc_entry();
492             memcpy(entry->name, ename, flen);
493
494                 if (entry && !proc_insert_splay(parent, entry)) {
495                         proc_free_entry(entry);
496                         entry = NULL;
497                 }
498         }
499
500         if (!entry) {
501             return NULL;
502         }
503
504         if (remain) {
505             entry->mode |= S_IFDIR | S_IRUGO | S_IXUGO;
506             cfs_set_flag(entry->flags, CFS_PROC_FLAG_DIRECTORY);
507             name = remain;
508             parent = entry;
509             goto again;
510         }
511     }
512
513     return entry;   
514 }
515
516 /* remove the path nodes from the proc fs tree */
517
518 void
519 proc_remove_entry(
520     const char *        name,
521     cfs_proc_entry_t *  root
522     )
523 {
524     cfs_proc_entry_t *entry;
525     char *first, *remain;
526     int  flen;
527     char ename[0x20];
528
529     entry  = NULL;
530
531     proc_dissect_name(name, &first, &flen, &remain);
532
533     if (first) {
534
535         memset(ename, 0, 0x20);
536         memcpy(ename, first, flen);
537
538         entry = proc_search_splay(root, ename);
539
540         if (entry) {
541
542             if (remain) {
543                 ASSERT(S_ISDIR(entry->mode));
544                 proc_remove_entry(remain, entry);
545             }
546
547             if (!entry->nlink) {
548                 proc_remove_splay(root, entry);
549                 proc_free_entry(entry);
550             }
551         }
552     } else {
553         cfs_enter_debugger();
554     }
555 }
556
557 /* create proc entry and insert it into the proc fs */
558
559 cfs_proc_entry_t *
560 create_proc_entry (
561     const char *        name,
562     mode_t              mode,
563     cfs_proc_entry_t *  parent
564     )
565 {
566     cfs_proc_entry_t *entry  = NULL;
567
568     if (S_ISDIR(mode)) {
569         if ((mode & S_IALLUGO) == 0)
570         mode |= S_IRUGO | S_IXUGO;
571     } else {
572         if ((mode & S_IFMT) == 0)
573             mode |= S_IFREG;
574         if ((mode & S_IALLUGO) == 0)
575             mode |= S_IRUGO;
576     }
577
578     LOCK_PROCFS();
579     ASSERT(NULL != cfs_proc_root);
580
581     if (!parent) {
582         if (name[0] == '/') {
583             parent = cfs_proc_root;
584         } else {
585             ASSERT(NULL != cfs_proc_proc);
586             parent = cfs_proc_proc;
587         }
588     }
589
590     entry = proc_search_entry(name, parent);
591
592     if (!entry) {
593         entry = proc_insert_entry(name, parent);
594         if (!entry) {
595             /* Failed to create/insert the splay node ... */
596             cfs_enter_debugger();
597             goto errorout;
598         }
599         /* Initializing entry ... */
600         entry->mode = mode;
601
602         if (S_ISDIR(mode)) {
603             cfs_set_flag(entry->flags, CFS_PROC_FLAG_DIRECTORY);
604         }
605     }
606
607 errorout:
608
609     UNLOCK_PROCFS();
610
611     return entry;
612 }
613
614
615 /* search the specified entry form the proc fs */
616
617 cfs_proc_entry_t *
618 search_proc_entry(
619     const char *        name,
620     cfs_proc_entry_t *  root
621     )
622 {
623     cfs_proc_entry_t * entry;
624
625     LOCK_PROCFS();
626     ASSERT(cfs_proc_root != NULL);
627     if (root == NULL) {
628         if (name[0] == '/') {
629             root = cfs_proc_root;
630         } else {
631             ASSERT(cfs_proc_proc != NULL);
632             root = cfs_proc_proc;
633         }
634     }
635     entry = proc_search_entry(name, root);
636     UNLOCK_PROCFS();
637
638     return entry;    
639 }
640
641 /* remove the entry from the proc fs */
642
643 void
644 remove_proc_entry(
645     const char *        name,
646     cfs_proc_entry_t *  parent
647     )
648 {
649     LOCK_PROCFS();
650     ASSERT(cfs_proc_root != NULL);
651     if (parent == NULL) {
652         if (name[0] == '/') {
653             parent = cfs_proc_root;
654         } else {
655             ASSERT(cfs_proc_proc != NULL);
656             parent = cfs_proc_proc;
657         }
658     }
659     proc_remove_entry(name, parent);
660     UNLOCK_PROCFS();
661 }
662
663
664 void proc_destroy_splay(cfs_proc_entry_t * entry)
665 {
666     cfs_proc_entry_t * node;
667
668     if (S_ISDIR(entry->mode)) {
669
670         while (entry->root) {
671             node = CONTAINING_RECORD(entry->root, cfs_proc_entry_t, s_link);
672             entry->root = RtlDelete(&(node->s_link));
673             proc_destroy_splay(node);
674         }
675     }
676
677     proc_free_entry(entry);
678 }
679
680 cfs_proc_entry_t *proc_symlink(
681     const char *name,
682         cfs_proc_entry_t *parent,
683     const char *dest
684     )
685 {
686     cfs_enter_debugger();
687     return NULL;
688 }
689
690 cfs_proc_entry_t *proc_mkdir(
691     const char *name,
692         cfs_proc_entry_t *parent)
693 {
694     return create_proc_entry((char *)name, S_IFDIR, parent);
695 }
696
697 void proc_destory_subtree(cfs_proc_entry_t *entry)
698 {
699     LOCK_PROCFS();
700     entry->root = NULL;
701     proc_destroy_splay(entry);
702     UNLOCK_PROCFS();
703 }
704
705 /* destory the whole proc fs tree */
706
707 void proc_destroy_fs()
708 {
709         LOCK_PROCFS();
710
711         if (cfs_proc_root)
712                 proc_destroy_splay(cfs_proc_root);
713
714         if (proc_entry_cache)
715                 kmem_cache_destroy(proc_entry_cache);
716    
717         UNLOCK_PROCFS();
718 }
719
720 static char proc_item_path[512];
721
722
723 void proc_show_tree(cfs_proc_entry_t * node);
724 void proc_print_node(cfs_proc_entry_t * node)
725 {
726     if (node != cfs_proc_root) {
727         if (S_ISDIR(node->mode)) {
728             printk("%s/%s/\n", proc_item_path, node->name);
729         } else {
730             printk("%s/%s\n", proc_item_path, node->name);
731         }
732     } else {
733          printk("%s\n", node->name);
734     }
735
736     if (S_ISDIR(node->mode)) {
737         proc_show_tree(node);
738     }
739 }
740
741 void proc_show_child(PRTL_SPLAY_LINKS link)
742 {
743     cfs_proc_entry_t * entry  = NULL;
744
745     if (!link) {
746         return;
747     }
748
749     proc_show_child(link->LeftChild);
750     entry = CONTAINING_RECORD(link, cfs_proc_entry_t, s_link);
751     proc_print_node(entry);
752     proc_show_child(link->RightChild);
753 }
754
755 void proc_show_tree(cfs_proc_entry_t * node)
756 {
757     PRTL_SPLAY_LINKS link = NULL;
758     cfs_proc_entry_t * entry = NULL;
759     int i;
760
761     link = node->root;
762     i = strlen(proc_item_path);
763     ASSERT(S_ISDIR(node->mode));
764     if (node != cfs_proc_root) {
765         strcat(proc_item_path, "/");
766         strcat(proc_item_path, node->name);
767     }
768     proc_show_child(link);
769     proc_item_path[i] = 0;
770 }
771
772 void proc_print_splay()
773 {
774     printk("=================================================\n");
775     printk("Lustre virtual proc entries:\n");
776     printk("-------------------------------------------------\n");
777     LOCK_PROCFS();
778     proc_show_tree(cfs_proc_root);
779     UNLOCK_PROCFS();
780     printk("=================================================\n");
781 }
782
783
784 /* initilaize / build the proc fs tree */
785 int proc_init_fs()
786 {
787     cfs_proc_entry_t * root = NULL;
788
789     memset(&(root_table_header), 0, sizeof(struct ctl_table_header));
790     CFS_INIT_LIST_HEAD(&(root_table_header.ctl_entry));
791
792     INIT_PROCFS_LOCK();
793     proc_entry_cache = kmem_cache_create(NULL, sizeof(cfs_proc_entry_t),
794                                          0, 0, NULL);
795
796     if (!proc_entry_cache) {
797         return (-ENOMEM);
798     }
799
800     root = proc_alloc_entry();
801     if (!root) {
802         proc_destroy_fs();
803         return (-ENOMEM);
804     }
805     root->magic = CFS_PROC_ENTRY_MAGIC;
806     root->flags = CFS_PROC_FLAG_DIRECTORY;
807     root->mode  = S_IFDIR | S_IRUGO | S_IXUGO;
808     root->nlink = 3; // root should never be deleted.
809     root->name[0]='/';
810     root->name[1]= 0;
811     cfs_proc_root = root;
812
813     cfs_proc_dev = create_proc_entry("dev", S_IFDIR, root);
814     if (!cfs_proc_dev) {
815         goto errorout;
816     }
817     cfs_proc_dev->nlink = 1;
818
819     cfs_proc_proc  = create_proc_entry("proc", S_IFDIR, root);
820     if (!cfs_proc_proc) {
821         goto errorout;
822     }
823     cfs_proc_proc->nlink = 1;
824
825     cfs_proc_fs = create_proc_entry("fs",  S_IFDIR, cfs_proc_proc);
826     if (!cfs_proc_fs) {
827         goto errorout;
828     }
829     cfs_proc_fs->nlink = 1;
830
831     cfs_proc_sys = create_proc_entry("sys",  S_IFDIR, cfs_proc_proc);
832     if (!cfs_proc_sys) {
833         goto errorout;
834     }
835     cfs_proc_sys->nlink = 1;
836
837   
838     return 0;
839
840 errorout:
841
842     proc_destroy_fs();
843     return (-ENOMEM);
844 }
845
846
847 static ssize_t do_rw_proc(int write, struct file * file, char * buf,
848               size_t count, loff_t *ppos)
849 {
850     int op;
851     cfs_proc_entry_t *de;
852     struct ctl_table *table;
853     size_t res;
854     ssize_t error;
855     
856     de = (cfs_proc_entry_t *) file->proc_dentry; 
857
858     if (!de || !de->data)
859         return -ENOTDIR;
860     table = (struct ctl_table *) de->data;
861     if (!table || !table->proc_handler)
862         return -ENOTDIR;
863     op = (write ? 002 : 004);
864
865     res = count;
866
867     /*
868      * FIXME: we need to pass on ppos to the handler.
869      */
870
871     error = (*table->proc_handler) (table, write, file, buf, &res);
872     if (error)
873         return error;
874     return res;
875 }
876
877 static ssize_t proc_readsys(struct file * file, char * buf,
878                 size_t count, loff_t *ppos)
879 {
880     return do_rw_proc(0, file, buf, count, ppos);
881 }
882
883 static ssize_t proc_writesys(struct file * file, const char * buf,
884                  size_t count, loff_t *ppos)
885 {
886     return do_rw_proc(1, file, (char *) buf, count, ppos);
887 }
888
889
890 struct file_operations proc_sys_file_operations = {
891     /*owner*/       THIS_MODULE,
892     /*lseek:*/      NULL,
893     /*read:*/       proc_readsys,
894     /*write:*/      proc_writesys,
895     /*ioctl:*/      NULL,
896     /*open:*/       NULL,
897     /*release:*/    NULL
898 };
899
900
901 /* Scan the sysctl entries in table and add them all into /proc */
902 void register_proc_table(cfs_sysctl_table_t * table, cfs_proc_entry_t * root)
903 {
904     cfs_proc_entry_t * de;
905     int len;
906     mode_t mode;
907     
908     for (; table->ctl_name; table++) {
909         /* Can't do anything without a proc name. */
910         if (!table->procname)
911             continue;
912         /* Maybe we can't do anything with it... */
913         if (!table->proc_handler && !table->child) {
914             printk(CFS_KERN_WARNING "SYSCTL: Can't register %s\n",
915                 table->procname);
916             continue;
917         }
918
919         len = strlen(table->procname);
920         mode = table->mode;
921
922         de = NULL;
923         if (table->proc_handler)
924             mode |= S_IFREG;
925         else {
926             de = search_proc_entry(table->procname, root);
927             if (de) {
928                 break;
929             }
930             /* If the subdir exists already, de is non-NULL */
931         }
932
933         if (!de) {
934
935             de = create_proc_entry((char *)table->procname, mode, root);
936             if (!de)
937                 continue;
938             de->data = (void *) table;
939             if (table->proc_handler) {
940                 de->proc_fops = &proc_sys_file_operations;
941             }
942         }
943         table->de = de;
944         if (de->mode & S_IFDIR)
945             register_proc_table(table->child, de);
946     }
947 }
948
949
950 /*
951  * Unregister a /proc sysctl table and any subdirectories.
952  */
953 void unregister_proc_table(cfs_sysctl_table_t * table, cfs_proc_entry_t *root)
954 {
955     cfs_proc_entry_t *de;
956     for (; table->ctl_name; table++) {
957         if (!(de = table->de))
958             continue;
959         if (de->mode & S_IFDIR) {
960             if (!table->child) {
961                 printk (CFS_KERN_ALERT "Help- malformed sysctl tree on free\n");
962                 continue;
963             }
964             unregister_proc_table(table->child, de);
965
966             /* Don't unregister directories which still have entries.. */
967             if (de->nlink)
968                 continue;
969         }
970
971         /* Don't unregister proc entries that are still being used.. */
972         if (de->nlink)
973             continue;
974
975         table->de = NULL;
976         remove_proc_entry((char *)table->procname, root);
977     }
978 }
979
980 /* The generic string strategy routine: */
981 int sysctl_string(cfs_sysctl_table_t *table, int *name, int nlen,
982           void *oldval, size_t *oldlenp,
983           void *newval, size_t newlen, void **context)
984 {
985     int l, len;
986     
987     if (!table->data || !table->maxlen) 
988         return -ENOTDIR;
989     
990     if (oldval && oldlenp) {
991         if (get_user(len, oldlenp))
992             return -EFAULT;
993         if (len) {
994                 l = strlen(table->data);
995                 if (len > l)
996                         len = l;
997                 if (len >= table->maxlen)
998                         len = table->maxlen;
999                 if (copy_to_user(oldval, table->data, len))
1000                         return -EFAULT;
1001                 if (put_user(0, ((char *) oldval) + len))
1002                         return -EFAULT;
1003                 if (put_user(len, oldlenp))
1004                         return -EFAULT;
1005         }
1006     }
1007     if (newval && newlen) {
1008         len = newlen;
1009         if (len > table->maxlen)
1010             len = table->maxlen;
1011         if (copy_from_user(table->data, newval, len))
1012             return -EFAULT;
1013         if (len == table->maxlen)
1014             len--;
1015         ((char *) table->data)[len] = 0;
1016     }
1017     return 0;
1018 }
1019
1020 /**
1021  * simple_strtoul - convert a string to an unsigned long
1022  * @cp: The start of the string
1023  * @endp: A pointer to the end of the parsed string will be placed here
1024  * @base: The number base to use
1025  */
1026 unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
1027 {
1028     unsigned long result = 0, value;
1029
1030     if (!base) {
1031         base = 10;
1032         if (*cp == '0') {
1033             base = 8;
1034             cp++;
1035             if ((*cp == 'x') && cfs_isxdigit(cp[1])) {
1036                 cp++;
1037                 base = 16;
1038             }
1039         }
1040     }
1041     while (cfs_isxdigit(*cp) &&
1042            (value = cfs_isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) {
1043         result = result*base + value;
1044         cp++;
1045     }
1046     if (endp)
1047         *endp = (char *)cp;
1048     return result;
1049 }
1050
1051 #define OP_SET  0
1052 #define OP_AND  1
1053 #define OP_OR   2
1054 #define OP_MAX  3
1055 #define OP_MIN  4
1056
1057
1058 static int do_proc_dointvec(cfs_sysctl_table_t *table, int write, struct file *filp,
1059           void *buffer, size_t *lenp, int conv, int op)
1060 {
1061     int *i, vleft, first=1, neg, val;
1062     size_t left, len;
1063     
1064     #define TMPBUFLEN 20
1065     char buf[TMPBUFLEN], *p;
1066     
1067     if (!table->data || !table->maxlen || !*lenp)
1068     {
1069         *lenp = 0;
1070         return 0;
1071     }
1072     
1073     i = (int *) table->data;
1074     vleft = table->maxlen / sizeof(int);
1075     left = *lenp;
1076     
1077     for (; left && vleft--; i++, first=0) {
1078         if (write) {
1079             while (left) {
1080                 char c;
1081                 if (get_user(c, (char *)buffer))
1082                         return -EFAULT;
1083                 if (!isspace(c))
1084                         break;
1085                 left--;
1086                 ((char *)buffer)++;
1087             }
1088             if (!left)
1089                 break;
1090             neg = 0;
1091             len = left;
1092             if (len > TMPBUFLEN-1)
1093                 len = TMPBUFLEN-1;
1094             if (copy_from_user(buf, buffer, len))
1095                 return -EFAULT;
1096             buf[len] = 0;
1097             p = buf;
1098             if (*p == '-' && left > 1) {
1099                 neg = 1;
1100                 left--, p++;
1101             }
1102             if (*p < '0' || *p > '9')
1103                 break;
1104             val = simple_strtoul(p, &p, 0) * conv;
1105             len = p-buf;
1106             if ((len < left) && *p && !isspace(*p))
1107                 break;
1108             if (neg)
1109                 val = -val;
1110             (char *)buffer += len;
1111             left -= len;
1112                 switch(op) {
1113                 case OP_SET:
1114                         *i = val;
1115                         break;
1116                 case OP_AND:
1117                         *i &= val;
1118                         break;
1119                 case OP_OR:
1120                         *i |= val;
1121                         break;
1122                 case OP_MAX:
1123                         if (*i < val)
1124                                 *i = val;
1125                         break;
1126                 case OP_MIN:
1127                         if (*i > val)
1128                                 *i = val;
1129                         break;
1130                 }
1131         } else {
1132             p = buf;
1133             if (!first)
1134                 *p++ = '\t';
1135             sprintf(p, "%d", (*i) / conv);
1136             len = strlen(buf);
1137             if (len > left)
1138                 len = left;
1139             if (copy_to_user(buffer, buf, len))
1140                 return -EFAULT;
1141             left -= len;
1142             (char *)buffer += len;
1143         }
1144     }
1145
1146     if (!write && !first && left) {
1147         if (put_user('\n', (char *) buffer))
1148             return -EFAULT;
1149         left--, ((char *)buffer)++;
1150     }
1151     if (write) {
1152         p = (char *) buffer;
1153         while (left) {
1154             char c;
1155             if (get_user(c, p++))
1156                 return -EFAULT;
1157             if (!isspace(c))
1158                 break;
1159             left--;
1160         }
1161     }
1162     if (write && first)
1163         return -EINVAL;
1164     *lenp -= left;
1165     memset(&(filp->f_pos) , 0, sizeof(loff_t));
1166     filp->f_pos += (loff_t)(*lenp);
1167     return 0;
1168 }
1169
1170 /**
1171  * proc_dointvec - read a vector of integers
1172  * @table: the sysctl table
1173  * @write: %TRUE if this is a write to the sysctl file
1174  * @filp: the file structure
1175  * @buffer: the user buffer
1176  * @lenp: the size of the user buffer
1177  *
1178  * Reads/writes up to table->maxlen/sizeof(unsigned int) integer
1179  * values from/to the user buffer, treated as an ASCII string. 
1180  *
1181  * Returns 0 on success.
1182  */
1183 int proc_dointvec(cfs_sysctl_table_t *table, int write, struct file *filp,
1184              void *buffer, size_t *lenp)
1185 {
1186     return do_proc_dointvec(table,write,filp,buffer,lenp,1,OP_SET);
1187 }
1188
1189
1190 /**
1191  * proc_dostring - read a string sysctl
1192  * @table: the sysctl table
1193  * @write: %TRUE if this is a write to the sysctl file
1194  * @filp: the file structure
1195  * @buffer: the user buffer
1196  * @lenp: the size of the user buffer
1197  *
1198  * Reads/writes a string from/to the user buffer. If the kernel
1199  * buffer provided is not large enough to hold the string, the
1200  * string is truncated. The copied string is %NULL-terminated.
1201  * If the string is being read by the user process, it is copied
1202  * and a newline '\n' is added. It is truncated if the buffer is
1203  * not large enough.
1204  *
1205  * Returns 0 on success.
1206  */
1207 int proc_dostring(cfs_sysctl_table_t *table, int write, struct file *filp,
1208           void *buffer, size_t *lenp)
1209 {
1210     size_t len;
1211     char *p, c;
1212     
1213     if (!table->data || !table->maxlen || !*lenp ||
1214         (filp->f_pos && !write)) {
1215         *lenp = 0;
1216         return 0;
1217     }
1218     
1219     if (write) {
1220         len = 0;
1221         p = buffer;
1222         while (len < *lenp) {
1223             if (get_user(c, p++))
1224                 return -EFAULT;
1225             if (c == 0 || c == '\n')
1226                 break;
1227             len++;
1228         }
1229         if (len >= (size_t)table->maxlen)
1230             len = (size_t)table->maxlen-1;
1231         if (copy_from_user(table->data, buffer, len))
1232             return -EFAULT;
1233         ((char *) table->data)[len] = 0;
1234         filp->f_pos += *lenp;
1235     } else {
1236         len = (size_t)strlen(table->data);
1237         if (len > (size_t)table->maxlen)
1238             len = (size_t)table->maxlen;
1239         if (len > *lenp)
1240             len = *lenp;
1241         if (len)
1242             if (copy_to_user(buffer, table->data, len))
1243                 return -EFAULT;
1244         if (len < *lenp) {
1245             if (put_user('\n', ((char *) buffer) + len))
1246                 return -EFAULT;
1247             len++;
1248         }
1249         *lenp = len;
1250         filp->f_pos += len;
1251     }
1252     return 0;
1253 }
1254
1255 /* Perform the actual read/write of a sysctl table entry. */
1256 int do_sysctl_strategy (cfs_sysctl_table_t *table, 
1257             int *name, int nlen,
1258             void *oldval, size_t *oldlenp,
1259             void *newval, size_t newlen, void **context)
1260 {
1261     int op = 0, rc;
1262     size_t len;
1263
1264     if (oldval)
1265         op |= 004;
1266     if (newval) 
1267         op |= 002;
1268
1269     if (table->strategy) {
1270         rc = table->strategy(table, name, nlen, oldval, oldlenp,
1271                      newval, newlen, context);
1272         if (rc < 0)
1273             return rc;
1274         if (rc > 0)
1275             return 0;
1276     }
1277
1278     /* If there is no strategy routine, or if the strategy returns
1279      * zero, proceed with automatic r/w */
1280     if (table->data && table->maxlen) {
1281         if (oldval && oldlenp) {
1282             get_user(len, oldlenp);
1283             if (len) {
1284                 if (len > (size_t)table->maxlen)
1285                     len = (size_t)table->maxlen;
1286                 if (copy_to_user(oldval, table->data, len))
1287                     return -EFAULT;
1288                 if (put_user(len, oldlenp))
1289                     return -EFAULT;
1290             }
1291         }
1292         if (newval && newlen) {
1293             len = newlen;
1294             if (len > (size_t)table->maxlen)
1295                 len = (size_t)table->maxlen;
1296             if (copy_from_user(table->data, newval, len))
1297                 return -EFAULT;
1298         }
1299     }
1300     return 0;
1301 }
1302
1303 static int parse_table(int *name, int nlen,
1304                void *oldval, size_t *oldlenp,
1305                void *newval, size_t newlen,
1306                cfs_sysctl_table_t *table, void **context)
1307 {
1308     int n;
1309
1310 repeat:
1311
1312     if (!nlen)
1313         return -ENOTDIR;
1314     if (get_user(n, name))
1315         return -EFAULT;
1316     for ( ; table->ctl_name; table++) {
1317         if (n == table->ctl_name || table->ctl_name == CTL_ANY) {
1318             int error;
1319             if (table->child) {
1320 /*
1321                 if (ctl_perm(table, 001))
1322                     return -EPERM;
1323 */
1324                 if (table->strategy) {
1325                     error = table->strategy(
1326                         table, name, nlen,
1327                         oldval, oldlenp,
1328                         newval, newlen, context);
1329                     if (error)
1330                         return error;
1331                 }
1332                 name++;
1333                 nlen--;
1334                 table = table->child;
1335                 goto repeat;
1336             }
1337             error = do_sysctl_strategy(table, name, nlen,
1338                            oldval, oldlenp,
1339                            newval, newlen, context);
1340             return error;
1341         }
1342     }
1343     return -ENOTDIR;
1344 }
1345
1346 int do_sysctl(int *name, int nlen, void *oldval, size_t *oldlenp,
1347            void *newval, size_t newlen)
1348 {
1349     cfs_list_t *tmp;
1350
1351     if (nlen <= 0 || nlen >= CTL_MAXNAME)
1352         return -ENOTDIR;
1353     if (oldval) {
1354         int old_len;
1355         if (!oldlenp || get_user(old_len, oldlenp))
1356             return -EFAULT;
1357     }
1358     tmp = &root_table_header.ctl_entry;
1359     do {
1360         struct ctl_table_header *head =
1361             cfs_list_entry(tmp, struct ctl_table_header, ctl_entry);
1362         void *context = NULL;
1363         int error = parse_table(name, nlen, oldval, oldlenp, 
1364                     newval, newlen, head->ctl_table,
1365                     &context);
1366         if (context)
1367             kfree(context);
1368         if (error != -ENOTDIR)
1369             return error;
1370         tmp = tmp->next;
1371     } while (tmp != &root_table_header.ctl_entry);
1372     return -ENOTDIR;
1373 }
1374
1375 /**
1376  * register_sysctl_table - register a sysctl heirarchy
1377  * @table: the top-level table structure
1378  * @insert_at_head: whether the entry should be inserted in front or at the end
1379  *
1380  * Register a sysctl table heirarchy. @table should be a filled in ctl_table
1381  * array. An entry with a ctl_name of 0 terminates the table. 
1382  *
1383  * The members of the &ctl_table structure are used as follows:
1384  *
1385  * ctl_name - This is the numeric sysctl value used by sysctl(2). The number
1386  *            must be unique within that level of sysctl
1387  *
1388  * procname - the name of the sysctl file under /proc/sys. Set to %NULL to not
1389  *            enter a sysctl file
1390  *
1391  * data - a pointer to data for use by proc_handler
1392  *
1393  * maxlen - the maximum size in bytes of the data
1394  *
1395  * mode - the file permissions for the /proc/sys file, and for sysctl(2)
1396  *
1397  * child - a pointer to the child sysctl table if this entry is a directory, or
1398  *         %NULL.
1399  *
1400  * proc_handler - the text handler routine (described below)
1401  *
1402  * strategy - the strategy routine (described below)
1403  *
1404  * de - for internal use by the sysctl routines
1405  *
1406  * extra1, extra2 - extra pointers usable by the proc handler routines
1407  *
1408  * Leaf nodes in the sysctl tree will be represented by a single file
1409  * under /proc; non-leaf nodes will be represented by directories.
1410  *
1411  * sysctl(2) can automatically manage read and write requests through
1412  * the sysctl table.  The data and maxlen fields of the ctl_table
1413  * struct enable minimal validation of the values being written to be
1414  * performed, and the mode field allows minimal authentication.
1415  *
1416  * More sophisticated management can be enabled by the provision of a
1417  * strategy routine with the table entry.  This will be called before
1418  * any automatic read or write of the data is performed.
1419  *
1420  * The strategy routine may return
1421  *
1422  * < 0 - Error occurred (error is passed to user process)
1423  *
1424  * 0   - OK - proceed with automatic read or write.
1425  *
1426  * > 0 - OK - read or write has been done by the strategy routine, so
1427  *       return immediately.
1428  *
1429  * There must be a proc_handler routine for any terminal nodes
1430  * mirrored under /proc/sys (non-terminals are handled by a built-in
1431  * directory handler).  Several default handlers are available to
1432  * cover common cases -
1433  *
1434  * proc_dostring(), proc_dointvec(), proc_dointvec_jiffies(),
1435  * proc_dointvec_minmax(), proc_doulongvec_ms_jiffies_minmax(),
1436  * proc_doulongvec_minmax()
1437  *
1438  * It is the handler's job to read the input buffer from user memory
1439  * and process it. The handler should return 0 on success.
1440  *
1441  * This routine returns %NULL on a failure to register, and a pointer
1442  * to the table header on success.
1443  */
1444 struct ctl_table_header *register_sysctl_table(cfs_sysctl_table_t * table, 
1445                            int insert_at_head)
1446 {
1447     struct ctl_table_header *tmp;
1448     tmp = kmalloc(sizeof(struct ctl_table_header), 0);
1449     if (!tmp)
1450         return NULL;
1451     tmp->ctl_table = table;
1452
1453     CFS_INIT_LIST_HEAD(&tmp->ctl_entry);
1454     if (insert_at_head)
1455         cfs_list_add(&tmp->ctl_entry, &root_table_header.ctl_entry);
1456     else
1457         cfs_list_add_tail(&tmp->ctl_entry, &root_table_header.ctl_entry);
1458 #ifdef CONFIG_PROC_FS
1459     register_proc_table(table, cfs_proc_sys);
1460 #endif
1461     return tmp;
1462 }
1463
1464 /**
1465  * unregister_sysctl_table - unregister a sysctl table heirarchy
1466  * @header: the header returned from register_sysctl_table
1467  *
1468  * Unregisters the sysctl table and all children. proc entries may not
1469  * actually be removed until they are no longer used by anyone.
1470  */
1471 void unregister_sysctl_table(struct ctl_table_header * header)
1472 {
1473     cfs_list_del(&header->ctl_entry);
1474 #ifdef CONFIG_PROC_FS
1475     unregister_proc_table(header->ctl_table, cfs_proc_sys);
1476 #endif
1477     kfree(header);
1478 }
1479
1480
1481 int cfs_psdev_register(cfs_psdev_t * psdev)
1482 {
1483     cfs_proc_entry_t *  entry;
1484
1485     entry = create_proc_entry (
1486                 (char *)psdev->name,
1487                 S_IFREG,
1488                 cfs_proc_dev
1489             );
1490
1491     if (!entry) {
1492         return -ENOMEM;
1493     }
1494
1495     entry->flags |= CFS_PROC_FLAG_MISCDEV;
1496
1497     entry->proc_fops = psdev->fops;
1498     entry->data = (void *)psdev;
1499
1500     return 0;
1501 }
1502
1503 int cfs_psdev_deregister(cfs_psdev_t * psdev)
1504 {
1505     cfs_proc_entry_t *  entry;
1506
1507     entry = search_proc_entry (
1508                 (char *)psdev->name,
1509                 cfs_proc_dev
1510             );
1511
1512     if (entry) {
1513
1514         ASSERT(entry->data == (void *)psdev);
1515         ASSERT(entry->flags & CFS_PROC_FLAG_MISCDEV);
1516
1517         remove_proc_entry(
1518             (char *)psdev->name,
1519             cfs_proc_dev
1520             );
1521     }
1522
1523     return 0;
1524 }
1525
1526 #define PSDEV_LNET  (0x100)
1527 enum {
1528         PSDEV_DEBUG = 1,          /* control debugging */
1529         PSDEV_SUBSYSTEM_DEBUG,    /* control debugging */
1530         PSDEV_PRINTK,             /* force all messages to console */
1531         PSDEV_CONSOLE_RATELIMIT,  /* rate limit console messages */
1532         PSDEV_DEBUG_PATH,         /* crashdump log location */
1533         PSDEV_DEBUG_DUMP_PATH,    /* crashdump tracelog location */
1534         PSDEV_LIBCFS_MEMUSED,     /* bytes currently PORTAL_ALLOCated */
1535 };
1536
1537 static struct ctl_table lnet_table[] = {
1538         {PSDEV_DEBUG, "debug", &libcfs_debug, sizeof(int), 0644, NULL,
1539          &proc_dointvec},
1540         {PSDEV_SUBSYSTEM_DEBUG, "subsystem_debug", &libcfs_subsystem_debug,
1541          sizeof(int), 0644, NULL, &proc_dointvec},
1542         {PSDEV_PRINTK, "printk", &libcfs_printk, sizeof(int), 0644, NULL,
1543          &proc_dointvec},
1544         {PSDEV_CONSOLE_RATELIMIT, "console_ratelimit", &libcfs_console_ratelimit,
1545          sizeof(int), 0644, NULL, &proc_dointvec},
1546 /*
1547         {PSDEV_PORTALS_UPCALL, "upcall", portals_upcall,
1548          sizeof(portals_upcall), 0644, NULL, &proc_dostring,
1549          &sysctl_string},
1550 */
1551         {PSDEV_LIBCFS_MEMUSED, "memused", (int *)&libcfs_kmemory.counter,
1552          sizeof(int), 0644, NULL, &proc_dointvec},
1553         {0}
1554 };
1555
1556 static struct ctl_table top_table[2] = {
1557         {PSDEV_LNET, "lnet", NULL, 0, 0555, lnet_table},
1558         {0}
1559 };
1560
1561
1562 int trace_write_dump_kernel(struct file *file, const char *buffer,
1563                              unsigned long count, void *data)
1564 {
1565         int rc = cfs_trace_dump_debug_buffer_usrstr((void *)buffer, count);
1566         
1567         return (rc < 0) ? rc : count;
1568 }
1569
1570 int trace_write_daemon_file(struct file *file, const char *buffer,
1571                             unsigned long count, void *data)
1572 {
1573         int rc = cfs_trace_daemon_command_usrstr((void *)buffer, count);
1574
1575         return (rc < 0) ? rc : count;
1576 }
1577
1578 int trace_read_daemon_file(char *page, char **start, off_t off, int count,
1579                            int *eof, void *data)
1580 {
1581         int rc;
1582         cfs_tracefile_read_lock();
1583         rc = cfs_trace_copyout_string(page, count, cfs_tracefile, "\n");
1584         cfs_tracefile_read_unlock();
1585         return rc;
1586 }
1587
1588 int trace_write_debug_mb(struct file *file, const char *buffer,
1589                          unsigned long count, void *data)
1590 {
1591         int rc = 0; /*trace_set_debug_mb_userstr((void *)buffer, count);*/
1592         
1593         return (rc < 0) ? rc : count;
1594 }
1595
1596 int trace_read_debug_mb(char *page, char **start, off_t off, int count,
1597                         int *eof, void *data)
1598 {
1599         char   str[32];
1600
1601         snprintf(str, sizeof(str), "%d\n", cfs_trace_get_debug_mb());
1602
1603         return cfs_trace_copyout_string(page, count, str, NULL);
1604 }
1605
1606 int insert_proc(void)
1607 {
1608         cfs_proc_entry_t *ent;
1609
1610         ent = create_proc_entry("sys/lnet/dump_kernel", 0, NULL);
1611         if (ent == NULL) {
1612                 CERROR("couldn't register dump_kernel\n");
1613                 return -1;
1614         }
1615         ent->write_proc = trace_write_dump_kernel;
1616
1617         ent = create_proc_entry("sys/lnet/daemon_file", 0, NULL);
1618         if (ent == NULL) {
1619                 CERROR("couldn't register daemon_file\n");
1620                 return -1;
1621         }
1622         ent->write_proc = trace_write_daemon_file;
1623         ent->read_proc = trace_read_daemon_file;
1624
1625         ent = create_proc_entry("sys/lnet/debug_mb", 0, NULL);
1626         if (ent == NULL) {
1627                 CERROR("couldn't register debug_mb\n");
1628                 return -1;
1629         }
1630         ent->write_proc = trace_write_debug_mb;
1631         ent->read_proc = trace_read_debug_mb;
1632
1633         return 0;
1634 }
1635
1636 void remove_proc(void)
1637 {
1638         remove_proc_entry("sys/lnet/dump_kernel", NULL);
1639         remove_proc_entry("sys/lnet/daemon_file", NULL);
1640         remove_proc_entry("sys/lnet/debug_mb", NULL);
1641 }
1642
1643
1644 /*
1645  *  proc process routines of kernel space
1646  */
1647
1648 struct file *
1649 lustre_open_file(char *filename)
1650 {
1651         int rc = 0;
1652         struct file *fh = NULL;
1653         cfs_proc_entry_t *fp = NULL;
1654
1655         fp = search_proc_entry(filename, cfs_proc_root);
1656         if (fp == NULL)
1657                 return NULL;
1658
1659         fh = kmalloc(sizeof(*fh), __GFP_ZERO);
1660         if (fh == NULL)
1661                 return NULL;
1662
1663     fh->f_inode = kmalloc(sizeof(struct inode), __GFP_ZERO);
1664     if (!fh->f_inode) {
1665         kfree(fh);
1666         return NULL;
1667     }
1668
1669     fh->f_inode->i_priv = (void *)fp;
1670     fh->f_op = fp->proc_fops;
1671
1672     if (fh->f_op->open) {
1673         rc = (fh->f_op->open)(fh->f_inode, fh);
1674     } else {
1675         fp->nlink++;
1676     }
1677
1678     if (0 != rc) {
1679         kfree(fh->f_inode);
1680         kfree(fh);
1681         return NULL;
1682     }
1683
1684     return fh;
1685 }
1686
1687 int
1688 lustre_close_file(struct file *fh)
1689 {
1690         int rc = 0;
1691         cfs_proc_entry_t *fp = NULL;
1692
1693     fp = (cfs_proc_entry_t *) fh->f_inode->i_priv;
1694     if (fh->f_op->release) {
1695         rc = (fh->f_op->release)(fh->f_inode, fh);
1696     } else {
1697         fp->nlink--;
1698     }
1699
1700     kfree(fh->f_inode);
1701     kfree(fh);
1702
1703     return rc;
1704 }
1705
1706 int
1707 lustre_do_ioctl(struct file *fh, unsigned long cmd, ulong_ptr_t arg)
1708 {
1709         int rc = 0;
1710
1711         if (fh->f_op->ioctl)
1712                 rc = (fh->f_op->ioctl)(fh, cmd, arg);
1713
1714         return rc;
1715 }
1716
1717 int
1718 lustre_ioctl_file(struct file *fh, PCFS_PROC_IOCTL devctl)
1719 {
1720     int         rc = 0;
1721     ulong_ptr_t data;
1722
1723     data = (ulong_ptr_t)devctl + sizeof(CFS_PROC_IOCTL);
1724 #if defined(_X86_)    
1725     CLASSERT(sizeof(struct obd_ioctl_data) == 528);
1726 #else
1727     CLASSERT(sizeof(struct obd_ioctl_data) == 576);
1728 #endif
1729
1730     /* obd ioctl code */
1731     if (_IOC_TYPE(devctl->cmd) == 'f') {
1732
1733         struct obd_ioctl_data * obd = (struct obd_ioctl_data *) data;
1734
1735         if ( devctl->cmd != (ULONG)OBD_IOC_BRW_WRITE  &&
1736              devctl->cmd != (ULONG)OBD_IOC_BRW_READ ) {
1737
1738             unsigned long off = obd->ioc_len;
1739
1740             if (obd->ioc_plen1) {
1741                 obd->ioc_pbuf1 = (char *)(data + off);
1742                 off += cfs_size_round(obd->ioc_plen1);
1743             } else {
1744                 obd->ioc_pbuf1 = NULL;
1745             }
1746
1747             if (obd->ioc_plen2) {
1748                 obd->ioc_pbuf2 = (char *)(data + off);
1749                 off += cfs_size_round(obd->ioc_plen2);
1750             } else {
1751                 obd->ioc_pbuf2 = NULL;
1752             }
1753         }
1754     }
1755
1756     rc = lustre_do_ioctl(fh, devctl->cmd, data);
1757
1758     return rc;
1759 }
1760
1761 size_t
1762 lustre_read_file(struct file *fh, loff_t off, size_t size, char *buf)
1763 {
1764     size_t  rc = 0;
1765     off_t   low, high;
1766
1767     low = (off_t) size;
1768     high = (off_t)(off >> 32);
1769
1770     if (fh->f_op->read) {
1771         rc = (fh->f_op->read) (fh, buf, size, &off);
1772     }
1773
1774     if (rc) {
1775         fh->f_pos = off + rc;
1776     }
1777
1778     return rc;
1779 }
1780
1781 size_t
1782 lustre_write_file(struct file *fh, loff_t off, size_t size, char *buf)
1783 {
1784         size_t rc = 0;
1785
1786         off = 0;
1787         if (fh->f_op->write)
1788                 rc = (fh->f_op->write)(fh, buf, size, &off);
1789
1790         return rc;
1791 }
1792
1793
1794 /*
1795  *  seq file routines
1796  */
1797
1798 /**
1799  *      seq_open -      initialize sequential file
1800  *      @file: file we initialize
1801  *      @op: method table describing the sequence
1802  *
1803  *      seq_open() sets @file, associating it with a sequence described
1804  *      by @op.  @op->start() sets the iterator up and returns the first
1805  *      element of sequence. @op->stop() shuts it down.  @op->next()
1806  *      returns the next element of sequence.  @op->show() prints element
1807  *      into the buffer.  In case of error ->start() and ->next() return
1808  *      ERR_PTR(error).  In the end of sequence they return %NULL. ->show()
1809  *      returns 0 in case of success and negative number in case of error.
1810  */
1811 int seq_open(struct file *file, const struct seq_operations *op)
1812 {
1813         struct seq_file *p = file->private_data;
1814
1815         if (!p) {
1816                 p = kmalloc(sizeof(*p), GFP_KERNEL);
1817                 if (!p)
1818                         return -ENOMEM;
1819                 file->private_data = p;
1820         }
1821         memset(p, 0, sizeof(*p));
1822         mutex_init(&p->lock);
1823         p->op = op;
1824
1825         /*
1826          * Wrappers around seq_open(e.g. swaps_open) need to be
1827          * aware of this. If they set f_version themselves, they
1828          * should call seq_open first and then set f_version.
1829          */
1830         file->f_version = 0;
1831
1832         /* SEQ files support lseek, but not pread/pwrite */
1833         file->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE);
1834         return 0;
1835 }
1836 EXPORT_SYMBOL(seq_open);
1837
1838 /**
1839  *      seq_read -      ->read() method for sequential files.
1840  *      @file: the file to read from
1841  *      @buf: the buffer to read to
1842  *      @size: the maximum number of bytes to read
1843  *      @ppos: the current position in the file
1844  *
1845  *      Ready-made ->f_op->read()
1846  */
1847 ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
1848 {
1849         struct seq_file *m = (struct seq_file *)file->private_data;
1850         size_t copied = 0;
1851         loff_t pos;
1852         size_t n;
1853         void *p;
1854         int err = 0;
1855
1856         mutex_lock(&m->lock);
1857         /*
1858          * seq_file->op->..m_start/m_stop/m_next may do special actions
1859          * or optimisations based on the file->f_version, so we want to
1860          * pass the file->f_version to those methods.
1861          *
1862          * seq_file->version is just copy of f_version, and seq_file
1863          * methods can treat it simply as file version.
1864          * It is copied in first and copied out after all operations.
1865          * It is convenient to have it as  part of structure to avoid the
1866          * need of passing another argument to all the seq_file methods.
1867          */
1868         m->version = file->f_version;
1869         /* grab buffer if we didn't have one */
1870         if (!m->buf) {
1871                 m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL);
1872                 if (!m->buf)
1873                         goto Enomem;
1874         }
1875         /* if not empty - flush it first */
1876         if (m->count) {
1877                 n = min(m->count, size);
1878                 err = copy_to_user(buf, m->buf + m->from, n);
1879                 if (err)
1880                         goto Efault;
1881                 m->count -= n;
1882                 m->from += n;
1883                 size -= n;
1884                 buf += n;
1885                 copied += n;
1886                 if (!m->count)
1887                         m->index++;
1888                 if (!size)
1889                         goto Done;
1890         }
1891         /* we need at least one record in buffer */
1892         while (1) {
1893                 pos = m->index;
1894                 p = m->op->start(m, &pos);
1895                 err = PTR_ERR(p);
1896                 if (!p || IS_ERR(p))
1897                         break;
1898                 err = m->op->show(m, p);
1899                 if (err)
1900                         break;
1901                 if (m->count < m->size)
1902                         goto Fill;
1903                 m->op->stop(m, p);
1904                 kfree(m->buf);
1905                 m->buf = kmalloc(m->size <<= 1, GFP_KERNEL);
1906                 if (!m->buf)
1907                         goto Enomem;
1908                 m->count = 0;
1909                 m->version = 0;
1910         }
1911         m->op->stop(m, p);
1912         m->count = 0;
1913         goto Done;
1914 Fill:
1915         /* they want more? let's try to get some more */
1916         while (m->count < size) {
1917                 size_t offs = m->count;
1918                 loff_t next = pos;
1919                 p = m->op->next(m, p, &next);
1920                 if (!p || IS_ERR(p)) {
1921                         err = PTR_ERR(p);
1922                         break;
1923                 }
1924                 err = m->op->show(m, p);
1925                 if (err || m->count == m->size) {
1926                         m->count = offs;
1927                         break;
1928                 }
1929                 pos = next;
1930         }
1931         m->op->stop(m, p);
1932         n = min(m->count, size);
1933         err = copy_to_user(buf, m->buf, n);
1934         if (err)
1935                 goto Efault;
1936         copied += n;
1937         m->count -= n;
1938         if (m->count)
1939                 m->from = n;
1940         else
1941                 pos++;
1942         m->index = pos;
1943 Done:
1944         if (!copied)
1945                 copied = err;
1946         else
1947                 *ppos += copied;
1948         file->f_version = m->version;
1949         mutex_unlock(&m->lock);
1950         return copied;
1951 Enomem:
1952         err = -ENOMEM;
1953         goto Done;
1954 Efault:
1955         err = -EFAULT;
1956         goto Done;
1957 }
1958 EXPORT_SYMBOL(seq_read);
1959
1960 static int traverse(struct seq_file *m, loff_t offset)
1961 {
1962         loff_t pos = 0, index;
1963         int error = 0;
1964         void *p;
1965
1966         m->version = 0;
1967         index = 0;
1968         m->count = m->from = 0;
1969         if (!offset) {
1970                 m->index = index;
1971                 return 0;
1972         }
1973         if (!m->buf) {
1974                 m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL);
1975                 if (!m->buf)
1976                         return -ENOMEM;
1977         }
1978         p = m->op->start(m, &index);
1979         while (p) {
1980                 error = PTR_ERR(p);
1981                 if (IS_ERR(p))
1982                         break;
1983                 error = m->op->show(m, p);
1984                 if (error)
1985                         break;
1986                 if (m->count == m->size)
1987                         goto Eoverflow;
1988                 if (pos + (loff_t)(m->count) > offset) {
1989                         m->from = (size_t)(offset - pos);
1990                         m->count -= m->from;
1991                         m->index = index;
1992                         break;
1993                 }
1994                 pos += m->count;
1995                 m->count = 0;
1996                 if (pos == offset) {
1997                         index++;
1998                         m->index = index;
1999                         break;
2000                 }
2001                 p = m->op->next(m, p, &index);
2002         }
2003         m->op->stop(m, p);
2004         return error;
2005
2006 Eoverflow:
2007         m->op->stop(m, p);
2008         kfree(m->buf);
2009         m->buf = kmalloc(m->size <<= 1, GFP_KERNEL | __GFP_ZERO);
2010         return !m->buf ? -ENOMEM : -EAGAIN;
2011 }
2012
2013 /**
2014  *      seq_lseek -     ->llseek() method for sequential files.
2015  *      @file: the file in question
2016  *      @offset: new position
2017  *      @origin: 0 for absolute, 1 for relative position
2018  *
2019  *      Ready-made ->f_op->llseek()
2020  */
2021 loff_t seq_lseek(struct file *file, loff_t offset, int origin)
2022 {
2023         struct seq_file *m = (struct seq_file *)file->private_data;
2024         long long retval = -EINVAL;
2025
2026         mutex_lock(&m->lock);
2027         m->version = file->f_version;
2028         switch (origin) {
2029                 case 1:
2030                         offset += file->f_pos;
2031                 case 0:
2032                         if (offset < 0)
2033                                 break;
2034                         retval = offset;
2035                         if (offset != file->f_pos) {
2036                                 while ((retval=traverse(m, offset)) == -EAGAIN)
2037                                         ;
2038                                 if (retval) {
2039                                         /* with extreme prejudice... */
2040                                         file->f_pos = 0;
2041                                         m->version = 0;
2042                                         m->index = 0;
2043                                         m->count = 0;
2044                                 } else {
2045                                         retval = file->f_pos = offset;
2046                                 }
2047                         }
2048         }
2049         file->f_version = m->version;
2050         mutex_unlock(&m->lock);
2051         return retval;
2052 }
2053 EXPORT_SYMBOL(seq_lseek);
2054
2055 /**
2056  *      seq_release -   free the structures associated with sequential file.
2057  *      @file: file in question
2058  *      @inode: file->f_path.dentry->d_inode
2059  *
2060  *      Frees the structures associated with sequential file; can be used
2061  *      as ->f_op->release() if you don't have private data to destroy.
2062  */
2063 int seq_release(struct inode *inode, struct file *file)
2064 {
2065         struct seq_file *m = (struct seq_file *)file->private_data;
2066     if (m) {
2067         if (m->buf)
2068                 kfree(m->buf);
2069             kfree(m);
2070     }
2071         return 0;
2072 }
2073 EXPORT_SYMBOL(seq_release);
2074
2075 /**
2076  *      seq_escape -    print string into buffer, escaping some characters
2077  *      @m:     target buffer
2078  *      @s:     string
2079  *      @esc:   set of characters that need escaping
2080  *
2081  *      Puts string into buffer, replacing each occurrence of character from
2082  *      @esc with usual octal escape.  Returns 0 in case of success, -1 - in
2083  *      case of overflow.
2084  */
2085 int seq_escape(struct seq_file *m, const char *s, const char *esc)
2086 {
2087         char *end = m->buf + m->size;
2088         char *p;
2089         char c;
2090
2091         for (p = m->buf + m->count; (c = *s) != '\0' && p < end; s++) {
2092                 if (!strchr(esc, c)) {
2093                         *p++ = c;
2094                         continue;
2095                 }
2096                 if (p + 3 < end) {
2097                         *p++ = '\\';
2098                         *p++ = '0' + ((c & 0300) >> 6);
2099                         *p++ = '0' + ((c & 070) >> 3);
2100                         *p++ = '0' + (c & 07);
2101                         continue;
2102                 }
2103                 m->count = m->size;
2104                 return -1;
2105         }
2106         m->count = p - m->buf;
2107         return 0;
2108 }
2109 EXPORT_SYMBOL(seq_escape);
2110
2111 int seq_printf(struct seq_file *m, const char *f, ...)
2112 {
2113         va_list args;
2114         int len;
2115
2116         if (m->count < m->size) {
2117                 va_start(args, f);
2118                 len = vsnprintf(m->buf + m->count, m->size - m->count, f, args);
2119                 va_end(args);
2120                 if (m->count + len < m->size) {
2121                         m->count += len;
2122                         return 0;
2123                 }
2124         }
2125         m->count = m->size;
2126         return -1;
2127 }
2128 EXPORT_SYMBOL(seq_printf);
2129
2130 char *d_path(struct path *p, char *buffer, int buflen)
2131 {
2132         cfs_enter_debugger();
2133         return ERR_PTR(-ENAMETOOLONG);
2134 }
2135
2136 int seq_path(struct seq_file *m, struct path *path, char *esc)
2137 {
2138         if (m->count < m->size) {
2139                 char *s = m->buf + m->count;
2140                 char *p = d_path(path, s, m->size - m->count);
2141                 if (!IS_ERR(p)) {
2142                         while (s <= p) {
2143                                 char c = *p++;
2144                                 if (!c) {
2145                                         p = m->buf + m->count;
2146                                         m->count = s - m->buf;
2147                                         return (int)(s - p);
2148                                 } else if (!strchr(esc, c)) {
2149                                         *s++ = c;
2150                                 } else if (s + 4 > p) {
2151                                         break;
2152                                 } else {
2153                                         *s++ = '\\';
2154                                         *s++ = '0' + ((c & 0300) >> 6);
2155                                         *s++ = '0' + ((c & 070) >> 3);
2156                                         *s++ = '0' + (c & 07);
2157                                 }
2158                         }
2159                 }
2160         }
2161         m->count = m->size;
2162         return -1;
2163 }
2164 EXPORT_SYMBOL(seq_path);
2165
2166 static void *single_start(struct seq_file *p, loff_t *pos)
2167 {
2168         return (void *) (INT_PTR) (*pos == 0);
2169 }
2170
2171 static void *single_next(struct seq_file *p, void *v, loff_t *pos)
2172 {
2173         ++*pos;
2174         return NULL;
2175 }
2176
2177 static void single_stop(struct seq_file *p, void *v)
2178 {
2179 }
2180
2181 int single_open(struct file *file, int (*show)(struct seq_file *, void *),
2182                 void *data)
2183 {
2184         struct seq_operations *op = kmalloc(sizeof(*op), GFP_KERNEL);
2185         int res = -ENOMEM;
2186
2187         if (op) {
2188                 op->start = single_start;
2189                 op->next = single_next;
2190                 op->stop = single_stop;
2191                 op->show = show;
2192                 res = seq_open(file, op);
2193                 if (!res)
2194                         ((struct seq_file *)file->private_data)->private = data;
2195                 else
2196                         kfree(op);
2197         }
2198         return res;
2199 }
2200 EXPORT_SYMBOL(single_open);
2201
2202 int single_release(struct inode *inode, struct file *file)
2203 {
2204         const struct seq_operations *op = ((struct seq_file *)file->private_data)->op;
2205         int res = seq_release(inode, file);
2206         kfree((void *)op);
2207         return res;
2208 }
2209 EXPORT_SYMBOL(single_release);
2210
2211 int seq_release_private(struct inode *inode, struct file *file)
2212 {
2213         struct seq_file *seq = file->private_data;
2214
2215         kfree(seq->private);
2216         seq->private = NULL;
2217         return seq_release(inode, file);
2218 }
2219 EXPORT_SYMBOL(seq_release_private);
2220
2221 void *__seq_open_private(struct file *f, const struct seq_operations *ops,
2222                 int psize)
2223 {
2224         int rc;
2225         void *private;
2226         struct seq_file *seq;
2227
2228         private = kmalloc(psize, GFP_KERNEL | __GFP_ZERO);
2229         if (private == NULL)
2230                 goto out;
2231
2232         rc = seq_open(f, ops);
2233         if (rc < 0)
2234                 goto out_free;
2235
2236         seq = f->private_data;
2237         seq->private = private;
2238         return private;
2239
2240 out_free:
2241         kfree(private);
2242 out:
2243         return NULL;
2244 }
2245 EXPORT_SYMBOL(__seq_open_private);
2246
2247 int seq_open_private(struct file *filp, const struct seq_operations *ops,
2248                 int psize)
2249 {
2250         return __seq_open_private(filp, ops, psize) ? 0 : -ENOMEM;
2251 }
2252 EXPORT_SYMBOL(seq_open_private);
2253
2254 int seq_putc(struct seq_file *m, char c)
2255 {
2256         if (m->count < m->size) {
2257                 m->buf[m->count++] = c;
2258                 return 0;
2259         }
2260         return -1;
2261 }
2262 EXPORT_SYMBOL(seq_putc);
2263
2264 int seq_puts(struct seq_file *m, const char *s)
2265 {
2266         int len = strlen(s);
2267         if (m->count + len < m->size) {
2268                 memcpy(m->buf + m->count, s, len);
2269                 m->count += len;
2270                 return 0;
2271         }
2272         m->count = m->size;
2273         return -1;
2274 }
2275 EXPORT_SYMBOL(seq_puts);
2276
2277 cfs_list_t *seq_list_start(cfs_list_t *head, loff_t pos)
2278 {
2279         cfs_list_t *lh;
2280
2281         cfs_list_for_each(lh, head)
2282                 if (pos-- == 0)
2283                         return lh;
2284
2285         return NULL;
2286 }
2287
2288 EXPORT_SYMBOL(seq_list_start);
2289
2290 cfs_list_t *seq_list_start_head(cfs_list_t *head,
2291                                 loff_t pos)
2292 {
2293         if (!pos)
2294                 return head;
2295
2296         return seq_list_start(head, pos - 1);
2297 }
2298
2299 EXPORT_SYMBOL(seq_list_start_head);
2300
2301 cfs_list_t *seq_list_next(void *v, cfs_list_t *head,
2302                           loff_t *ppos)
2303 {
2304         cfs_list_t *lh;
2305
2306         lh = ((cfs_list_t *)v)->next;
2307         ++*ppos;
2308         return lh == head ? NULL : lh;
2309 }
2310
2311 EXPORT_SYMBOL(seq_list_next);
2312
2313 struct proc_dir_entry *PDE(const struct inode *inode)
2314 {
2315         return (struct proc_dir_entry *)inode->i_priv;
2316 }
2317
2318
2319 #endif /* __KERNEL__ */