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