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