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