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