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