Whamcloud - gitweb
a9585197af9c4952fb8f24968da397a7df906ba2
[fs/lustre-release.git] / libcfs / libcfs / winnt / winnt-proc.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * GPL HEADER START
5  *
6  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 only,
10  * as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License version 2 for more details (a copy is included
16  * in the LICENSE file that accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License
19  * version 2 along with this program; If not, see [sun.com URL with a
20  * copy of GPLv2].
21  *
22  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23  * CA 95054 USA or visit www.sun.com if you need additional information or
24  * have any questions.
25  *
26  * GPL HEADER END
27  */
28 /*
29  * Copyright  2008 Sun Microsystems, Inc. All rights reserved
30  * Use is subject to license terms.
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
38 #ifndef EXPORT_SYMTAB
39 # define EXPORT_SYMTAB
40 #endif
41
42 # define DEBUG_SUBSYSTEM S_LNET
43
44 #include <libcfs/libcfs.h>
45 #include "tracefile.h"
46
47 #ifdef __KERNEL__
48
49
50 /*
51  *  /proc emulator routines ...
52  */
53
54 /* The root node of the proc fs emulation: /proc */
55 cfs_proc_entry_t *              proc_fs_root = NULL;
56
57
58 /* The sys root: /proc/sys */
59 cfs_proc_entry_t *              proc_sys_root = NULL;
60
61
62 /* The sys root: /proc/dev | to implement misc device */
63
64 cfs_proc_entry_t *              proc_dev_root = NULL;
65
66
67 /* SLAB object for cfs_proc_entry_t allocation */
68
69 cfs_mem_cache_t *               proc_entry_cache = NULL;
70
71 /* root node for sysctl table */
72
73 cfs_sysctl_table_header_t       root_table_header;
74
75 /* The global lock to protect all the access */
76
77 #if LIBCFS_PROCFS_SPINLOCK
78 spinlock_t                      proc_fs_lock;
79
80 #define INIT_PROCFS_LOCK()      spin_lock_init(&proc_fs_lock)
81 #define LOCK_PROCFS()           spin_lock(&proc_fs_lock)
82 #define UNLOCK_PROCFS()         spin_unlock(&proc_fs_lock)
83
84 #else
85
86 mutex_t                         proc_fs_lock;
87
88 #define INIT_PROCFS_LOCK()      init_mutex(&proc_fs_lock)
89 #define LOCK_PROCFS()           mutex_down(&proc_fs_lock)
90 #define UNLOCK_PROCFS()         mutex_up(&proc_fs_lock)
91
92 #endif
93
94 static ssize_t
95 proc_file_read(struct file * file, const char * buf, size_t nbytes, loff_t *ppos)
96 {
97     char    *page;
98     ssize_t retval=0;
99     int eof=0;
100     ssize_t n, count;
101     char    *start;
102     cfs_proc_entry_t * dp;
103
104     dp = (cfs_proc_entry_t  *) file->private_data;
105     if (!(page = (char*) cfs_alloc(CFS_PAGE_SIZE, 0)))
106         return -ENOMEM;
107
108     while ((nbytes > 0) && !eof) {
109
110         count = min_t(size_t, PROC_BLOCK_SIZE, nbytes);
111
112         start = NULL;
113         if (dp->read_proc) {
114             n = dp->read_proc( page, &start, (long)*ppos,
115                                count, &eof, dp->data);
116         } else
117             break;
118
119         if (!start) {
120             /*
121              * For proc files that are less than 4k
122              */
123             start = page + *ppos;
124             n -= (ssize_t)(*ppos);
125             if (n <= 0)
126                 break;
127             if (n > count)
128                 n = count;
129         }
130         if (n == 0)
131             break;  /* End of file */
132         if (n < 0) {
133             if (retval == 0)
134                 retval = n;
135             break;
136         }
137         
138         n -= copy_to_user((void *)buf, start, n);
139         if (n == 0) {
140             if (retval == 0)
141                 retval = -EFAULT;
142             break;
143         }
144
145         *ppos += n;
146         nbytes -= n;
147         buf += n;
148         retval += n;
149     }
150     cfs_free(page);
151
152     return retval;
153 }
154
155 static ssize_t
156 proc_file_write(struct file * file, const char * buffer,
157                 size_t count, loff_t *ppos)
158 {
159     cfs_proc_entry_t  * dp;
160     
161     dp = (cfs_proc_entry_t *) file->private_data;
162
163     if (!dp->write_proc)
164         return -EIO;
165
166     /* FIXME: does this routine need ppos?  probably... */
167     return dp->write_proc(file, buffer, count, dp->data);
168 }
169
170 struct file_operations proc_file_operations = {
171     /*lseek:*/      NULL, //proc_file_lseek,
172     /*read:*/       proc_file_read,
173     /*write:*/      proc_file_write,
174     /*ioctl:*/      NULL,
175     /*open:*/       NULL,
176     /*release:*/    NULL
177 };
178
179 /* allocate proc entry block */
180
181 cfs_proc_entry_t *
182 proc_alloc_entry()
183 {
184     cfs_proc_entry_t * entry = NULL;
185
186     entry = cfs_mem_cache_alloc(proc_entry_cache, 0);
187     if (!entry) {
188         return NULL;
189     }
190
191     memset(entry, 0, sizeof(cfs_proc_entry_t));
192
193     entry->magic = CFS_PROC_ENTRY_MAGIC;
194     RtlInitializeSplayLinks(&(entry->s_link));
195     entry->proc_fops = &proc_file_operations;
196
197     return entry;
198 }
199
200 /* free the proc entry block */
201
202 void
203 proc_free_entry(cfs_proc_entry_t * entry)
204
205 {
206     ASSERT(entry->magic == CFS_PROC_ENTRY_MAGIC);
207
208     cfs_mem_cache_free(proc_entry_cache, entry);
209 }
210
211 /* dissect the path string for a given full proc path */
212
213 void
214 proc_dissect_name(
215     char *path,
216     char **first,
217     int  *first_len,
218     char **remain
219     )
220 {
221     int i = 0, j = 0, len = 0;
222
223     *first = *remain = NULL;
224     *first_len = 0;
225
226     len = strlen(path);
227
228     while (i < len && (path[i] == '/')) i++;
229
230     if (i < len) {
231
232         *first = path + i;
233         while (i < len && (path[i] != '/')) i++;
234         *first_len = (path + i - *first);
235
236         if (i + 1 < len) {
237             *remain = path + i + 1;
238         }
239     }
240 }
241
242 /* search the children entries of the parent entry */
243
244 cfs_proc_entry_t *
245 proc_search_splay (
246     cfs_proc_entry_t *  parent,
247     char *              name
248     )
249 {
250     cfs_proc_entry_t *  node;
251     PRTL_SPLAY_LINKS    link;
252
253     ASSERT(parent->magic == CFS_PROC_ENTRY_MAGIC);
254     ASSERT(cfs_is_flag_set(parent->flags, CFS_PROC_FLAG_DIRECTORY));
255
256     link = parent->root;
257
258     while (link) {
259
260         ANSI_STRING ename,nname;
261         long        result;
262
263         node = CONTAINING_RECORD(link, cfs_proc_entry_t, s_link);
264
265         ASSERT(node->magic == CFS_PROC_ENTRY_MAGIC);
266
267         /*  Compare the prefix in the tree with the full name */
268
269         RtlInitAnsiString(&ename, name);
270         RtlInitAnsiString(&nname, node->name);
271
272         result = RtlCompareString(&nname, &ename,TRUE);
273
274         if (result > 0) {
275
276             /*  The prefix is greater than the full name
277                 so we go down the left child          */
278
279             link = RtlLeftChild(link);
280
281         } else if (result < 0) {
282
283             /*  The prefix is less than the full name
284                 so we go down the right child      */
285             //
286
287             link = RtlRightChild(link);
288
289         } else {
290
291             /*  We got the entry in the splay tree and
292                 make it root node instead           */
293
294             parent->root = RtlSplay(link);
295
296             return node;
297         }
298
299         /* we need continue searching down the tree ... */
300     }
301
302     /*  There's no the exptected entry in the splay tree */
303
304     return NULL;
305 }
306
307 int
308 proc_insert_splay (
309     cfs_proc_entry_t * parent,
310     cfs_proc_entry_t * child
311     )
312 {
313     cfs_proc_entry_t * entry;
314
315     ASSERT(parent != NULL && child != NULL);
316     ASSERT(parent->magic == CFS_PROC_ENTRY_MAGIC);
317     ASSERT(child->magic == CFS_PROC_ENTRY_MAGIC);
318     ASSERT(cfs_is_flag_set(parent->flags, CFS_PROC_FLAG_DIRECTORY));
319
320     if (!parent->root) {
321         parent->root = &(child->s_link);
322     } else {
323         entry = CONTAINING_RECORD(parent->root, cfs_proc_entry_t, s_link);
324         while (TRUE) {
325             long        result;
326             ANSI_STRING ename, cname;
327
328             ASSERT(entry->magic == CFS_PROC_ENTRY_MAGIC);
329
330             RtlInitAnsiString(&ename, entry->name);
331             RtlInitAnsiString(&cname, child->name);
332
333             result = RtlCompareString(&ename, &cname,TRUE);
334
335             if (result == 0) {
336                 cfs_enter_debugger();
337                 if (entry == child) {
338                     break;
339                 }
340                 return FALSE;
341             }
342
343             if (result > 0) {
344                 if (RtlLeftChild(&entry->s_link) == NULL) {
345                     RtlInsertAsLeftChild(&entry->s_link, &child->s_link);
346                     break;
347                 } else {
348                     entry = CONTAINING_RECORD( RtlLeftChild(&entry->s_link),
349                                                cfs_proc_entry_t, s_link);
350                 }
351             } else {
352                 if (RtlRightChild(&entry->s_link) == NULL) {
353                     RtlInsertAsRightChild(&entry->s_link, &child->s_link);
354                     break;
355                 } else {
356                     entry = CONTAINING_RECORD( RtlRightChild(&entry->s_link),
357                                                cfs_proc_entry_t, s_link );
358                 }
359             }
360         }
361     }
362
363     cfs_set_flag(child->flags, CFS_PROC_FLAG_ATTACHED);
364     parent->nlink++;
365
366     return TRUE;
367 }
368
369
370 /* remove a child entry from the splay tree */
371 int
372 proc_remove_splay (
373     cfs_proc_entry_t *  parent,
374     cfs_proc_entry_t *  child
375     )
376 {
377     cfs_proc_entry_t * entry = NULL;
378
379     ASSERT(parent != NULL && child != NULL);
380     ASSERT(parent->magic == CFS_PROC_ENTRY_MAGIC);
381     ASSERT(child->magic == CFS_PROC_ENTRY_MAGIC);
382     ASSERT(cfs_is_flag_set(parent->flags, CFS_PROC_FLAG_DIRECTORY));
383     ASSERT(cfs_is_flag_set(child->flags, CFS_PROC_FLAG_ATTACHED));
384
385     entry = proc_search_splay(parent, child->name);
386
387     if (entry) {
388         ASSERT(entry == child);
389         parent->root = RtlDelete(&(entry->s_link));
390         parent->nlink--;
391     } else {
392         cfs_enter_debugger();
393         return FALSE;
394     }
395
396     return TRUE;
397 }
398
399
400 /* search a node inside the proc fs tree */
401
402 cfs_proc_entry_t *
403 proc_search_entry(
404     char *              name,
405     cfs_proc_entry_t *  root
406     )
407 {
408     cfs_proc_entry_t *  entry;
409     cfs_proc_entry_t *  parent;
410     char *first, *remain;
411     int   flen;
412     char *ename = NULL;
413
414     parent = root;
415     entry = NULL;
416
417     ename = cfs_alloc(0x21, CFS_ALLOC_ZERO);
418
419     if (ename == NULL) {
420         goto errorout;
421     }
422
423 again:
424
425     /* dissect the file name string */
426     proc_dissect_name(name, &first, &flen, &remain);
427
428     if (first) {
429
430         if (flen >= 0x20) {
431             cfs_enter_debugger();
432             entry = NULL;
433             goto errorout;
434         }
435
436         memset(ename, 0, 0x20);
437         memcpy(ename, first, flen);
438
439         entry = proc_search_splay(parent, ename);
440
441         if (!entry) {
442             goto errorout;
443         }
444
445         if (remain) {
446             name = remain;
447             parent = entry;
448
449             goto again;
450         }
451     }
452
453 errorout:
454
455     if (ename) {
456         cfs_free(ename);
457     }
458
459     return entry;   
460 }
461
462 /* insert the path nodes to the proc fs tree */
463
464 cfs_proc_entry_t *
465 proc_insert_entry(
466     char *              name,
467     cfs_proc_entry_t *  root
468     )
469 {
470     cfs_proc_entry_t *entry;
471     cfs_proc_entry_t *parent;
472     char *first, *remain;
473     int flen;
474     char ename[0x20];
475
476     parent = root;
477     entry = NULL;
478
479 again:
480
481     proc_dissect_name(name, &first, &flen, &remain);
482
483     if (first) {
484
485         if (flen >= 0x20) {
486             return NULL;
487         }
488
489         memset(ename, 0, 0x20);
490         memcpy(ename, first, flen);
491
492         entry = proc_search_splay(parent, ename);
493
494         if (!entry) {
495             entry = proc_alloc_entry();
496             memcpy(entry->name, ename, flen);
497
498             if (entry) {
499                 if(!proc_insert_splay(parent, entry)) {
500                     proc_free_entry(entry);
501                     entry = NULL;
502                 }
503             }
504         }
505
506         if (!entry) {
507             return NULL;
508         }
509
510         if (remain) {
511             entry->mode |= S_IFDIR | S_IRUGO | S_IXUGO;
512             cfs_set_flag(entry->flags, CFS_PROC_FLAG_DIRECTORY);
513             name = remain;
514             parent = entry;
515             goto again;
516         }
517     }
518
519     return entry;   
520 }
521
522 /* remove the path nodes from the proc fs tree */
523
524 void
525 proc_remove_entry(
526     char *              name,
527     cfs_proc_entry_t *  root
528     )
529 {
530     cfs_proc_entry_t *entry;
531     char *first, *remain;
532     int  flen;
533     char ename[0x20];
534
535     entry  = NULL;
536
537     proc_dissect_name(name, &first, &flen, &remain);
538
539     if (first) {
540
541         memset(ename, 0, 0x20);
542         memcpy(ename, first, flen);
543
544         entry = proc_search_splay(root, ename);
545
546         if (entry) {
547
548             if (remain) {
549                 ASSERT(S_ISDIR(entry->mode));
550                 proc_remove_entry(remain, entry);
551             }
552
553             if (!entry->nlink) {
554                 proc_remove_splay(root, entry);
555                 proc_free_entry(entry);
556             }
557         }
558     } else {
559         cfs_enter_debugger();
560     }
561 }
562
563 /* create proc entry and insert it into the proc fs */
564
565 cfs_proc_entry_t *
566 create_proc_entry (
567     char *              name,
568     mode_t              mode,
569     cfs_proc_entry_t *  root
570     )
571 {
572     cfs_proc_entry_t *parent = root;
573     cfs_proc_entry_t *entry  = NULL;
574
575     if (S_ISDIR(mode)) {
576         if ((mode & S_IALLUGO) == 0)
577         mode |= S_IRUGO | S_IXUGO;
578     } else {
579         if ((mode & S_IFMT) == 0)
580             mode |= S_IFREG;
581         if ((mode & S_IALLUGO) == 0)
582             mode |= S_IRUGO;
583     }
584
585     LOCK_PROCFS();
586
587     ASSERT(NULL != proc_fs_root);
588
589     if (!parent) {
590         parent = proc_fs_root;
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     char *              name,
623     cfs_proc_entry_t *  root
624     )
625 {
626     cfs_proc_entry_t * entry;
627
628     LOCK_PROCFS();
629     if (root == NULL) {
630         root = proc_fs_root;
631     }
632     entry = proc_search_entry(name, root);
633     UNLOCK_PROCFS();
634
635     return entry;    
636 }
637
638 /* remove the entry from the proc fs */
639
640 void
641 remove_proc_entry(
642     char *              name,
643     cfs_proc_entry_t *  parent
644     )
645 {
646     LOCK_PROCFS();
647     if (parent == NULL) {
648         parent = proc_fs_root;
649     }
650     proc_remove_entry(name, parent);
651     UNLOCK_PROCFS();
652 }
653
654
655 void proc_destroy_splay(cfs_proc_entry_t * entry)
656 {
657     cfs_proc_entry_t * node;
658
659     if (S_ISDIR(entry->mode)) {
660
661         while (entry->root) {
662             node = CONTAINING_RECORD(entry->root, cfs_proc_entry_t, s_link);
663             entry->root = RtlDelete(&(node->s_link));
664             proc_destroy_splay(node);
665         }
666     }
667
668     proc_free_entry(entry);
669 }
670
671
672 /* destory the whole proc fs tree */
673
674 void proc_destroy_fs()
675 {
676     LOCK_PROCFS();
677
678     if (proc_fs_root) {
679         proc_destroy_splay(proc_fs_root);
680     }
681
682     if (proc_entry_cache) {
683         cfs_mem_cache_destroy(proc_entry_cache);
684     }
685    
686     UNLOCK_PROCFS();
687 }
688
689 /* initilaize / build the proc fs tree */
690
691 int proc_init_fs()
692 {
693     cfs_proc_entry_t * root = NULL;
694
695     memset(&(root_table_header), 0, sizeof(struct ctl_table_header));
696     INIT_LIST_HEAD(&(root_table_header.ctl_entry));
697
698     INIT_PROCFS_LOCK();
699     proc_entry_cache = cfs_mem_cache_create(
700                             NULL,
701                             sizeof(cfs_proc_entry_t),
702                             0,
703                             0
704                             );
705
706     if (!proc_entry_cache) {
707         return (-ENOMEM);
708     }
709
710     root = proc_alloc_entry();
711
712     if (!root) {
713         proc_destroy_fs();
714         return (-ENOMEM);
715     }
716
717     root->magic = CFS_PROC_ENTRY_MAGIC;
718     root->flags = CFS_PROC_FLAG_DIRECTORY;
719     root->mode  = S_IFDIR | S_IRUGO | S_IXUGO;
720     root->nlink = 3; // root should never be deleted.
721
722     root->name[0]='p';
723     root->name[1]='r';
724     root->name[2]='o';
725     root->name[3]='c';
726
727     proc_fs_root = root;
728
729     proc_sys_root = create_proc_entry("sys", S_IFDIR, root);
730
731     if (!proc_sys_root) {
732         proc_free_entry(root);
733         proc_fs_root = NULL;
734         proc_destroy_fs();
735         return (-ENOMEM);
736     }
737
738     proc_sys_root->nlink = 1;
739
740     proc_dev_root = create_proc_entry("dev", S_IFDIR, root);
741
742     if (!proc_dev_root) {
743         proc_free_entry(proc_sys_root);
744         proc_sys_root = NULL;
745         proc_free_entry(proc_fs_root);
746         proc_fs_root = NULL;
747         proc_destroy_fs();
748         return (-ENOMEM);
749     }
750
751     proc_dev_root->nlink = 1;
752    
753     return 0;
754 }
755
756
757 static ssize_t do_rw_proc(int write, struct file * file, char * buf,
758               size_t count, loff_t *ppos)
759 {
760     int op;
761     cfs_proc_entry_t *de;
762     struct ctl_table *table;
763     size_t res;
764     ssize_t error;
765     
766     de = (cfs_proc_entry_t *) file->proc_dentry; 
767
768     if (!de || !de->data)
769         return -ENOTDIR;
770     table = (struct ctl_table *) de->data;
771     if (!table || !table->proc_handler)
772         return -ENOTDIR;
773     op = (write ? 002 : 004);
774
775 //  if (ctl_perm(table, op))
776 //      return -EPERM;
777     
778     res = count;
779
780     /*
781      * FIXME: we need to pass on ppos to the handler.
782      */
783
784     error = (*table->proc_handler) (table, write, file, buf, &res);
785     if (error)
786         return error;
787     return res;
788 }
789
790 static ssize_t proc_readsys(struct file * file, char * buf,
791                 size_t count, loff_t *ppos)
792 {
793     return do_rw_proc(0, file, buf, count, ppos);
794 }
795
796 static ssize_t proc_writesys(struct file * file, const char * buf,
797                  size_t count, loff_t *ppos)
798 {
799     return do_rw_proc(1, file, (char *) buf, count, ppos);
800 }
801
802
803 struct file_operations proc_sys_file_operations = {
804     /*lseek:*/      NULL,
805     /*read:*/       proc_readsys,
806     /*write:*/      proc_writesys,
807     /*ioctl:*/      NULL,
808     /*open:*/       NULL,
809     /*release:*/    NULL
810 };
811
812
813 /* Scan the sysctl entries in table and add them all into /proc */
814 void register_proc_table(cfs_sysctl_table_t * table, cfs_proc_entry_t * root)
815 {
816     cfs_proc_entry_t * de;
817     int len;
818     mode_t mode;
819     
820     for (; table->ctl_name; table++) {
821         /* Can't do anything without a proc name. */
822         if (!table->procname)
823             continue;
824         /* Maybe we can't do anything with it... */
825         if (!table->proc_handler && !table->child) {
826             printk(KERN_WARNING "SYSCTL: Can't register %s\n",
827                 table->procname);
828             continue;
829         }
830
831         len = strlen(table->procname);
832         mode = table->mode;
833
834         de = NULL;
835         if (table->proc_handler)
836             mode |= S_IFREG;
837         else {
838             de = search_proc_entry(table->procname, root);
839             if (de) {
840                 break;
841             }
842             /* If the subdir exists already, de is non-NULL */
843         }
844
845         if (!de) {
846
847             de = create_proc_entry((char *)table->procname, mode, root);
848             if (!de)
849                 continue;
850             de->data = (void *) table;
851             if (table->proc_handler) {
852                 de->proc_fops = &proc_sys_file_operations;
853             }
854         }
855         table->de = de;
856         if (de->mode & S_IFDIR)
857             register_proc_table(table->child, de);
858     }
859 }
860
861
862 /*
863  * Unregister a /proc sysctl table and any subdirectories.
864  */
865 void unregister_proc_table(cfs_sysctl_table_t * table, cfs_proc_entry_t *root)
866 {
867     cfs_proc_entry_t *de;
868     for (; table->ctl_name; table++) {
869         if (!(de = table->de))
870             continue;
871         if (de->mode & S_IFDIR) {
872             if (!table->child) {
873                 printk (KERN_ALERT "Help - malformed sysctl tree on free\n");
874                 continue;
875             }
876             unregister_proc_table(table->child, de);
877
878             /* Don't unregister directories which still have entries.. */
879             if (de->nlink)
880                 continue;
881         }
882
883         /* Don't unregister proc entries that are still being used.. */
884         if (de->nlink)
885             continue;
886
887         table->de = NULL;
888         remove_proc_entry((char *)table->procname, root);
889     }
890 }
891
892 /* The generic string strategy routine: */
893 int sysctl_string(cfs_sysctl_table_t *table, int *name, int nlen,
894           void *oldval, size_t *oldlenp,
895           void *newval, size_t newlen, void **context)
896 {
897     int l, len;
898     
899     if (!table->data || !table->maxlen) 
900         return -ENOTDIR;
901     
902     if (oldval && oldlenp) {
903         if(get_user(len, oldlenp))
904             return -EFAULT;
905         if (len) {
906             l = strlen(table->data);
907             if (len > l) len = l;
908             if (len >= table->maxlen)
909                 len = table->maxlen;
910             if(copy_to_user(oldval, table->data, len))
911                 return -EFAULT;
912             if(put_user(0, ((char *) oldval) + len))
913                 return -EFAULT;
914             if(put_user(len, oldlenp))
915                 return -EFAULT;
916         }
917     }
918     if (newval && newlen) {
919         len = newlen;
920         if (len > table->maxlen)
921             len = table->maxlen;
922         if(copy_from_user(table->data, newval, len))
923             return -EFAULT;
924         if (len == table->maxlen)
925             len--;
926         ((char *) table->data)[len] = 0;
927     }
928     return 0;
929 }
930
931 /**
932  * simple_strtoul - convert a string to an unsigned long
933  * @cp: The start of the string
934  * @endp: A pointer to the end of the parsed string will be placed here
935  * @base: The number base to use
936  */
937 unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
938 {
939     unsigned long result = 0, value;
940
941     if (!base) {
942         base = 10;
943         if (*cp == '0') {
944             base = 8;
945             cp++;
946             if ((*cp == 'x') && isxdigit(cp[1])) {
947                 cp++;
948                 base = 16;
949             }
950         }
951     }
952     while (isxdigit(*cp) &&
953            (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) {
954         result = result*base + value;
955         cp++;
956     }
957     if (endp)
958         *endp = (char *)cp;
959     return result;
960 }
961
962 #define OP_SET  0
963 #define OP_AND  1
964 #define OP_OR   2
965 #define OP_MAX  3
966 #define OP_MIN  4
967
968
969 static int do_proc_dointvec(cfs_sysctl_table_t *table, int write, struct file *filp,
970           void *buffer, size_t *lenp, int conv, int op)
971 {
972     int *i, vleft, first=1, neg, val;
973     size_t left, len;
974     
975     #define TMPBUFLEN 20
976     char buf[TMPBUFLEN], *p;
977     
978     if (!table->data || !table->maxlen || !*lenp)
979     {
980         *lenp = 0;
981         return 0;
982     }
983     
984     i = (int *) table->data;
985     vleft = table->maxlen / sizeof(int);
986     left = *lenp;
987     
988     for (; left && vleft--; i++, first=0) {
989         if (write) {
990             while (left) {
991                 char c;
992                 if(get_user(c,(char *) buffer))
993                     return -EFAULT;
994                 if (!isspace(c))
995                     break;
996                 left--;
997                 ((char *) buffer)++;
998             }
999             if (!left)
1000                 break;
1001             neg = 0;
1002             len = left;
1003             if (len > TMPBUFLEN-1)
1004                 len = TMPBUFLEN-1;
1005             if(copy_from_user(buf, buffer, len))
1006                 return -EFAULT;
1007             buf[len] = 0;
1008             p = buf;
1009             if (*p == '-' && left > 1) {
1010                 neg = 1;
1011                 left--, p++;
1012             }
1013             if (*p < '0' || *p > '9')
1014                 break;
1015             val = simple_strtoul(p, &p, 0) * conv;
1016             len = p-buf;
1017             if ((len < left) && *p && !isspace(*p))
1018                 break;
1019             if (neg)
1020                 val = -val;
1021             (char *)buffer += len;
1022             left -= len;
1023             switch(op) {
1024             case OP_SET:    *i = val; break;
1025             case OP_AND:    *i &= val; break;
1026             case OP_OR: *i |= val; break;
1027             case OP_MAX:    if(*i < val)
1028                         *i = val;
1029                     break;
1030             case OP_MIN:    if(*i > val)
1031                         *i = val;
1032                     break;
1033             }
1034         } else {
1035             p = buf;
1036             if (!first)
1037                 *p++ = '\t';
1038             sprintf(p, "%d", (*i) / conv);
1039             len = strlen(buf);
1040             if (len > left)
1041                 len = left;
1042             if(copy_to_user(buffer, buf, len))
1043                 return -EFAULT;
1044             left -= len;
1045             (char *)buffer += len;
1046         }
1047     }
1048
1049     if (!write && !first && left) {
1050         if(put_user('\n', (char *) buffer))
1051             return -EFAULT;
1052         left--, ((char *)buffer)++;
1053     }
1054     if (write) {
1055         p = (char *) buffer;
1056         while (left) {
1057             char c;
1058             if(get_user(c, p++))
1059                 return -EFAULT;
1060             if (!isspace(c))
1061                 break;
1062             left--;
1063         }
1064     }
1065     if (write && first)
1066         return -EINVAL;
1067     *lenp -= left;
1068     memset(&(filp->f_pos) , 0, sizeof(loff_t));
1069     filp->f_pos += (loff_t)(*lenp);
1070     return 0;
1071 }
1072
1073 /**
1074  * proc_dointvec - read a vector of integers
1075  * @table: the sysctl table
1076  * @write: %TRUE if this is a write to the sysctl file
1077  * @filp: the file structure
1078  * @buffer: the user buffer
1079  * @lenp: the size of the user buffer
1080  *
1081  * Reads/writes up to table->maxlen/sizeof(unsigned int) integer
1082  * values from/to the user buffer, treated as an ASCII string. 
1083  *
1084  * Returns 0 on success.
1085  */
1086 int proc_dointvec(cfs_sysctl_table_t *table, int write, struct file *filp,
1087              void *buffer, size_t *lenp)
1088 {
1089     return do_proc_dointvec(table,write,filp,buffer,lenp,1,OP_SET);
1090 }
1091
1092
1093 /**
1094  * proc_dostring - read a string sysctl
1095  * @table: the sysctl table
1096  * @write: %TRUE if this is a write to the sysctl file
1097  * @filp: the file structure
1098  * @buffer: the user buffer
1099  * @lenp: the size of the user buffer
1100  *
1101  * Reads/writes a string from/to the user buffer. If the kernel
1102  * buffer provided is not large enough to hold the string, the
1103  * string is truncated. The copied string is %NULL-terminated.
1104  * If the string is being read by the user process, it is copied
1105  * and a newline '\n' is added. It is truncated if the buffer is
1106  * not large enough.
1107  *
1108  * Returns 0 on success.
1109  */
1110 int proc_dostring(cfs_sysctl_table_t *table, int write, struct file *filp,
1111           void *buffer, size_t *lenp)
1112 {
1113     size_t len;
1114     char *p, c;
1115     
1116     if (!table->data || !table->maxlen || !*lenp ||
1117         (filp->f_pos && !write)) {
1118         *lenp = 0;
1119         return 0;
1120     }
1121     
1122     if (write) {
1123         len = 0;
1124         p = buffer;
1125         while (len < *lenp) {
1126             if(get_user(c, p++))
1127                 return -EFAULT;
1128             if (c == 0 || c == '\n')
1129                 break;
1130             len++;
1131         }
1132         if (len >= (size_t)table->maxlen)
1133             len = (size_t)table->maxlen-1;
1134         if(copy_from_user(table->data, buffer, len))
1135             return -EFAULT;
1136         ((char *) table->data)[len] = 0;
1137         filp->f_pos += *lenp;
1138     } else {
1139         len = (size_t)strlen(table->data);
1140         if (len > (size_t)table->maxlen)
1141             len = (size_t)table->maxlen;
1142         if (len > *lenp)
1143             len = *lenp;
1144         if (len)
1145             if(copy_to_user(buffer, table->data, len))
1146                 return -EFAULT;
1147         if (len < *lenp) {
1148             if(put_user('\n', ((char *) buffer) + len))
1149                 return -EFAULT;
1150             len++;
1151         }
1152         *lenp = len;
1153         filp->f_pos += len;
1154     }
1155     return 0;
1156 }
1157
1158 /* Perform the actual read/write of a sysctl table entry. */
1159 int do_sysctl_strategy (cfs_sysctl_table_t *table, 
1160             int *name, int nlen,
1161             void *oldval, size_t *oldlenp,
1162             void *newval, size_t newlen, void **context)
1163 {
1164     int op = 0, rc;
1165     size_t len;
1166
1167     if (oldval)
1168         op |= 004;
1169     if (newval) 
1170         op |= 002;
1171
1172     if (table->strategy) {
1173         rc = table->strategy(table, name, nlen, oldval, oldlenp,
1174                      newval, newlen, context);
1175         if (rc < 0)
1176             return rc;
1177         if (rc > 0)
1178             return 0;
1179     }
1180
1181     /* If there is no strategy routine, or if the strategy returns
1182      * zero, proceed with automatic r/w */
1183     if (table->data && table->maxlen) {
1184         if (oldval && oldlenp) {
1185             get_user(len, oldlenp);
1186             if (len) {
1187                 if (len > (size_t)table->maxlen)
1188                     len = (size_t)table->maxlen;
1189                 if(copy_to_user(oldval, table->data, len))
1190                     return -EFAULT;
1191                 if(put_user(len, oldlenp))
1192                     return -EFAULT;
1193             }
1194         }
1195         if (newval && newlen) {
1196             len = newlen;
1197             if (len > (size_t)table->maxlen)
1198                 len = (size_t)table->maxlen;
1199             if(copy_from_user(table->data, newval, len))
1200                 return -EFAULT;
1201         }
1202     }
1203     return 0;
1204 }
1205
1206 static int parse_table(int *name, int nlen,
1207                void *oldval, size_t *oldlenp,
1208                void *newval, size_t newlen,
1209                cfs_sysctl_table_t *table, void **context)
1210 {
1211     int n;
1212
1213 repeat:
1214
1215     if (!nlen)
1216         return -ENOTDIR;
1217     if (get_user(n, name))
1218         return -EFAULT;
1219     for ( ; table->ctl_name; table++) {
1220         if (n == table->ctl_name || table->ctl_name == CTL_ANY) {
1221             int error;
1222             if (table->child) {
1223 /*
1224                 if (ctl_perm(table, 001))
1225                     return -EPERM;
1226 */
1227                 if (table->strategy) {
1228                     error = table->strategy(
1229                         table, name, nlen,
1230                         oldval, oldlenp,
1231                         newval, newlen, context);
1232                     if (error)
1233                         return error;
1234                 }
1235                 name++;
1236                 nlen--;
1237                 table = table->child;
1238                 goto repeat;
1239             }
1240             error = do_sysctl_strategy(table, name, nlen,
1241                            oldval, oldlenp,
1242                            newval, newlen, context);
1243             return error;
1244         }
1245     }
1246     return -ENOTDIR;
1247 }
1248
1249 int do_sysctl(int *name, int nlen, void *oldval, size_t *oldlenp,
1250            void *newval, size_t newlen)
1251 {
1252     struct list_head *tmp;
1253
1254     if (nlen <= 0 || nlen >= CTL_MAXNAME)
1255         return -ENOTDIR;
1256     if (oldval) {
1257         int old_len;
1258         if (!oldlenp || get_user(old_len, oldlenp))
1259             return -EFAULT;
1260     }
1261     tmp = &root_table_header.ctl_entry;
1262     do {
1263         struct ctl_table_header *head =
1264             list_entry(tmp, struct ctl_table_header, ctl_entry);
1265         void *context = NULL;
1266         int error = parse_table(name, nlen, oldval, oldlenp, 
1267                     newval, newlen, head->ctl_table,
1268                     &context);
1269         if (context)
1270             cfs_free(context);
1271         if (error != -ENOTDIR)
1272             return error;
1273         tmp = tmp->next;
1274     } while (tmp != &root_table_header.ctl_entry);
1275     return -ENOTDIR;
1276 }
1277
1278 /**
1279  * register_sysctl_table - register a sysctl heirarchy
1280  * @table: the top-level table structure
1281  * @insert_at_head: whether the entry should be inserted in front or at the end
1282  *
1283  * Register a sysctl table heirarchy. @table should be a filled in ctl_table
1284  * array. An entry with a ctl_name of 0 terminates the table. 
1285  *
1286  * The members of the &ctl_table structure are used as follows:
1287  *
1288  * ctl_name - This is the numeric sysctl value used by sysctl(2). The number
1289  *            must be unique within that level of sysctl
1290  *
1291  * procname - the name of the sysctl file under /proc/sys. Set to %NULL to not
1292  *            enter a sysctl file
1293  *
1294  * data - a pointer to data for use by proc_handler
1295  *
1296  * maxlen - the maximum size in bytes of the data
1297  *
1298  * mode - the file permissions for the /proc/sys file, and for sysctl(2)
1299  *
1300  * child - a pointer to the child sysctl table if this entry is a directory, or
1301  *         %NULL.
1302  *
1303  * proc_handler - the text handler routine (described below)
1304  *
1305  * strategy - the strategy routine (described below)
1306  *
1307  * de - for internal use by the sysctl routines
1308  *
1309  * extra1, extra2 - extra pointers usable by the proc handler routines
1310  *
1311  * Leaf nodes in the sysctl tree will be represented by a single file
1312  * under /proc; non-leaf nodes will be represented by directories.
1313  *
1314  * sysctl(2) can automatically manage read and write requests through
1315  * the sysctl table.  The data and maxlen fields of the ctl_table
1316  * struct enable minimal validation of the values being written to be
1317  * performed, and the mode field allows minimal authentication.
1318  *
1319  * More sophisticated management can be enabled by the provision of a
1320  * strategy routine with the table entry.  This will be called before
1321  * any automatic read or write of the data is performed.
1322  *
1323  * The strategy routine may return
1324  *
1325  * < 0 - Error occurred (error is passed to user process)
1326  *
1327  * 0   - OK - proceed with automatic read or write.
1328  *
1329  * > 0 - OK - read or write has been done by the strategy routine, so
1330  *       return immediately.
1331  *
1332  * There must be a proc_handler routine for any terminal nodes
1333  * mirrored under /proc/sys (non-terminals are handled by a built-in
1334  * directory handler).  Several default handlers are available to
1335  * cover common cases -
1336  *
1337  * proc_dostring(), proc_dointvec(), proc_dointvec_jiffies(),
1338  * proc_dointvec_minmax(), proc_doulongvec_ms_jiffies_minmax(),
1339  * proc_doulongvec_minmax()
1340  *
1341  * It is the handler's job to read the input buffer from user memory
1342  * and process it. The handler should return 0 on success.
1343  *
1344  * This routine returns %NULL on a failure to register, and a pointer
1345  * to the table header on success.
1346  */
1347 struct ctl_table_header *register_sysctl_table(cfs_sysctl_table_t * table, 
1348                            int insert_at_head)
1349 {
1350     struct ctl_table_header *tmp;
1351     tmp = cfs_alloc(sizeof(struct ctl_table_header), 0);
1352     if (!tmp)
1353         return NULL;
1354     tmp->ctl_table = table;
1355
1356     INIT_LIST_HEAD(&tmp->ctl_entry);
1357     if (insert_at_head)
1358         list_add(&tmp->ctl_entry, &root_table_header.ctl_entry);
1359     else
1360         list_add_tail(&tmp->ctl_entry, &root_table_header.ctl_entry);
1361 #ifdef CONFIG_PROC_FS
1362     register_proc_table(table, proc_sys_root);
1363 #endif
1364     return tmp;
1365 }
1366
1367 /**
1368  * unregister_sysctl_table - unregister a sysctl table heirarchy
1369  * @header: the header returned from register_sysctl_table
1370  *
1371  * Unregisters the sysctl table and all children. proc entries may not
1372  * actually be removed until they are no longer used by anyone.
1373  */
1374 void unregister_sysctl_table(struct ctl_table_header * header)
1375 {
1376     list_del(&header->ctl_entry);
1377 #ifdef CONFIG_PROC_FS
1378     unregister_proc_table(header->ctl_table, proc_sys_root);
1379 #endif
1380     cfs_free(header);
1381 }
1382
1383
1384 int cfs_psdev_register(cfs_psdev_t * psdev)
1385 {
1386     cfs_proc_entry_t *  entry;
1387
1388     entry = create_proc_entry (
1389                 (char *)psdev->name,
1390                 S_IFREG,
1391                 proc_dev_root
1392             );
1393
1394     if (!entry) {
1395         return -ENOMEM;
1396     }
1397
1398     entry->flags |= CFS_PROC_FLAG_MISCDEV;
1399
1400     entry->proc_fops = psdev->fops;
1401     entry->data = (void *)psdev;
1402
1403     return 0;
1404 }
1405
1406 int cfs_psdev_deregister(cfs_psdev_t * psdev)
1407 {
1408     cfs_proc_entry_t *  entry;
1409
1410     entry = search_proc_entry (
1411                 (char *)psdev->name,
1412                 proc_dev_root
1413             );
1414
1415     if (entry) {
1416
1417         ASSERT(entry->data == (void *)psdev);
1418         ASSERT(entry->flags & CFS_PROC_FLAG_MISCDEV);
1419
1420         remove_proc_entry(
1421             (char *)psdev->name,
1422             proc_dev_root
1423             );
1424     }
1425
1426     return 0;
1427 }
1428
1429 extern char debug_file_path[1024];
1430
1431 #define PSDEV_LNET  (0x100)
1432 enum {
1433         PSDEV_DEBUG = 1,          /* control debugging */
1434         PSDEV_SUBSYSTEM_DEBUG,    /* control debugging */
1435         PSDEV_PRINTK,             /* force all messages to console */
1436         PSDEV_CONSOLE_RATELIMIT,  /* rate limit console messages */
1437         PSDEV_DEBUG_PATH,         /* crashdump log location */
1438         PSDEV_DEBUG_DUMP_PATH,    /* crashdump tracelog location */
1439         PSDEV_LIBCFS_MEMUSED,     /* bytes currently PORTAL_ALLOCated */
1440 };
1441
1442 static struct ctl_table lnet_table[] = {
1443         {PSDEV_DEBUG, "debug", &libcfs_debug, sizeof(int), 0644, NULL,
1444          &proc_dointvec},
1445         {PSDEV_SUBSYSTEM_DEBUG, "subsystem_debug", &libcfs_subsystem_debug,
1446          sizeof(int), 0644, NULL, &proc_dointvec},
1447         {PSDEV_PRINTK, "printk", &libcfs_printk, sizeof(int), 0644, NULL,
1448          &proc_dointvec},
1449         {PSDEV_CONSOLE_RATELIMIT, "console_ratelimit", &libcfs_console_ratelimit, 
1450          sizeof(int), 0644, NULL, &proc_dointvec},
1451         {PSDEV_DEBUG_PATH, "debug_path", debug_file_path,
1452          sizeof(debug_file_path), 0644, NULL, &proc_dostring, &sysctl_string},
1453 /*
1454         {PSDEV_PORTALS_UPCALL, "upcall", portals_upcall,
1455          sizeof(portals_upcall), 0644, NULL, &proc_dostring,
1456          &sysctl_string},
1457 */
1458         {PSDEV_LIBCFS_MEMUSED, "memused", (int *)&libcfs_kmemory.counter,
1459          sizeof(int), 0644, NULL, &proc_dointvec},
1460         {0}
1461 };
1462
1463 static struct ctl_table top_table[2] = {
1464         {PSDEV_LNET, "lnet", NULL, 0, 0555, lnet_table},
1465         {0}
1466 };
1467
1468
1469 int trace_write_dump_kernel(struct file *file, const char *buffer,
1470                              unsigned long count, void *data)
1471 {
1472         int rc = trace_dump_debug_buffer_usrstr(buffer, count);
1473         
1474         return (rc < 0) ? rc : count;
1475 }
1476
1477 int trace_write_daemon_file(struct file *file, const char *buffer,
1478                             unsigned long count, void *data)
1479 {
1480         int rc = trace_daemon_command_usrstr(buffer, count);
1481
1482         return (rc < 0) ? rc : count;
1483 }
1484
1485 int trace_read_daemon_file(char *page, char **start, off_t off, int count,
1486                            int *eof, void *data)
1487 {
1488         int rc;
1489
1490         tracefile_read_lock();
1491
1492         rc = trace_copyout_string(page, count, tracefile, "\n");
1493
1494         tracefile_read_unlock();
1495
1496         return rc;
1497 }
1498
1499 int trace_write_debug_mb(struct file *file, const char *buffer,
1500                          unsigned long count, void *data)
1501 {
1502         int rc = trace_set_debug_mb_userstr(buffer, count);
1503         
1504         return (rc < 0) ? rc : count;
1505 }
1506
1507 int trace_read_debug_mb(char *page, char **start, off_t off, int count,
1508                         int *eof, void *data)
1509 {
1510         char   str[32];
1511
1512         snprintf(str, sizeof(str), "%d\n", trace_get_debug_mb());
1513
1514         return trace_copyout_string(page, count, str, NULL);
1515 }
1516
1517 int insert_proc(void)
1518 {
1519         cfs_proc_entry_t *ent;
1520
1521         ent = create_proc_entry("sys/lnet/dump_kernel", 0, NULL);
1522         if (ent == NULL) {
1523                 CERROR(("couldn't register dump_kernel\n"));
1524                 return -1;
1525         }
1526         ent->write_proc = trace_write_dump_kernel;
1527
1528         ent = create_proc_entry("sys/lnet/daemon_file", 0, NULL);
1529         if (ent == NULL) {
1530                 CERROR(("couldn't register daemon_file\n"));
1531                 return -1;
1532         }
1533         ent->write_proc = trace_write_daemon_file;
1534         ent->read_proc = trace_read_daemon_file;
1535
1536         ent = create_proc_entry("sys/lnet/debug_mb", 0, NULL);
1537         if (ent == NULL) {
1538                 CERROR(("couldn't register debug_mb\n"));
1539                 return -1;
1540         }
1541         ent->write_proc = trace_write_debug_mb;
1542         ent->read_proc = trace_read_debug_mb;
1543
1544         return 0;
1545 }
1546
1547 void remove_proc(void)
1548 {
1549         remove_proc_entry("sys/portals/dump_kernel", NULL);
1550         remove_proc_entry("sys/portals/daemon_file", NULL);
1551         remove_proc_entry("sys/portals/debug_mb", NULL);
1552
1553 #ifdef CONFIG_SYSCTL
1554         if (portals_table_header)
1555                 unregister_sysctl_table(portals_table_header);
1556         portals_table_header = NULL;
1557 #endif
1558 }
1559
1560
1561 /*
1562  *  proc process routines of kernel space
1563  */
1564
1565 cfs_file_t *
1566 lustre_open_file(char * filename)
1567 {
1568     int rc = 0;
1569     cfs_file_t * fh = NULL;
1570     cfs_proc_entry_t * fp = NULL;
1571
1572     fp = search_proc_entry(filename, proc_fs_root);
1573
1574     if (!fp) {
1575         rc =  -ENOENT;
1576         return NULL;
1577     }
1578
1579     fh = cfs_alloc(sizeof(cfs_file_t), CFS_ALLOC_ZERO);
1580
1581     if (!fh) {
1582         rc =  -ENOMEM;
1583         return NULL;
1584     }
1585
1586     fh->private_data = (void *)fp;
1587     fh->f_op = fp->proc_fops;
1588
1589     if (fh->f_op->open) {
1590         rc = (fh->f_op->open)(fh);
1591     } else {
1592         fp->nlink++;
1593     }
1594
1595     if (0 != rc) {
1596         cfs_free(fh);
1597         return NULL;
1598     }
1599
1600     return fh;
1601 }
1602
1603 int
1604 lustre_close_file(cfs_file_t * fh)
1605 {
1606     int rc = 0;
1607     cfs_proc_entry_t * fp = NULL;
1608
1609     fp = (cfs_proc_entry_t *) fh->private_data;
1610
1611     if (fh->f_op->release) {
1612         rc = (fh->f_op->release)(fh);
1613     } else {
1614         fp->nlink--;
1615     }
1616
1617     cfs_free(fh);
1618
1619     return rc;
1620 }
1621
1622 int
1623 lustre_do_ioctl( cfs_file_t * fh,
1624                  unsigned long cmd,
1625                  ulong_ptr arg )
1626 {
1627     int rc = 0;
1628
1629     if (fh->f_op->ioctl) {
1630         rc = (fh->f_op->ioctl)(fh, cmd, arg);
1631     }
1632
1633     if (rc != 0) {
1634         printk("lustre_do_ioctl: fialed: cmd = %xh arg = %xh rc = %d\n",
1635                 cmd, arg, rc);
1636     }
1637
1638     return rc;
1639 }
1640     
1641 int
1642 lustre_ioctl_file(cfs_file_t * fh, PCFS_PROC_IOCTL devctl)
1643 {
1644     int         rc = 0;
1645     ulong_ptr   data;
1646
1647     data = (ulong_ptr)devctl + sizeof(CFS_PROC_IOCTL);
1648
1649     /* obd ioctl code */
1650     if (_IOC_TYPE(devctl->cmd) == 'f') {
1651 #if 0
1652         struct obd_ioctl_data * obd = (struct obd_ioctl_data *) data;
1653
1654         if ( devctl->cmd != (ULONG)OBD_IOC_BRW_WRITE  &&
1655              devctl->cmd != (ULONG)OBD_IOC_BRW_READ ) {
1656
1657             unsigned long off = obd->ioc_len;
1658
1659             if (obd->ioc_pbuf1) {
1660                 obd->ioc_pbuf1 = (char *)(data + off);
1661                 off += size_round(obd->ioc_plen1);
1662             }
1663
1664             if (obd->ioc_pbuf2) {
1665                 obd->ioc_pbuf2 = (char *)(data + off);
1666             }
1667         }
1668  #endif
1669    }
1670
1671     rc = lustre_do_ioctl(fh, devctl->cmd, data);
1672
1673     return rc;
1674
1675
1676
1677 size_t
1678 lustre_read_file(
1679     cfs_file_t *    fh,
1680     loff_t          off,
1681     size_t          size,
1682     char *          buf
1683     )
1684 {
1685     size_t rc = 0;
1686
1687     if (fh->f_op->read) {
1688         rc = (fh->f_op->read) (fh, buf, size, &off);
1689     }
1690
1691     return rc;
1692 }
1693  
1694
1695 size_t
1696 lustre_write_file(
1697     cfs_file_t *    fh,
1698     loff_t          off,
1699     size_t          size,
1700     char *          buf
1701     )
1702 {
1703     size_t rc = 0;
1704
1705     if (fh->f_op->write) {
1706         rc = (fh->f_op->write)(fh, buf, size, &off);
1707     }
1708
1709     return rc;
1710 }  
1711
1712 #else /* !__KERNEL__ */
1713
1714 #include <lnet/api-support.h>
1715 #include <liblustre.h>
1716 #include <lustre_lib.h>
1717
1718 /*
1719  * proc process routines of user space
1720  */
1721
1722 HANDLE cfs_proc_open (char * filename, int oflag)
1723 {
1724     NTSTATUS            status;
1725     IO_STATUS_BLOCK     iosb;
1726     int                 rc;
1727
1728     HANDLE              FileHandle = INVALID_HANDLE_VALUE;
1729     OBJECT_ATTRIBUTES   ObjectAttributes;
1730     ACCESS_MASK         DesiredAccess;
1731     ULONG               CreateDisposition;
1732     ULONG               ShareAccess;
1733     ULONG               CreateOptions;
1734     UNICODE_STRING      UnicodeName;
1735     USHORT              NameLength;
1736
1737     PFILE_FULL_EA_INFORMATION Ea = NULL;
1738     ULONG               EaLength;
1739     UCHAR               EaBuffer[EA_MAX_LENGTH];
1740
1741     /* Check the filename: should start with "/proc" or "/dev" */
1742     NameLength = (USHORT)strlen(filename);
1743     if (NameLength > 0x05) {
1744         if (_strnicmp(filename, "/proc/", 6) == 0) {
1745             filename += 6;
1746             NameLength -=6;
1747             if (NameLength <= 0) {
1748                 rc = -EINVAL;
1749                 goto errorout;
1750             }
1751         } else if (_strnicmp(filename, "/dev/", 5) == 0) {
1752         } else {
1753             rc = -EINVAL;
1754             goto errorout;
1755         }
1756     } else {
1757         rc = -EINVAL;
1758         goto errorout;
1759     }
1760
1761     /* Analyze the flags settings */
1762
1763     if (cfs_is_flag_set(oflag, O_WRONLY)) {
1764         DesiredAccess = (GENERIC_WRITE | SYNCHRONIZE);
1765         ShareAccess = 0;
1766     }  else if (cfs_is_flag_set(oflag, O_RDWR)) {
1767         DesiredAccess = (GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE);
1768         ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE;
1769     } else {
1770         DesiredAccess = (GENERIC_READ | SYNCHRONIZE);
1771         ShareAccess = FILE_SHARE_READ;
1772     }
1773
1774     if (cfs_is_flag_set(oflag, O_CREAT)) {
1775         if (cfs_is_flag_set(oflag, O_EXCL)) {
1776             CreateDisposition = FILE_CREATE;
1777             rc = -EINVAL;
1778             goto errorout;
1779         } else {
1780             CreateDisposition = FILE_OPEN_IF;
1781         }
1782     } else {
1783         CreateDisposition = FILE_OPEN;
1784     }
1785
1786     if (cfs_is_flag_set(oflag, O_TRUNC)) {
1787         if (cfs_is_flag_set(oflag, O_EXCL)) {
1788             CreateDisposition = FILE_OVERWRITE;
1789         } else {
1790             CreateDisposition = FILE_OVERWRITE_IF;
1791         }
1792     }
1793
1794     CreateOptions = 0;
1795
1796     if (cfs_is_flag_set(oflag, O_DIRECTORY)) {
1797         cfs_set_flag(CreateOptions,  FILE_DIRECTORY_FILE);
1798     }
1799
1800     if (cfs_is_flag_set(oflag, O_SYNC)) {
1801          cfs_set_flag(CreateOptions, FILE_WRITE_THROUGH);
1802     }
1803
1804     if (cfs_is_flag_set(oflag, O_DIRECT)) {
1805          cfs_set_flag(CreateOptions, FILE_NO_INTERMEDIATE_BUFFERING);
1806     }
1807
1808     /* Initialize the unicode path name for the specified file */
1809     RtlInitUnicodeString(&UnicodeName, LUSTRE_PROC_SYMLNK);
1810
1811     /* Setup the object attributes structure for the file. */
1812     InitializeObjectAttributes(
1813             &ObjectAttributes,
1814             &UnicodeName,
1815             OBJ_CASE_INSENSITIVE,
1816             NULL,
1817             NULL );
1818
1819     /* building EA for the proc entry ...  */
1820     Ea = (PFILE_FULL_EA_INFORMATION)EaBuffer;
1821     Ea->NextEntryOffset = 0;
1822     Ea->Flags = 0;
1823     Ea->EaNameLength = (UCHAR)NameLength;
1824     Ea->EaValueLength = 0;
1825     RtlCopyMemory(
1826         &(Ea->EaName),
1827         filename,
1828         NameLength + 1
1829         );
1830     EaLength =  sizeof(FILE_FULL_EA_INFORMATION) - 1 +
1831                                 Ea->EaNameLength + 1;
1832
1833     /* Now to open or create the file now */
1834     status = ZwCreateFile(
1835                 &FileHandle,
1836                 DesiredAccess,
1837                 &ObjectAttributes,
1838                 &iosb,
1839                 0,
1840                 FILE_ATTRIBUTE_NORMAL,
1841                 ShareAccess,
1842                 CreateDisposition,
1843                 CreateOptions,
1844                 Ea,
1845                 EaLength );
1846
1847     /* Check the returned status of Iosb ... */
1848
1849     if (!NT_SUCCESS(status)) {
1850         rc = cfs_error_code(status);
1851         goto errorout;
1852     }
1853
1854 errorout:
1855
1856     return FileHandle;
1857 }
1858
1859 int cfs_proc_close(HANDLE handle)
1860 {
1861     if (handle) {
1862         NtClose((HANDLE)handle);
1863     }
1864
1865     return 0;
1866 }
1867
1868 int cfs_proc_read(HANDLE handle, void *buffer, unsigned int count)
1869 {
1870     NTSTATUS            status;
1871     IO_STATUS_BLOCK     iosb;
1872     LARGE_INTEGER       offset;
1873
1874
1875     offset.QuadPart = 0;
1876
1877     /* read file data */
1878     status = NtReadFile(
1879                 (HANDLE)handle,
1880                 0,
1881                 NULL,
1882                 NULL,
1883                 &iosb,
1884                 buffer,
1885                 count,
1886                 &offset,
1887                 NULL);                     
1888
1889     /* check the return status */
1890     if (!NT_SUCCESS(status)) {
1891         printf("NtReadFile request failed 0x%0x\n", status);
1892         goto errorout;
1893     }
1894
1895 errorout:
1896
1897     if (NT_SUCCESS(status)) {
1898         return iosb.Information;
1899     }
1900
1901     return cfs_error_code(status);
1902 }
1903
1904
1905 int cfs_proc_write(HANDLE handle, void *buffer, unsigned int count)
1906 {
1907     NTSTATUS            status;
1908     IO_STATUS_BLOCK     iosb;
1909     LARGE_INTEGER       offset;
1910
1911     offset.QuadPart = -1;
1912
1913     /* write buffer to the opened file */
1914     status = NtWriteFile(
1915                 (HANDLE)handle,
1916                 0,
1917                 NULL,
1918                 NULL,
1919                 &iosb,
1920                 buffer,
1921                 count,
1922                 &offset,
1923                 NULL);                     
1924
1925     /* check the return status */
1926     if (!NT_SUCCESS(status)) {
1927         printf("NtWriteFile request failed 0x%0x\n", status);
1928         goto errorout;
1929     }
1930
1931 errorout:
1932
1933     if (NT_SUCCESS(status)) {
1934         return iosb.Information;
1935     }
1936
1937     return cfs_error_code(status);
1938 }
1939
1940 int cfs_proc_ioctl(HANDLE handle, int cmd, void *buffer)
1941 {
1942     PUCHAR          procdat = NULL;
1943     CFS_PROC_IOCTL  procctl;
1944     ULONG           length = 0;
1945     ULONG           extra = 0;
1946
1947     NTSTATUS        status;
1948     IO_STATUS_BLOCK iosb;
1949
1950     procctl.cmd = cmd;
1951
1952     if(_IOC_TYPE(cmd) == IOC_LIBCFS_TYPE) {
1953         struct libcfs_ioctl_data * portal;
1954         portal = (struct libcfs_ioctl_data *) buffer;
1955         length = portal->ioc_len;
1956     } else if (_IOC_TYPE(cmd) == 'f') {
1957         struct obd_ioctl_data * obd;
1958         obd = (struct obd_ioctl_data *) buffer;
1959         length = obd->ioc_len;
1960         extra = size_round(obd->ioc_plen1) + size_round(obd->ioc_plen2);
1961     } else if(_IOC_TYPE(cmd) == 'u') {
1962         length = 4;
1963         extra  = 0;
1964     } else {
1965         printf("user:winnt-proc:cfs_proc_ioctl: un-supported ioctl type ...\n");
1966         cfs_enter_debugger();
1967         status = STATUS_INVALID_PARAMETER;
1968         goto errorout;
1969     }
1970
1971     procctl.len = length + extra;
1972     procdat = malloc(length + extra + sizeof(CFS_PROC_IOCTL));
1973
1974     if (NULL == procdat) {
1975         printf("user:winnt-proc:cfs_proc_ioctl: no enough memory ...\n");
1976         status = STATUS_INSUFFICIENT_RESOURCES;
1977         cfs_enter_debugger();
1978         goto errorout;
1979     }
1980     memset(procdat, 0, length + extra + sizeof(CFS_PROC_IOCTL));
1981     memcpy(procdat, &procctl, sizeof(CFS_PROC_IOCTL));
1982     memcpy(&procdat[sizeof(CFS_PROC_IOCTL)], buffer, length);
1983     length += sizeof(CFS_PROC_IOCTL);
1984
1985     if (_IOC_TYPE(cmd) == 'f') {
1986
1987         char *ptr;
1988         struct obd_ioctl_data * data;
1989         struct obd_ioctl_data * obd;
1990
1991         data = (struct obd_ioctl_data *) buffer;
1992         obd  = (struct obd_ioctl_data *) (procdat + sizeof(CFS_PROC_IOCTL));
1993         ptr = obd->ioc_bulk;
1994
1995         if (data->ioc_inlbuf1) {
1996                 obd->ioc_inlbuf1 = ptr;
1997                 LOGL(data->ioc_inlbuf1, data->ioc_inllen1, ptr);
1998         }
1999
2000         if (data->ioc_inlbuf2) {
2001                 obd->ioc_inlbuf2 = ptr;
2002                 LOGL(data->ioc_inlbuf2, data->ioc_inllen2, ptr);
2003         }
2004         if (data->ioc_inlbuf3) {
2005                 obd->ioc_inlbuf3 = ptr;
2006                 LOGL(data->ioc_inlbuf3, data->ioc_inllen3, ptr);
2007         }
2008         if (data->ioc_inlbuf4) {
2009                 obd->ioc_inlbuf4 = ptr;
2010                 LOGL(data->ioc_inlbuf4, data->ioc_inllen4, ptr);
2011         }
2012     
2013         if ( cmd != (ULONG)OBD_IOC_BRW_WRITE  &&
2014              cmd != (ULONG)OBD_IOC_BRW_READ ) {
2015
2016             if (data->ioc_pbuf1 && data->ioc_plen1) {
2017                 obd->ioc_pbuf1 = &procdat[length];
2018                 memcpy(obd->ioc_pbuf1, data->ioc_pbuf1, data->ioc_plen1); 
2019                 length += size_round(data->ioc_plen1);
2020             }
2021
2022             if (data->ioc_pbuf2 && data->ioc_plen2) {
2023                 obd->ioc_pbuf2 = &procdat[length];
2024                 memcpy(obd->ioc_pbuf2, data->ioc_pbuf2, data->ioc_plen2);
2025                 length += size_round(data->ioc_plen2);
2026             }
2027         }
2028
2029         if (obd_ioctl_is_invalid(obd)) {
2030             cfs_enter_debugger();
2031         }
2032     }
2033
2034     status = NtDeviceIoControlFile(
2035                 (HANDLE)handle,
2036                 NULL, NULL, NULL, &iosb,
2037                 IOCTL_LIBCFS_ENTRY,
2038                 procdat, length,
2039                 procdat, length );
2040
2041
2042     if (NT_SUCCESS(status)) {
2043         memcpy(buffer, &procdat[sizeof(CFS_PROC_IOCTL)], procctl.len); 
2044     }
2045
2046 errorout:
2047
2048     if (procdat) {
2049         free(procdat);
2050     }
2051
2052     return cfs_error_code(status);
2053 }
2054
2055 #endif /* __KERNEL__ */