Whamcloud - gitweb
LU-3963 cleanup: C89 and build cleanups
[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 struct ctl_table_header       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()           mutex_lock(&proc_fs_lock)
87 #define UNLOCK_PROCFS()         mutex_unlock(&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     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(struct ctl_table * 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(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(struct ctl_table * 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 (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(struct ctl_table *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(struct ctl_table *table, int write,
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     return 0;
1166 }
1167
1168 /**
1169  * proc_dointvec - read a vector of integers
1170  * @table: the sysctl table
1171  * @write: %TRUE if this is a write to the sysctl file
1172  * @buffer: the user buffer
1173  * @lenp: the size of the user buffer
1174  *
1175  * Reads/writes up to table->maxlen/sizeof(unsigned int) integer
1176  * values from/to the user buffer, treated as an ASCII string. 
1177  *
1178  * Returns 0 on success.
1179  */
1180 int proc_dointvec(struct ctl_table *table, int write,
1181              void *buffer, size_t *lenp)
1182 {
1183     return do_proc_dointvec(table,write,buffer,lenp,1,OP_SET);
1184 }
1185
1186
1187 /**
1188  * proc_dostring - read a string sysctl
1189  * @table: the sysctl table
1190  * @write: %TRUE if this is a write to the sysctl file
1191  * @buffer: the user buffer
1192  * @lenp: the size of the user buffer
1193  *
1194  * Reads/writes a string from/to the user buffer. If the kernel
1195  * buffer provided is not large enough to hold the string, the
1196  * string is truncated. The copied string is %NULL-terminated.
1197  * If the string is being read by the user process, it is copied
1198  * and a newline '\n' is added. It is truncated if the buffer is
1199  * not large enough.
1200  *
1201  * Returns 0 on success.
1202  */
1203 int proc_dostring(struct ctl_table *table, int write,
1204           void *buffer, size_t *lenp)
1205 {
1206     size_t len;
1207     char *p, c;
1208     
1209     if (!table->data || !table->maxlen || !*lenp ||
1210         (!write)) {
1211         *lenp = 0;
1212         return 0;
1213     }
1214     
1215     if (write) {
1216         len = 0;
1217         p = buffer;
1218         while (len < *lenp) {
1219             if (get_user(c, p++))
1220                 return -EFAULT;
1221             if (c == 0 || c == '\n')
1222                 break;
1223             len++;
1224         }
1225         if (len >= (size_t)table->maxlen)
1226             len = (size_t)table->maxlen-1;
1227         if (copy_from_user(table->data, buffer, len))
1228             return -EFAULT;
1229         ((char *) table->data)[len] = 0;
1230     } else {
1231         len = (size_t)strlen(table->data);
1232         if (len > (size_t)table->maxlen)
1233             len = (size_t)table->maxlen;
1234         if (len > *lenp)
1235             len = *lenp;
1236         if (len)
1237             if (copy_to_user(buffer, table->data, len))
1238                 return -EFAULT;
1239         if (len < *lenp) {
1240             if (put_user('\n', ((char *) buffer) + len))
1241                 return -EFAULT;
1242             len++;
1243         }
1244         *lenp = len;
1245     }
1246     return 0;
1247 }
1248
1249 /* Perform the actual read/write of a sysctl table entry. */
1250 int do_sysctl_strategy(struct ctl_table *table, int *name, int nlen,
1251                        void *oldval, size_t *oldlenp, void *newval,
1252                        size_t newlen, void **context)
1253 {
1254     int op = 0, rc;
1255     size_t len;
1256
1257     if (oldval)
1258         op |= 004;
1259     if (newval) 
1260         op |= 002;
1261
1262     if (table->strategy) {
1263         rc = table->strategy(table, name, nlen, oldval, oldlenp,
1264                      newval, newlen, context);
1265         if (rc < 0)
1266             return rc;
1267         if (rc > 0)
1268             return 0;
1269     }
1270
1271     /* If there is no strategy routine, or if the strategy returns
1272      * zero, proceed with automatic r/w */
1273     if (table->data && table->maxlen) {
1274         if (oldval && oldlenp) {
1275             get_user(len, oldlenp);
1276             if (len) {
1277                 if (len > (size_t)table->maxlen)
1278                     len = (size_t)table->maxlen;
1279                 if (copy_to_user(oldval, table->data, len))
1280                     return -EFAULT;
1281                 if (put_user(len, oldlenp))
1282                     return -EFAULT;
1283             }
1284         }
1285         if (newval && newlen) {
1286             len = newlen;
1287             if (len > (size_t)table->maxlen)
1288                 len = (size_t)table->maxlen;
1289             if (copy_from_user(table->data, newval, len))
1290                 return -EFAULT;
1291         }
1292     }
1293     return 0;
1294 }
1295
1296 static int parse_table(int *name, int nlen,
1297                void *oldval, size_t *oldlenp,
1298                void *newval, size_t newlen,
1299                struct ctl_table *table, void **context)
1300 {
1301     int n;
1302
1303 repeat:
1304
1305     if (!nlen)
1306         return -ENOTDIR;
1307     if (get_user(n, name))
1308         return -EFAULT;
1309     for ( ; table->ctl_name; table++) {
1310         if (n == table->ctl_name || table->ctl_name == CTL_ANY) {
1311             int error;
1312             if (table->child) {
1313 /*
1314                 if (ctl_perm(table, 001))
1315                     return -EPERM;
1316 */
1317                 if (table->strategy) {
1318                     error = table->strategy(
1319                         table, name, nlen,
1320                         oldval, oldlenp,
1321                         newval, newlen, context);
1322                     if (error)
1323                         return error;
1324                 }
1325                 name++;
1326                 nlen--;
1327                 table = table->child;
1328                 goto repeat;
1329             }
1330             error = do_sysctl_strategy(table, name, nlen,
1331                            oldval, oldlenp,
1332                            newval, newlen, context);
1333             return error;
1334         }
1335     }
1336     return -ENOTDIR;
1337 }
1338
1339 int do_sysctl(int *name, int nlen, void *oldval, size_t *oldlenp,
1340            void *newval, size_t newlen)
1341 {
1342     struct list_head *tmp;
1343
1344     if (nlen <= 0 || nlen >= CTL_MAXNAME)
1345         return -ENOTDIR;
1346     if (oldval) {
1347         int old_len;
1348         if (!oldlenp || get_user(old_len, oldlenp))
1349             return -EFAULT;
1350     }
1351     tmp = &root_table_header.ctl_entry;
1352     do {
1353         struct ctl_table_header *head =
1354             list_entry(tmp, struct ctl_table_header, ctl_entry);
1355         void *context = NULL;
1356         int error = parse_table(name, nlen, oldval, oldlenp, 
1357                     newval, newlen, head->ctl_table,
1358                     &context);
1359         if (context)
1360             kfree(context);
1361         if (error != -ENOTDIR)
1362             return error;
1363         tmp = tmp->next;
1364     } while (tmp != &root_table_header.ctl_entry);
1365     return -ENOTDIR;
1366 }
1367
1368 /**
1369  * register_sysctl_table - register a sysctl heirarchy
1370  * @table: the top-level table structure
1371  * @insert_at_head: whether the entry should be inserted in front or at the end
1372  *
1373  * Register a sysctl table heirarchy. @table should be a filled in ctl_table
1374  * array. An entry with a ctl_name of 0 terminates the table. 
1375  *
1376  * The members of the &ctl_table structure are used as follows:
1377  *
1378  * ctl_name - This is the numeric sysctl value used by sysctl(2). The number
1379  *            must be unique within that level of sysctl
1380  *
1381  * procname - the name of the sysctl file under /proc/sys. Set to %NULL to not
1382  *            enter a sysctl file
1383  *
1384  * data - a pointer to data for use by proc_handler
1385  *
1386  * maxlen - the maximum size in bytes of the data
1387  *
1388  * mode - the file permissions for the /proc/sys file, and for sysctl(2)
1389  *
1390  * child - a pointer to the child sysctl table if this entry is a directory, or
1391  *         %NULL.
1392  *
1393  * proc_handler - the text handler routine (described below)
1394  *
1395  * strategy - the strategy routine (described below)
1396  *
1397  * de - for internal use by the sysctl routines
1398  *
1399  * extra1, extra2 - extra pointers usable by the proc handler routines
1400  *
1401  * Leaf nodes in the sysctl tree will be represented by a single file
1402  * under /proc; non-leaf nodes will be represented by directories.
1403  *
1404  * sysctl(2) can automatically manage read and write requests through
1405  * the sysctl table.  The data and maxlen fields of the ctl_table
1406  * struct enable minimal validation of the values being written to be
1407  * performed, and the mode field allows minimal authentication.
1408  *
1409  * More sophisticated management can be enabled by the provision of a
1410  * strategy routine with the table entry.  This will be called before
1411  * any automatic read or write of the data is performed.
1412  *
1413  * The strategy routine may return
1414  *
1415  * < 0 - Error occurred (error is passed to user process)
1416  *
1417  * 0   - OK - proceed with automatic read or write.
1418  *
1419  * > 0 - OK - read or write has been done by the strategy routine, so
1420  *       return immediately.
1421  *
1422  * There must be a proc_handler routine for any terminal nodes
1423  * mirrored under /proc/sys (non-terminals are handled by a built-in
1424  * directory handler).  Several default handlers are available to
1425  * cover common cases -
1426  *
1427  * proc_dostring(), proc_dointvec(), proc_dointvec_jiffies(),
1428  * proc_dointvec_minmax(), proc_doulongvec_ms_jiffies_minmax(),
1429  * proc_doulongvec_minmax()
1430  *
1431  * It is the handler's job to read the input buffer from user memory
1432  * and process it. The handler should return 0 on success.
1433  *
1434  * This routine returns %NULL on a failure to register, and a pointer
1435  * to the table header on success.
1436  */
1437 struct ctl_table_header *
1438 register_sysctl_table(struct ctl_table *table)
1439 {
1440         struct ctl_table_header *tmp;
1441         tmp = kmalloc(sizeof(struct ctl_table_header), 0);
1442         if (!tmp)
1443                 return NULL;
1444         tmp->ctl_table = table;
1445
1446         INIT_LIST_HEAD(&tmp->ctl_entry);
1447         list_add_tail(&tmp->ctl_entry, &root_table_header.ctl_entry);
1448 #ifdef CONFIG_PROC_FS
1449         register_proc_table(table, cfs_proc_sys);
1450 #endif
1451         return tmp;
1452 }
1453
1454 /**
1455  * unregister_sysctl_table - unregister a sysctl table heirarchy
1456  * @header: the header returned from register_sysctl_table
1457  *
1458  * Unregisters the sysctl table and all children. proc entries may not
1459  * actually be removed until they are no longer used by anyone.
1460  */
1461 void unregister_sysctl_table(struct ctl_table_header * header)
1462 {
1463     list_del(&header->ctl_entry);
1464 #ifdef CONFIG_PROC_FS
1465     unregister_proc_table(header->ctl_table, cfs_proc_sys);
1466 #endif
1467     kfree(header);
1468 }
1469
1470
1471 int misc_register(struct miscdevice * psdev)
1472 {
1473     cfs_proc_entry_t *  entry;
1474
1475     entry = create_proc_entry (
1476                 (char *)psdev->name,
1477                 S_IFREG,
1478                 cfs_proc_dev
1479             );
1480
1481     if (!entry) {
1482         return -ENOMEM;
1483     }
1484
1485     entry->flags |= CFS_PROC_FLAG_MISCDEV;
1486
1487     entry->proc_fops = psdev->fops;
1488     entry->data = (void *)psdev;
1489
1490     return 0;
1491 }
1492
1493 int misc_deregister(struct miscdevice * psdev)
1494 {
1495     cfs_proc_entry_t *  entry;
1496
1497     entry = search_proc_entry (
1498                 (char *)psdev->name,
1499                 cfs_proc_dev
1500             );
1501
1502     if (entry) {
1503
1504         ASSERT(entry->data == (void *)psdev);
1505         ASSERT(entry->flags & CFS_PROC_FLAG_MISCDEV);
1506
1507         remove_proc_entry(
1508             (char *)psdev->name,
1509             cfs_proc_dev
1510             );
1511     }
1512
1513     return 0;
1514 }
1515
1516 #define PSDEV_LNET  (0x100)
1517 enum {
1518         PSDEV_DEBUG = 1,          /* control debugging */
1519         PSDEV_SUBSYSTEM_DEBUG,    /* control debugging */
1520         PSDEV_PRINTK,             /* force all messages to console */
1521         PSDEV_CONSOLE_RATELIMIT,  /* rate limit console messages */
1522         PSDEV_DEBUG_PATH,         /* crashdump log location */
1523         PSDEV_DEBUG_DUMP_PATH,    /* crashdump tracelog location */
1524         PSDEV_LIBCFS_MEMUSED,     /* bytes currently PORTAL_ALLOCated */
1525 };
1526
1527 static struct ctl_table lnet_table[] = {
1528         {PSDEV_DEBUG, "debug", &libcfs_debug, sizeof(int), 0644, NULL,
1529          &proc_dointvec},
1530         {PSDEV_SUBSYSTEM_DEBUG, "subsystem_debug", &libcfs_subsystem_debug,
1531          sizeof(int), 0644, NULL, &proc_dointvec},
1532         {PSDEV_PRINTK, "printk", &libcfs_printk, sizeof(int), 0644, NULL,
1533          &proc_dointvec},
1534         {PSDEV_CONSOLE_RATELIMIT, "console_ratelimit", &libcfs_console_ratelimit,
1535          sizeof(int), 0644, NULL, &proc_dointvec},
1536 /*
1537         {PSDEV_PORTALS_UPCALL, "upcall", portals_upcall,
1538          sizeof(portals_upcall), 0644, NULL, &proc_dostring,
1539          &sysctl_string},
1540 */
1541         {PSDEV_LIBCFS_MEMUSED, "memused", (int *)&libcfs_kmemory.counter,
1542          sizeof(int), 0644, NULL, &proc_dointvec},
1543         {0}
1544 };
1545
1546 static struct ctl_table top_table[2] = {
1547         {PSDEV_LNET, "lnet", NULL, 0, 0555, lnet_table},
1548         {0}
1549 };
1550
1551
1552 int trace_write_dump_kernel(struct file *file, const char *buffer,
1553                              unsigned long count, void *data)
1554 {
1555         int rc = cfs_trace_dump_debug_buffer_usrstr((void *)buffer, count);
1556         
1557         return (rc < 0) ? rc : count;
1558 }
1559
1560 int trace_write_daemon_file(struct file *file, const char *buffer,
1561                             unsigned long count, void *data)
1562 {
1563         int rc = cfs_trace_daemon_command_usrstr((void *)buffer, count);
1564
1565         return (rc < 0) ? rc : count;
1566 }
1567
1568 int trace_read_daemon_file(char *page, char **start, off_t off, int count,
1569                            int *eof, void *data)
1570 {
1571         int rc;
1572         cfs_tracefile_read_lock();
1573         rc = cfs_trace_copyout_string(page, count, cfs_tracefile, "\n");
1574         cfs_tracefile_read_unlock();
1575         return rc;
1576 }
1577
1578 int trace_write_debug_mb(struct file *file, const char *buffer,
1579                          unsigned long count, void *data)
1580 {
1581         int rc = 0; /*trace_set_debug_mb_userstr((void *)buffer, count);*/
1582         
1583         return (rc < 0) ? rc : count;
1584 }
1585
1586 int trace_read_debug_mb(char *page, char **start, off_t off, int count,
1587                         int *eof, void *data)
1588 {
1589         char   str[32];
1590
1591         snprintf(str, sizeof(str), "%d\n", cfs_trace_get_debug_mb());
1592
1593         return cfs_trace_copyout_string(page, count, str, NULL);
1594 }
1595
1596 int insert_proc(void)
1597 {
1598         cfs_proc_entry_t *ent;
1599
1600         ent = create_proc_entry("sys/lnet/dump_kernel", 0, NULL);
1601         if (ent == NULL) {
1602                 CERROR("couldn't register dump_kernel\n");
1603                 return -1;
1604         }
1605         ent->write_proc = trace_write_dump_kernel;
1606
1607         ent = create_proc_entry("sys/lnet/daemon_file", 0, NULL);
1608         if (ent == NULL) {
1609                 CERROR("couldn't register daemon_file\n");
1610                 return -1;
1611         }
1612         ent->write_proc = trace_write_daemon_file;
1613         ent->read_proc = trace_read_daemon_file;
1614
1615         ent = create_proc_entry("sys/lnet/debug_mb", 0, NULL);
1616         if (ent == NULL) {
1617                 CERROR("couldn't register debug_mb\n");
1618                 return -1;
1619         }
1620         ent->write_proc = trace_write_debug_mb;
1621         ent->read_proc = trace_read_debug_mb;
1622
1623         return 0;
1624 }
1625
1626 void remove_proc(void)
1627 {
1628         remove_proc_entry("sys/lnet/dump_kernel", NULL);
1629         remove_proc_entry("sys/lnet/daemon_file", NULL);
1630         remove_proc_entry("sys/lnet/debug_mb", NULL);
1631 }
1632
1633
1634 /*
1635  *  proc process routines of kernel space
1636  */
1637
1638 struct file *
1639 lustre_open_file(char *filename)
1640 {
1641         int rc = 0;
1642         struct file *fh = NULL;
1643         cfs_proc_entry_t *fp = NULL;
1644
1645         fp = search_proc_entry(filename, cfs_proc_root);
1646         if (fp == NULL)
1647                 return NULL;
1648
1649         fh = kmalloc(sizeof(*fh), __GFP_ZERO);
1650         if (fh == NULL)
1651                 return NULL;
1652
1653     fh->f_inode = kmalloc(sizeof(struct inode), __GFP_ZERO);
1654     if (!fh->f_inode) {
1655         kfree(fh);
1656         return NULL;
1657     }
1658
1659     fh->f_inode->i_priv = (void *)fp;
1660     fh->f_op = fp->proc_fops;
1661
1662     if (fh->f_op->open) {
1663         rc = (fh->f_op->open)(fh->f_inode, fh);
1664     } else {
1665         fp->nlink++;
1666     }
1667
1668     if (0 != rc) {
1669         kfree(fh->f_inode);
1670         kfree(fh);
1671         return NULL;
1672     }
1673
1674     return fh;
1675 }
1676
1677 int
1678 lustre_close_file(struct file *fh)
1679 {
1680         int rc = 0;
1681         cfs_proc_entry_t *fp = NULL;
1682
1683     fp = (cfs_proc_entry_t *) fh->f_inode->i_priv;
1684     if (fh->f_op->release) {
1685         rc = (fh->f_op->release)(fh->f_inode, fh);
1686     } else {
1687         fp->nlink--;
1688     }
1689
1690     kfree(fh->f_inode);
1691     kfree(fh);
1692
1693     return rc;
1694 }
1695
1696 int
1697 lustre_do_ioctl(struct file *fh, unsigned long cmd, ulong_ptr_t arg)
1698 {
1699         int rc = 0;
1700
1701         if (fh->f_op->ioctl)
1702                 rc = (fh->f_op->ioctl)(fh, cmd, arg);
1703
1704         return rc;
1705 }
1706
1707 int
1708 lustre_ioctl_file(struct file *fh, PCFS_PROC_IOCTL devctl)
1709 {
1710     int         rc = 0;
1711     ulong_ptr_t data;
1712
1713     data = (ulong_ptr_t)devctl + sizeof(CFS_PROC_IOCTL);
1714 #if defined(_X86_)    
1715     CLASSERT(sizeof(struct obd_ioctl_data) == 528);
1716 #else
1717     CLASSERT(sizeof(struct obd_ioctl_data) == 576);
1718 #endif
1719
1720     /* obd ioctl code */
1721     if (_IOC_TYPE(devctl->cmd) == 'f') {
1722
1723         struct obd_ioctl_data * obd = (struct obd_ioctl_data *) data;
1724
1725         if ( devctl->cmd != (ULONG)OBD_IOC_BRW_WRITE  &&
1726              devctl->cmd != (ULONG)OBD_IOC_BRW_READ ) {
1727
1728             unsigned long off = obd->ioc_len;
1729
1730             if (obd->ioc_plen1) {
1731                 obd->ioc_pbuf1 = (char *)(data + off);
1732                 off += cfs_size_round(obd->ioc_plen1);
1733             } else {
1734                 obd->ioc_pbuf1 = NULL;
1735             }
1736
1737             if (obd->ioc_plen2) {
1738                 obd->ioc_pbuf2 = (char *)(data + off);
1739                 off += cfs_size_round(obd->ioc_plen2);
1740             } else {
1741                 obd->ioc_pbuf2 = NULL;
1742             }
1743         }
1744     }
1745
1746     rc = lustre_do_ioctl(fh, devctl->cmd, data);
1747
1748     return rc;
1749 }
1750
1751 size_t
1752 lustre_read_file(struct file *fh, loff_t off, size_t size, char *buf)
1753 {
1754     size_t  rc = 0;
1755     off_t   low, high;
1756
1757     low = (off_t) size;
1758     high = (off_t)(off >> 32);
1759
1760     if (fh->f_op->read) {
1761         rc = (fh->f_op->read) (fh, buf, size, &off);
1762     }
1763
1764     if (rc) {
1765         fh->f_pos = off + rc;
1766     }
1767
1768     return rc;
1769 }
1770
1771 size_t
1772 lustre_write_file(struct file *fh, loff_t off, size_t size, char *buf)
1773 {
1774         size_t rc = 0;
1775
1776         off = 0;
1777         if (fh->f_op->write)
1778                 rc = (fh->f_op->write)(fh, buf, size, &off);
1779
1780         return rc;
1781 }
1782
1783
1784 /*
1785  *  seq file routines
1786  */
1787
1788 /**
1789  *      seq_open -      initialize sequential file
1790  *      @file: file we initialize
1791  *      @op: method table describing the sequence
1792  *
1793  *      seq_open() sets @file, associating it with a sequence described
1794  *      by @op.  @op->start() sets the iterator up and returns the first
1795  *      element of sequence. @op->stop() shuts it down.  @op->next()
1796  *      returns the next element of sequence.  @op->show() prints element
1797  *      into the buffer.  In case of error ->start() and ->next() return
1798  *      ERR_PTR(error).  In the end of sequence they return %NULL. ->show()
1799  *      returns 0 in case of success and negative number in case of error.
1800  */
1801 int seq_open(struct file *file, const struct seq_operations *op)
1802 {
1803         struct seq_file *p = file->private_data;
1804
1805         if (!p) {
1806                 p = kmalloc(sizeof(*p), GFP_KERNEL);
1807                 if (!p)
1808                         return -ENOMEM;
1809                 file->private_data = p;
1810         }
1811         memset(p, 0, sizeof(*p));
1812         mutex_init(&p->lock);
1813         p->op = op;
1814
1815         /*
1816          * Wrappers around seq_open(e.g. swaps_open) need to be
1817          * aware of this. If they set f_version themselves, they
1818          * should call seq_open first and then set f_version.
1819          */
1820         file->f_version = 0;
1821
1822         /* SEQ files support lseek, but not pread/pwrite */
1823         file->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE);
1824         return 0;
1825 }
1826 EXPORT_SYMBOL(seq_open);
1827
1828 /**
1829  *      seq_read -      ->read() method for sequential files.
1830  *      @file: the file to read from
1831  *      @buf: the buffer to read to
1832  *      @size: the maximum number of bytes to read
1833  *      @ppos: the current position in the file
1834  *
1835  *      Ready-made ->f_op->read()
1836  */
1837 ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
1838 {
1839         struct seq_file *m = (struct seq_file *)file->private_data;
1840         size_t copied = 0;
1841         loff_t pos;
1842         size_t n;
1843         void *p;
1844         int err = 0;
1845
1846         mutex_lock(&m->lock);
1847         /*
1848          * seq_file->op->..m_start/m_stop/m_next may do special actions
1849          * or optimisations based on the file->f_version, so we want to
1850          * pass the file->f_version to those methods.
1851          *
1852          * seq_file->version is just copy of f_version, and seq_file
1853          * methods can treat it simply as file version.
1854          * It is copied in first and copied out after all operations.
1855          * It is convenient to have it as  part of structure to avoid the
1856          * need of passing another argument to all the seq_file methods.
1857          */
1858         m->version = file->f_version;
1859         /* grab buffer if we didn't have one */
1860         if (!m->buf) {
1861                 m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL);
1862                 if (!m->buf)
1863                         goto Enomem;
1864         }
1865         /* if not empty - flush it first */
1866         if (m->count) {
1867                 n = min(m->count, size);
1868                 err = copy_to_user(buf, m->buf + m->from, n);
1869                 if (err)
1870                         goto Efault;
1871                 m->count -= n;
1872                 m->from += n;
1873                 size -= n;
1874                 buf += n;
1875                 copied += n;
1876                 if (!m->count)
1877                         m->index++;
1878                 if (!size)
1879                         goto Done;
1880         }
1881         /* we need at least one record in buffer */
1882         while (1) {
1883                 pos = m->index;
1884                 p = m->op->start(m, &pos);
1885                 err = PTR_ERR(p);
1886                 if (!p || IS_ERR(p))
1887                         break;
1888                 err = m->op->show(m, p);
1889                 if (err)
1890                         break;
1891                 if (m->count < m->size)
1892                         goto Fill;
1893                 m->op->stop(m, p);
1894                 kfree(m->buf);
1895                 m->buf = kmalloc(m->size <<= 1, GFP_KERNEL);
1896                 if (!m->buf)
1897                         goto Enomem;
1898                 m->count = 0;
1899                 m->version = 0;
1900         }
1901         m->op->stop(m, p);
1902         m->count = 0;
1903         goto Done;
1904 Fill:
1905         /* they want more? let's try to get some more */
1906         while (m->count < size) {
1907                 size_t offs = m->count;
1908                 loff_t next = pos;
1909                 p = m->op->next(m, p, &next);
1910                 if (!p || IS_ERR(p)) {
1911                         err = PTR_ERR(p);
1912                         break;
1913                 }
1914                 err = m->op->show(m, p);
1915                 if (err || m->count == m->size) {
1916                         m->count = offs;
1917                         break;
1918                 }
1919                 pos = next;
1920         }
1921         m->op->stop(m, p);
1922         n = min(m->count, size);
1923         err = copy_to_user(buf, m->buf, n);
1924         if (err)
1925                 goto Efault;
1926         copied += n;
1927         m->count -= n;
1928         if (m->count)
1929                 m->from = n;
1930         else
1931                 pos++;
1932         m->index = pos;
1933 Done:
1934         if (!copied)
1935                 copied = err;
1936         else
1937                 *ppos += copied;
1938         file->f_version = m->version;
1939         mutex_unlock(&m->lock);
1940         return copied;
1941 Enomem:
1942         err = -ENOMEM;
1943         goto Done;
1944 Efault:
1945         err = -EFAULT;
1946         goto Done;
1947 }
1948 EXPORT_SYMBOL(seq_read);
1949
1950 static int traverse(struct seq_file *m, loff_t offset)
1951 {
1952         loff_t pos = 0, index;
1953         int error = 0;
1954         void *p;
1955
1956         m->version = 0;
1957         index = 0;
1958         m->count = m->from = 0;
1959         if (!offset) {
1960                 m->index = index;
1961                 return 0;
1962         }
1963         if (!m->buf) {
1964                 m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL);
1965                 if (!m->buf)
1966                         return -ENOMEM;
1967         }
1968         p = m->op->start(m, &index);
1969         while (p) {
1970                 error = PTR_ERR(p);
1971                 if (IS_ERR(p))
1972                         break;
1973                 error = m->op->show(m, p);
1974                 if (error)
1975                         break;
1976                 if (m->count == m->size)
1977                         goto Eoverflow;
1978                 if (pos + (loff_t)(m->count) > offset) {
1979                         m->from = (size_t)(offset - pos);
1980                         m->count -= m->from;
1981                         m->index = index;
1982                         break;
1983                 }
1984                 pos += m->count;
1985                 m->count = 0;
1986                 if (pos == offset) {
1987                         index++;
1988                         m->index = index;
1989                         break;
1990                 }
1991                 p = m->op->next(m, p, &index);
1992         }
1993         m->op->stop(m, p);
1994         return error;
1995
1996 Eoverflow:
1997         m->op->stop(m, p);
1998         kfree(m->buf);
1999         m->buf = kmalloc(m->size <<= 1, GFP_KERNEL | __GFP_ZERO);
2000         return !m->buf ? -ENOMEM : -EAGAIN;
2001 }
2002
2003 /**
2004  *      seq_lseek -     ->llseek() method for sequential files.
2005  *      @file: the file in question
2006  *      @offset: new position
2007  *      @origin: 0 for absolute, 1 for relative position
2008  *
2009  *      Ready-made ->f_op->llseek()
2010  */
2011 loff_t seq_lseek(struct file *file, loff_t offset, int origin)
2012 {
2013         struct seq_file *m = (struct seq_file *)file->private_data;
2014         long long retval = -EINVAL;
2015
2016         mutex_lock(&m->lock);
2017         m->version = file->f_version;
2018         switch (origin) {
2019                 case 1:
2020                         offset += file->f_pos;
2021                 case 0:
2022                         if (offset < 0)
2023                                 break;
2024                         retval = offset;
2025                         if (offset != file->f_pos) {
2026                                 while ((retval=traverse(m, offset)) == -EAGAIN)
2027                                         ;
2028                                 if (retval) {
2029                                         /* with extreme prejudice... */
2030                                         file->f_pos = 0;
2031                                         m->version = 0;
2032                                         m->index = 0;
2033                                         m->count = 0;
2034                                 } else {
2035                                         retval = file->f_pos = offset;
2036                                 }
2037                         }
2038         }
2039         file->f_version = m->version;
2040         mutex_unlock(&m->lock);
2041         return retval;
2042 }
2043 EXPORT_SYMBOL(seq_lseek);
2044
2045 /**
2046  *      seq_release -   free the structures associated with sequential file.
2047  *      @file: file in question
2048  *      @inode: file->f_path.dentry->d_inode
2049  *
2050  *      Frees the structures associated with sequential file; can be used
2051  *      as ->f_op->release() if you don't have private data to destroy.
2052  */
2053 int seq_release(struct inode *inode, struct file *file)
2054 {
2055         struct seq_file *m = (struct seq_file *)file->private_data;
2056     if (m) {
2057         if (m->buf)
2058                 kfree(m->buf);
2059             kfree(m);
2060     }
2061         return 0;
2062 }
2063 EXPORT_SYMBOL(seq_release);
2064
2065 /**
2066  *      seq_escape -    print string into buffer, escaping some characters
2067  *      @m:     target buffer
2068  *      @s:     string
2069  *      @esc:   set of characters that need escaping
2070  *
2071  *      Puts string into buffer, replacing each occurrence of character from
2072  *      @esc with usual octal escape.  Returns 0 in case of success, -1 - in
2073  *      case of overflow.
2074  */
2075 int seq_escape(struct seq_file *m, const char *s, const char *esc)
2076 {
2077         char *end = m->buf + m->size;
2078         char *p;
2079         char c;
2080
2081         for (p = m->buf + m->count; (c = *s) != '\0' && p < end; s++) {
2082                 if (!strchr(esc, c)) {
2083                         *p++ = c;
2084                         continue;
2085                 }
2086                 if (p + 3 < end) {
2087                         *p++ = '\\';
2088                         *p++ = '0' + ((c & 0300) >> 6);
2089                         *p++ = '0' + ((c & 070) >> 3);
2090                         *p++ = '0' + (c & 07);
2091                         continue;
2092                 }
2093                 m->count = m->size;
2094                 return -1;
2095         }
2096         m->count = p - m->buf;
2097         return 0;
2098 }
2099 EXPORT_SYMBOL(seq_escape);
2100
2101 int seq_printf(struct seq_file *m, const char *f, ...)
2102 {
2103         va_list args;
2104         int len;
2105
2106         if (m->count < m->size) {
2107                 va_start(args, f);
2108                 len = vsnprintf(m->buf + m->count, m->size - m->count, f, args);
2109                 va_end(args);
2110                 if (m->count + len < m->size) {
2111                         m->count += len;
2112                         return 0;
2113                 }
2114         }
2115         m->count = m->size;
2116         return -1;
2117 }
2118 EXPORT_SYMBOL(seq_printf);
2119
2120 char *d_path(struct path *p, char *buffer, int buflen)
2121 {
2122         cfs_enter_debugger();
2123         return ERR_PTR(-ENAMETOOLONG);
2124 }
2125
2126 int seq_path(struct seq_file *m, struct path *path, char *esc)
2127 {
2128         if (m->count < m->size) {
2129                 char *s = m->buf + m->count;
2130                 char *p = d_path(path, s, m->size - m->count);
2131                 if (!IS_ERR(p)) {
2132                         while (s <= p) {
2133                                 char c = *p++;
2134                                 if (!c) {
2135                                         p = m->buf + m->count;
2136                                         m->count = s - m->buf;
2137                                         return (int)(s - p);
2138                                 } else if (!strchr(esc, c)) {
2139                                         *s++ = c;
2140                                 } else if (s + 4 > p) {
2141                                         break;
2142                                 } else {
2143                                         *s++ = '\\';
2144                                         *s++ = '0' + ((c & 0300) >> 6);
2145                                         *s++ = '0' + ((c & 070) >> 3);
2146                                         *s++ = '0' + (c & 07);
2147                                 }
2148                         }
2149                 }
2150         }
2151         m->count = m->size;
2152         return -1;
2153 }
2154 EXPORT_SYMBOL(seq_path);
2155
2156 static void *single_start(struct seq_file *p, loff_t *pos)
2157 {
2158         return (void *) (INT_PTR) (*pos == 0);
2159 }
2160
2161 static void *single_next(struct seq_file *p, void *v, loff_t *pos)
2162 {
2163         ++*pos;
2164         return NULL;
2165 }
2166
2167 static void single_stop(struct seq_file *p, void *v)
2168 {
2169 }
2170
2171 int single_open(struct file *file, int (*show)(struct seq_file *, void *),
2172                 void *data)
2173 {
2174         struct seq_operations *op = kmalloc(sizeof(*op), GFP_KERNEL);
2175         int res = -ENOMEM;
2176
2177         if (op) {
2178                 op->start = single_start;
2179                 op->next = single_next;
2180                 op->stop = single_stop;
2181                 op->show = show;
2182                 res = seq_open(file, op);
2183                 if (!res)
2184                         ((struct seq_file *)file->private_data)->private = data;
2185                 else
2186                         kfree(op);
2187         }
2188         return res;
2189 }
2190 EXPORT_SYMBOL(single_open);
2191
2192 int single_release(struct inode *inode, struct file *file)
2193 {
2194         const struct seq_operations *op = ((struct seq_file *)file->private_data)->op;
2195         int res = seq_release(inode, file);
2196         kfree((void *)op);
2197         return res;
2198 }
2199 EXPORT_SYMBOL(single_release);
2200
2201 int seq_release_private(struct inode *inode, struct file *file)
2202 {
2203         struct seq_file *seq = file->private_data;
2204
2205         kfree(seq->private);
2206         seq->private = NULL;
2207         return seq_release(inode, file);
2208 }
2209 EXPORT_SYMBOL(seq_release_private);
2210
2211 void *__seq_open_private(struct file *f, const struct seq_operations *ops,
2212                 int psize)
2213 {
2214         int rc;
2215         void *private;
2216         struct seq_file *seq;
2217
2218         private = kmalloc(psize, GFP_KERNEL | __GFP_ZERO);
2219         if (private == NULL)
2220                 goto out;
2221
2222         rc = seq_open(f, ops);
2223         if (rc < 0)
2224                 goto out_free;
2225
2226         seq = f->private_data;
2227         seq->private = private;
2228         return private;
2229
2230 out_free:
2231         kfree(private);
2232 out:
2233         return NULL;
2234 }
2235 EXPORT_SYMBOL(__seq_open_private);
2236
2237 int seq_open_private(struct file *filp, const struct seq_operations *ops,
2238                 int psize)
2239 {
2240         return __seq_open_private(filp, ops, psize) ? 0 : -ENOMEM;
2241 }
2242 EXPORT_SYMBOL(seq_open_private);
2243
2244 int seq_putc(struct seq_file *m, char c)
2245 {
2246         if (m->count < m->size) {
2247                 m->buf[m->count++] = c;
2248                 return 0;
2249         }
2250         return -1;
2251 }
2252 EXPORT_SYMBOL(seq_putc);
2253
2254 int seq_puts(struct seq_file *m, const char *s)
2255 {
2256         int len = strlen(s);
2257         if (m->count + len < m->size) {
2258                 memcpy(m->buf + m->count, s, len);
2259                 m->count += len;
2260                 return 0;
2261         }
2262         m->count = m->size;
2263         return -1;
2264 }
2265 EXPORT_SYMBOL(seq_puts);
2266
2267 struct list_head *seq_list_start(struct list_head *head, loff_t pos)
2268 {
2269         struct list_head *lh;
2270
2271         list_for_each(lh, head)
2272                 if (pos-- == 0)
2273                         return lh;
2274
2275         return NULL;
2276 }
2277
2278 EXPORT_SYMBOL(seq_list_start);
2279
2280 struct list_head *seq_list_start_head(struct list_head *head,
2281                                 loff_t pos)
2282 {
2283         if (!pos)
2284                 return head;
2285
2286         return seq_list_start(head, pos - 1);
2287 }
2288
2289 EXPORT_SYMBOL(seq_list_start_head);
2290
2291 struct list_head *seq_list_next(void *v, struct list_head *head,
2292                           loff_t *ppos)
2293 {
2294         struct list_head *lh;
2295
2296         lh = ((struct list_head *)v)->next;
2297         ++*ppos;
2298         return lh == head ? NULL : lh;
2299 }
2300
2301 EXPORT_SYMBOL(seq_list_next);
2302
2303 struct proc_dir_entry *PDE(const struct inode *inode)
2304 {
2305         return (struct proc_dir_entry *)inode->i_priv;
2306 }
2307
2308
2309 #endif /* __KERNEL__ */