Whamcloud - gitweb
Changes to accomodate the snapshot driver.
[fs/lustre-release.git] / lustre / obdclass / class_obd.c
1 /*
2  *              An implementation of a loadable kernel mode driver providing
3  *              multiple kernel/user space bidirectional communications links.
4  *
5  *              Author:         Alan Cox <alan@cymru.net>
6  *
7  *              This program is free software; you can redistribute it and/or
8  *              modify it under the terms of the GNU General Public License
9  *              as published by the Free Software Foundation; either version
10  *              2 of the License, or (at your option) any later version.
11  * 
12  *              Adapted to become the Linux 2.0 Coda pseudo device
13  *              Peter  Braam  <braam@maths.ox.ac.uk> 
14  *              Michael Callahan <mjc@emmy.smith.edu>           
15  *
16  *              Changes for Linux 2.1
17  *              Copyright (c) 1997 Carnegie-Mellon University
18  *
19  *              Redone again for Intermezzo
20  *              Copyright (c) 1998 Peter J. Braam
21  *
22  *              Hacked up again for simulated OBD
23  *              Copyright (c) 1999 Stelias Computing, Inc.
24  *                (authors {pschwan,braam}@stelias.com)
25  *              Copyright (C) 1999 Seagate Technology, Inc.
26  *
27  * 
28  */
29
30 #define EXPORT_SYMTAB
31
32 #include <linux/config.h> /* for CONFIG_PROC_FS */
33 #include <linux/module.h>
34 #include <linux/errno.h>
35 #include <linux/kernel.h>
36 #include <linux/major.h>
37 #include <linux/sched.h>
38 #include <linux/lp.h>
39 #include <linux/malloc.h>
40 #include <linux/ioport.h>
41 #include <linux/fcntl.h>
42 #include <linux/delay.h>
43 #include <linux/skbuff.h>
44 #include <linux/proc_fs.h>
45 #include <linux/vmalloc.h>
46 #include <linux/fs.h>
47 #include <linux/poll.h>
48 #include <linux/init.h>
49 #include <linux/list.h>
50 #include <asm/io.h>
51 #include <asm/segment.h>
52 #include <asm/system.h>
53 #include <asm/poll.h>
54 #include <asm/uaccess.h>
55
56 #include <linux/obd_support.h>
57 #include <linux/obd_class.h>
58
59 static int obd_init_magic;
60 int           obd_print_entry = 1;
61 int           obd_debug_level = 4095;
62 struct obd_device obd_dev[MAX_OBD_DEVICES];
63 struct list_head obd_types;
64
65 /* called when opening /dev/obdNNN */
66 static int obd_class_open(struct inode * inode, struct file * file)
67 {
68         int dev;
69         ENTRY;
70
71         if (!inode)
72                 return -EINVAL;
73         dev = MINOR(inode->i_rdev);
74         if (dev >= MAX_OBD_DEVICES)
75                 return -ENODEV;
76         obd_dev[dev].obd_refcnt++;
77         CDEBUG(D_PSDEV, "Refcount now %d\n", obd_dev[dev].obd_refcnt++);
78
79         MOD_INC_USE_COUNT;
80         EXIT;
81         return 0;
82 }
83
84 /* called when closing /dev/obdNNN */
85 static int obd_class_release(struct inode * inode, struct file * file)
86 {
87         int dev;
88         ENTRY;
89
90         if (!inode)
91                 return -EINVAL;
92         dev = MINOR(inode->i_rdev);
93         if (dev >= MAX_OBD_DEVICES)
94                 return -ENODEV;
95         fsync_dev(inode->i_rdev);
96         if (obd_dev[dev].obd_refcnt <= 0)
97                 printk(KERN_ALERT "presto_psdev_release: refcount(%d) <= 0\n",
98                        obd_dev[dev].obd_refcnt);
99         obd_dev[dev].obd_refcnt--;
100
101         CDEBUG(D_PSDEV, "Refcount now %d\n", obd_dev[dev].obd_refcnt++);
102
103         MOD_DEC_USE_COUNT;
104
105         EXIT;
106         return 0;
107 }
108
109 /* support function */
110 static struct obd_type *obd_nm_to_type(char *nm) 
111 {
112         struct list_head *tmp;
113         struct obd_type *type;
114         CDEBUG(D_IOCTL, "SEARCH %s\n", nm);
115         
116         tmp = &obd_types;
117         while ( (tmp = tmp->next) != &obd_types ) {
118                 type = list_entry(tmp, struct obd_type, typ_chain);
119                 CDEBUG(D_IOCTL, "TYP %s\n", type->typ_name);
120                 if (strlen(type->typ_name) == strlen(nm) &&
121                     strcmp(type->typ_name, nm) == 0 ) {
122                         return type;
123                 }
124         }
125         return NULL;
126 }
127
128
129 static int getdata(int len, void **data)
130 {
131         void *tmp = NULL;
132
133         if (!len) 
134                 return 0;
135
136         CDEBUG(D_IOCTL, "getdata: len %d, add %p\n", len, *data);
137
138         OBD_ALLOC(tmp, void *, len);
139         if ( !tmp )
140                 return -ENOMEM;
141         
142         memset(tmp, 0, len);
143         if ( copy_from_user(tmp, *data, len)) {
144                 OBD_FREE(tmp,len);
145                 return -EFAULT;
146         }
147         *data = tmp;
148
149         return 0;
150 }
151
152 /* to control /dev/obdNNN */
153 static int obd_class_ioctl (struct inode * inode, struct file * filp, 
154                             unsigned int cmd, unsigned long arg)
155 {
156         int err, i_ino, dev;
157         struct obd_device *obddev;
158         struct obd_conn conn;
159         long int cli_id; /* connect, disconnect */
160
161         if (!inode)
162                 return -EINVAL;
163
164         dev = MINOR(inode->i_rdev);
165         if (dev > MAX_OBD_DEVICES)
166                 return -ENODEV;
167         obddev = &obd_dev[dev];
168         conn.oc_dev = obddev;
169
170         switch (cmd) {
171         case OBD_IOC_ATTACH: {
172                 struct obd_type *type;
173                 struct oic_attach input;
174
175                 /* have we attached a type to this device */
176                 if ( obddev->obd_type || (obddev->obd_flags & OBD_ATTACHED) ){
177                         CDEBUG(D_IOCTL, "OBD Device %d already attached to type %s.\n", dev, obddev->obd_type->typ_name);
178                         return -EINVAL;
179                 }
180
181                 /* get data structures */
182                 err = copy_from_user(&input, (void *) arg, sizeof(input));
183                 if (err)
184                         return err;
185
186                 if ( (err = getdata(input.att_typelen + 1, &input.att_type)) )
187                         return err;
188
189                 /* find the type */
190                 err = -EINVAL;
191                 type = obd_nm_to_type(input.att_type);
192                 OBD_FREE(input.att_type, input.att_typelen + 1);
193                 if ( !type ) {
194                         printk("Unknown obd type dev %d\n", dev);
195                         return err;
196                 }
197                 obddev->obd_type = type;
198                 
199                 /* get the attach data */
200                 if ( (err = getdata(input.att_datalen, &input.att_data)) ) {
201                         return err;
202                 }
203
204                 INIT_LIST_HEAD(&obddev->obd_gen_clients);
205                 obddev->obd_multi_count = 0;
206
207                 CDEBUG(D_IOCTL, "Attach %d,  datalen %d, type %s\n", 
208                        dev, input.att_datalen, obddev->obd_type->typ_name);
209                 if (!obddev->obd_type->typ_ops || !OBP(obddev,attach)) {
210                         obddev->obd_flags |=  OBD_ATTACHED;
211                         type->typ_refcnt++;
212                         MOD_INC_USE_COUNT;
213                         return 0;
214                 }
215
216                 /* do the attach */
217                 err = OBP(obddev,attach)(obddev,  
218                                          input.att_datalen, input.att_data);
219                 OBD_FREE(input.att_data, input.att_datalen);
220
221                 if ( err ) {
222                         obddev->obd_flags &= ~OBD_ATTACHED;
223                         obddev->obd_type = NULL;
224                 } else {
225                         obddev->obd_flags |=  OBD_ATTACHED;
226                         type->typ_refcnt++;
227                         MOD_INC_USE_COUNT;
228                 }
229                 return err;
230         }
231
232         case OBD_IOC_DETACH: {
233
234                 if (obddev->obd_flags & OBD_SET_UP)
235                         return -EINVAL;
236                 if (! (obddev->obd_flags & OBD_ATTACHED) )
237                         return -EINVAL;
238                 if ( !list_empty(&obddev->obd_gen_clients) ) 
239                         return -EINVAL;
240
241                 obddev->obd_flags &= ~OBD_ATTACHED;
242                 obddev->obd_type->typ_refcnt--;
243                 obddev->obd_type = NULL;
244                 MOD_DEC_USE_COUNT;
245                 return 0;
246         }
247
248
249         case OBD_IOC_FORMAT: {
250                 struct ioc_format {
251                         int format_datalen;
252                         void *format_data;
253                 } input;
254
255                 /* have we attached a type to this device */
256                 if ( !obddev->obd_type ) {
257                         CDEBUG(D_IOCTL, "OBD Device %d has no type.\n", dev);
258                         return -EINVAL;
259                 }
260
261                 /* get main structure */
262                 err = copy_from_user(&input, (void *) arg, sizeof(input));
263                 if (err) 
264                         return err;
265
266                 err = getdata(input.format_datalen, &input.format_data);
267                 if (err) 
268                         return err;
269
270                 if (!obddev->obd_type->typ_ops || 
271                     !obddev->obd_type->typ_ops->o_format )
272                         return -EOPNOTSUPP;
273
274                 /* do the format */
275                 CDEBUG(D_IOCTL, "Format %d, type %s\n", dev, 
276                        obddev->obd_type->typ_name);
277                 err = obddev->obd_type->typ_ops->o_format
278                         (obddev, input.format_datalen, input.format_data);
279
280                 OBD_FREE(input.format_data, input.format_datalen);
281                 return err;
282         }
283         case OBD_IOC_PARTITION: {
284                 struct ioc_part {
285                         int part_datalen;
286                         void *part_data;
287                 } input;
288
289                 /* have we attached a type to this device */
290                 if ( !obddev->obd_type ) {
291                         CDEBUG(D_IOCTL, "OBD Device %d has no type.\n", dev);
292                         return -EINVAL;
293                 }
294
295                 /* get main structure */
296                 err = copy_from_user(&input, (void *) arg, sizeof(input));
297                 if (err) 
298                         return err;
299
300                 err = getdata(input.part_datalen, &input.part_data);
301                 if (err) 
302                         return err;
303
304                 if (!obddev->obd_type->typ_ops || 
305                     !obddev->obd_type->typ_ops->o_partition )
306                         return -EOPNOTSUPP;
307
308                 /* do the partition */
309                 CDEBUG(D_IOCTL, "Partition %d, type %s\n", dev, 
310                        obddev->obd_type->typ_name);
311                 err = obddev->obd_type->typ_ops->o_partition
312                         (obddev, input.part_datalen, input.part_data);
313
314                 OBD_FREE(input.part_data, input.part_datalen);
315                 return err;
316         }
317
318         case OBD_IOC_COPY: {
319                 struct ioc_mv_s mvdata;
320                 struct ioc_part {
321                         int part_datalen;
322                         void *part_data;
323                 } input;
324                 obdattr *srcoa, *tgtoa;
325
326                 if ( (!(obddev->obd_flags & OBD_SET_UP)) ||
327                      (!(obddev->obd_flags & OBD_ATTACHED))) {
328                         CDEBUG(D_IOCTL, "Device not attached or set up\n");
329                         return -EINVAL;
330                 }
331
332                 /* get main structure */
333                 err = copy_from_user(&input, (void *) arg, sizeof(input));
334                 if (err) 
335                         return err;
336
337
338                 err = copy_from_user(&mvdata, input.part_data, sizeof(mvdata));
339                 if (err) 
340                         return err;
341
342                 if (!obddev->obd_type->typ_ops || 
343                     !obddev->obd_type->typ_ops->o_copy )
344                         return -EOPNOTSUPP;
345
346                 /* do the partition */
347                 CDEBUG(D_IOCTL, "Copy %d, type %s src %ld tgt %ld\n", dev, 
348                        obddev->obd_type->typ_name, mvdata.src, mvdata.tgt);
349
350                 conn.oc_id = mvdata.conn_id;
351                 srcoa = obd_oa_fromid(&conn, mvdata.src);
352                 if ( !srcoa ) 
353                         return -ENOENT;
354                 tgtoa = obd_oa_fromid(&conn, mvdata.tgt);
355                 if ( ! tgtoa ) {
356                         obd_free_oa(srcoa);
357                         return -ENOMEM;
358                 }
359
360                 err = obddev->obd_type->typ_ops->o_copy(&conn,srcoa, tgtoa);
361
362                 obd_free_oa(srcoa);
363                 obd_free_oa(tgtoa);
364                 return err;
365         }
366         case OBD_IOC_MIGR: {
367                 struct ioc_mv_s mvdata;
368                 struct ioc_part {
369                         int part_datalen;
370                         void *part_data;
371                 } input;
372                 obdattr *srcoa, *tgtoa;
373
374                 if ( (!(obddev->obd_flags & OBD_SET_UP)) ||
375                      (!(obddev->obd_flags & OBD_ATTACHED))) {
376                         CDEBUG(D_IOCTL, "Device not attached or set up\n");
377                         return -EINVAL;
378                 }
379
380                 /* get main structure */
381                 err = copy_from_user(&input, (void *) arg, sizeof(input));
382                 if (err) 
383                         return err;
384
385
386                 CDEBUG(D_IOCTL, "Migrate copying %d\n", sizeof(mvdata));
387                 err = copy_from_user(&mvdata, input.part_data, sizeof(mvdata));
388                 if (err) 
389                         return err;
390
391                 if (!obddev->obd_type->typ_ops || 
392                     !obddev->obd_type->typ_ops->o_copy )
393                         return -EOPNOTSUPP;
394
395                 /* do the partition */
396                 CDEBUG(D_IOCTL, "Migrate %d, type %s conn %d src %ld tgt %ld\n", dev, 
397                        obddev->obd_type->typ_name, mvdata.conn_id, mvdata.src, mvdata.tgt);
398
399
400                 if ( ! (srcoa = obd_empty_oa()) ) 
401                         return -ENOMEM;
402                 if ( ! (tgtoa = obd_empty_oa()) ) {
403                         obd_free_oa(srcoa);
404                         return -ENOMEM;
405                 }
406
407                 srcoa->i_ino = mvdata.src;
408                 tgtoa->i_ino = mvdata.tgt;
409
410                 conn.oc_id = mvdata.conn_id;
411
412                 err = obddev->obd_type->typ_ops->o_migrate(&conn, srcoa, tgtoa);
413
414                 obd_free_oa(srcoa);
415                 obd_free_oa(tgtoa);
416                 return err;
417         }
418
419         case OBD_IOC_SETUP: {
420                 struct ioc_setup {
421                         int setup_datalen;
422                         void *setup_data;
423                 } input;
424
425                 /* have we attached a type to this device */
426                 if (!(obddev->obd_flags & OBD_ATTACHED)) {
427                         CDEBUG(D_IOCTL, "OBD Device %d has no type.\n", dev);
428                         return -EINVAL;
429                 }
430
431                 /* has this been done already? */
432                 if ( obddev->obd_flags & OBD_SET_UP ) {
433                         CDEBUG(D_IOCTL, "Device %d already setup (type %s)\n",
434                                dev, obddev->obd_type->typ_name);
435                         return -EINVAL;
436                 }
437
438                 /* get main structure */
439                 err = copy_from_user(&input, (void *) arg, sizeof(input));
440                 if (err) 
441                         return err;
442
443                 err = getdata(input.setup_datalen, &input.setup_data);
444                 if (err) 
445                         return err;
446
447
448                 /* do the setup */
449                 CDEBUG(D_IOCTL, "Setup %d, type %s\n", dev, 
450                        obddev->obd_type->typ_name);
451                 if ( !obddev->obd_type->typ_ops || 
452                      !obddev->obd_type->typ_ops->o_setup ) {
453                         obddev->obd_flags |= OBD_SET_UP;
454                         return 0;
455                 }
456
457                 err = obddev->obd_type->typ_ops->o_setup
458                         (obddev, input.setup_datalen, input.setup_data);
459
460                 if ( err ) 
461                         obddev->obd_flags &= ~OBD_SET_UP;
462                 else {
463                         obddev->obd_type->typ_refcnt++;
464                         obddev->obd_flags |= OBD_SET_UP;
465                 }
466                 return err;
467         }
468         case OBD_IOC_CLEANUP: {
469                 int rc;
470
471                 /* has this minor been registered? */
472                 if (!obddev->obd_type)
473                         return -ENODEV;
474
475                 if ( !obddev->obd_type->typ_refcnt ) 
476                         printk("OBD_CLEANUP: refcount wrap!\n");
477
478                 if ( !obddev->obd_flags & OBD_SET_UP ) 
479                         return -EINVAL;
480
481                 if ( !obddev->obd_type->typ_ops->o_cleanup )
482                         goto cleanup_out;
483
484                 /* cleanup has no argument */
485                 rc = OBP(obddev, cleanup)(obddev);
486                 if ( rc )
487                         return rc;
488
489         cleanup_out: 
490                 obddev->obd_flags &= ~OBD_SET_UP;
491                 obddev->obd_type->typ_refcnt--;
492                 return 0;
493         }
494         case OBD_IOC_CONNECT:
495         {
496
497                 if ( (!(obddev->obd_flags & OBD_SET_UP)) ||
498                      (!(obddev->obd_flags & OBD_ATTACHED))) {
499                         CDEBUG(D_IOCTL, "Device not attached or set up\n");
500                         return -EINVAL;
501                 }
502
503                 
504                 if (obddev->obd_type->typ_ops->o_connect(&conn))
505                         return -EINVAL;
506
507                 return copy_to_user((int *)arg, &conn.oc_id,
508                                     sizeof(int));
509         }
510         case OBD_IOC_DISCONNECT:
511                 /* frees data structures */
512                 /* has this minor been registered? */
513                 if (!obddev->obd_type)
514                         return -ENODEV;
515
516                 get_user(cli_id, (int *) arg);
517                 conn.oc_id = cli_id;
518
519                 OBP(obddev, disconnect)(&conn);
520                 return 0;
521
522         case OBD_IOC_SYNC: {
523                 /* sync doesn't need a connection ID, because it knows
524                  * what device it was called on, and can thus get the
525                  * superblock that it needs. */
526                 /* has this minor been registered? */
527                 if (!obddev->obd_type)
528                         return -ENODEV;
529
530                 if (!obddev->u.ext2.ext2_sb || !obddev->u.ext2.ext2_sb->s_dev) {
531                         CDEBUG(D_IOCTL, "fatal: device not initialized.\n");
532                         err = -EINVAL;
533                 } else {
534                         if ((err = fsync_dev(obddev->u.ext2.ext2_sb->s_dev)))
535                                 CDEBUG(D_IOCTL, "sync: fsync_dev failure\n");
536                         else
537                                 CDEBUG(D_IOCTL, "sync: success\n");
538                 }
539
540                 return put_user(err, (int *) arg);
541         }
542         case OBD_IOC_CREATE: {
543                 int err;
544                 struct oic_create_s foo;
545
546                 if ( copy_from_user(&foo, (const void *)arg, sizeof(foo)) )
547                         return -EFAULT;
548
549                 /* has this minor been registered? */
550                 if ( !(obddev->obd_flags & OBD_ATTACHED) ||
551                      !(obddev->obd_flags & OBD_SET_UP))
552                         return -ENODEV;
553                 conn.oc_id = foo.conn_id;
554
555                 i_ino = OBP(obddev, create)(&conn, foo.prealloc, &err);
556                 if (err) {
557                         CDEBUG(D_IOCTL, "create: obd_inode_new failure\n");
558                         /* 0 is the only error value */
559                         return put_user(0, (int *) arg);
560                 }
561
562                 return put_user(i_ino, (int *) arg);
563         }
564         case OBD_IOC_DESTROY:
565         {
566                 struct destroy_s {
567                         unsigned int conn_id;
568                         unsigned int ino;
569                 } destroy;
570                 obdattr *oa;
571                 int rc;
572                 
573                 if ( ! (oa = obd_empty_oa()) ) 
574                         return -ENOMEM;
575
576                 /* has this minor been registered? */
577                 if (!obddev->obd_type)
578                         return -ENODEV;
579
580
581                 copy_from_user(&destroy, (int *)arg, sizeof(struct destroy_s));
582                 if ( !obddev->obd_type ||
583                      !obddev->obd_type->typ_ops->o_destroy)
584                         return -EINVAL;
585
586                 oa->i_ino = destroy.ino;
587                 conn.oc_id = destroy.conn_id;
588                 rc = obddev->obd_type->typ_ops->o_destroy(&conn, oa);
589                 OBD_FREE(oa, sizeof(*oa));
590                 return rc;
591         }
592         case OBD_IOC_SETATTR:
593         {
594                 struct oic_attr_s foo;
595                 obdattr *oa;
596                 int rc;
597
598                 if ( ! (oa = obd_empty_oa()) ) 
599                         return -ENOMEM;
600
601                 /* has this minor been registered? */
602                 if (!obddev->obd_type)
603                         return -ENODEV;
604
605                 rc = copy_from_user(&foo, (int *)arg, sizeof(foo));
606                 if (rc)
607                         return rc;
608
609                 if ( !obddev->obd_type ||
610                      !obddev->obd_type->typ_ops->o_setattr)
611                         return -EINVAL;
612                 
613                 oa->i_ino = foo.ino;
614                 inode_setattr(oa, &foo.iattr);
615                 conn.oc_id = foo.conn_id;
616                 rc = obddev->obd_type->typ_ops->o_setattr(&conn, oa);
617                 OBD_FREE(oa, sizeof(*oa));
618                 return rc;
619         }
620
621         case OBD_IOC_GETATTR:
622         {
623                 int rc;
624                 struct oic_getattr {
625                         unsigned int conn_id;
626                         unsigned long ino;
627                 } foo;
628                 struct iattr iattr;
629                 obdattr *oa;
630
631                 rc = copy_from_user(&foo, (int *)arg, sizeof(foo));
632                 if (rc)
633                         return rc;
634
635                 conn.oc_id = foo.conn_id;
636                 oa = obd_oa_fromid(&conn, foo.ino);
637                 if ( !oa ) 
638                         return -ENOENT;
639
640                 inode_to_iattr(oa, &iattr);
641                 rc = copy_to_user((int *)arg, &iattr, sizeof(iattr));
642                 return rc;
643         }
644
645         case OBD_IOC_READ:
646         {
647                 obdattr *oa = NULL;
648                 int rc;
649                 struct oic_rw_s rw_s;  /* read, write ioctl str */
650
651                 rc = copy_from_user(&rw_s, (int *)arg, sizeof(rw_s));
652                 if ( rc ) 
653                         goto READ_OUT;
654
655                 
656                 conn.oc_id = rw_s.conn_id;
657                 if ( ! (oa = obd_oa_fromid(&conn, rw_s.id)) ) 
658                         return -ENOENT;
659
660                 rc = -EINVAL;
661                 if ( !obddev->obd_type->typ_ops || 
662                      !obddev->obd_type->typ_ops->o_read ) 
663                         goto READ_OUT;
664
665                 rc = obddev->obd_type->typ_ops->o_read
666                         (&conn, oa, rw_s.buf, &rw_s.count, rw_s.offset);
667                 if ( rc ) 
668                         goto READ_OUT;
669
670                 rc = copy_to_user((int*)arg, &rw_s.count, sizeof(rw_s.count));
671
672         READ_OUT:
673                 if ( oa ) 
674                         OBD_FREE(oa, sizeof(*oa));
675                 return rc;
676         }
677
678         case OBD_IOC_WRITE: {
679                 obdattr *oa = NULL;
680                 int rc;
681                 struct oic_rw_s rw_s;  /* read, write ioctl str */
682
683                 rc = copy_from_user(&rw_s, (int *)arg, sizeof(rw_s));
684                 if ( rc ) 
685                         goto WRITE_OUT;
686
687                 conn.oc_id = rw_s.conn_id;
688                 oa = obd_oa_fromid(&conn, rw_s.id);
689                 if ( !oa ) 
690                         return -ENOENT;
691
692                 rc = -EINVAL;
693                 if ( !obddev->obd_type->typ_ops || 
694                      !obddev->obd_type->typ_ops->o_write ) 
695                         goto WRITE_OUT;
696
697                 rc = obddev->obd_type->typ_ops->o_write
698                         (&conn, oa, rw_s.buf, &rw_s.count, rw_s.offset);
699                 if ( rc ) 
700                         goto WRITE_OUT;
701
702                 rc = copy_to_user((int*)arg, &rw_s.count, sizeof(rw_s.count));
703
704         WRITE_OUT:
705                 OBD_FREE(oa, sizeof(*oa));
706                 return rc;
707         }
708         case OBD_IOC_PREALLOCATE: {
709                 struct oic_prealloc_s prealloc;
710                 int rc;
711
712                 /* has this minor been registered? */
713                 if (!obddev->obd_type)
714                         return -ENODEV;
715
716
717                 rc = copy_from_user(&prealloc, (int *)arg, sizeof(prealloc));
718                 if (rc) 
719                         return -ENOMEM;
720
721                 if ( !(obddev->obd_flags & OBD_ATTACHED) ||
722                      !(obddev->obd_flags & OBD_SET_UP)) {
723                         CDEBUG(D_IOCTL, "fatal: device not initialized.\n");
724                         return -EINVAL;
725                 }
726
727                 if (!obddev->obd_type || 
728                     !obddev->obd_type->typ_ops->o_preallocate)
729                         return -EOPNOTSUPP;
730                 conn.oc_id = prealloc.cli_id;
731                 rc = obddev->obd_type->typ_ops->o_preallocate
732                         (&conn, &prealloc.alloc, prealloc.inodes);
733                 if ( rc ) 
734                         return rc;
735
736                 return copy_to_user((int *)arg, &prealloc, sizeof(prealloc));
737         }
738         case OBD_IOC_STATFS:
739         {
740                 struct statfs *tmp;
741                 unsigned int conn_id;
742                 struct statfs buf;
743                 int rc;
744
745                 /* has this minor been registered? */
746                 if (!obddev->obd_type)
747                         return -ENODEV;
748
749                 tmp = (void *)arg + sizeof(unsigned int);
750                 get_user(conn_id, (int *) arg);
751                 if ( !obddev->obd_type ||
752                      !obddev->obd_type->typ_ops->o_statfs)
753                         return -EINVAL;
754
755                 conn.oc_id = conn_id;
756                 rc = obddev->obd_type->typ_ops->o_statfs(&conn, &buf);
757                 if ( rc ) 
758                         return rc;
759                 rc = copy_to_user(tmp, &buf, sizeof(buf));
760                 return rc;
761                 
762         }
763         default:
764                 printk("invalid ioctl: cmd = %x, arg = %lx\n", cmd, arg);
765                 return -ENOTTY;
766         }
767 }
768
769 /* Driver interface done, utility functions follow */
770
771 int obd_register_type(struct obd_ops *ops, char *nm)
772 {
773         struct obd_type *type;
774
775
776         if (obd_init_magic != 0x11223344) {
777                 EXIT;
778                 return -EINVAL;
779         }
780
781         if  ( obd_nm_to_type(nm) ) {
782                 CDEBUG(D_IOCTL, "Type %s already registered\n", nm);
783                 EXIT;
784                 return -1;
785         }
786         
787         OBD_ALLOC(type, struct obd_type * , sizeof(*type));
788         if ( !type ) {
789                 EXIT;
790                 return -ENOMEM;
791         }
792         memset(type, 0, sizeof(*type));
793         INIT_LIST_HEAD(&type->typ_chain);
794         MOD_INC_USE_COUNT;
795         list_add(&type->typ_chain, obd_types.next);
796         type->typ_ops = ops;
797         type->typ_name = nm;
798         EXIT;
799         return 0;
800 }
801         
802 int obd_unregister_type(char *nm)
803 {
804         struct obd_type *type = obd_nm_to_type(nm);
805
806         if ( !type ) {
807                 MOD_DEC_USE_COUNT;
808                 printk("OBD: NO TYPE\n");
809                 EXIT;
810                 return -1;
811         }
812
813         if ( type->typ_refcnt ) {
814                 MOD_DEC_USE_COUNT;
815                 printk("OBD: refcount wrap\n");
816                 EXIT;
817                 return -1;
818         }
819
820         list_del(&type->typ_chain);
821         OBD_FREE(type, sizeof(*type));
822         MOD_DEC_USE_COUNT;
823         return 0;
824 }
825
826 /* declare character device */
827 static struct file_operations obd_psdev_fops = {
828         NULL,                  /* llseek */
829         NULL,                  /* read */
830         NULL,                  /* write */
831         NULL,                  /* presto_psdev_readdir */
832         NULL,                  /* poll */
833         obd_class_ioctl,       /* ioctl */
834         NULL,                  /* presto_psdev_mmap */
835         obd_class_open,        /* open */
836         NULL,
837         obd_class_release,     /* release */
838         NULL,                  /* fsync */
839         NULL,                  /* fasync */
840         NULL,                  /* check_media_change */
841         NULL,                  /* revalidate */
842         NULL                   /* lock */
843 };
844
845
846 /* modules setup */
847
848 int init_obd(void)
849 {
850         int i;
851
852         printk(KERN_INFO "OBD class driver  v0.002, braam@stelias.com\n");
853         
854         INIT_LIST_HEAD(&obd_types);
855         
856         if (register_chrdev(OBD_PSDEV_MAJOR,"obd_psdev", 
857                             &obd_psdev_fops)) {
858                 printk(KERN_ERR "obd_psdev: unable to get major %d\n", 
859                        OBD_PSDEV_MAJOR);
860                 return -EIO;
861         }
862
863         for (i = 0; i < MAX_OBD_DEVICES; i++) {
864                 memset(&(obd_dev[i]), 0, sizeof(obd_dev[i]));
865                 obd_dev[i].obd_minor = i;
866                 INIT_LIST_HEAD(&obd_dev[i].obd_gen_clients);
867         }
868
869         obd_sysctl_init();
870         obd_init_magic = 0x11223344;
871         return 0;
872 }
873
874 EXPORT_SYMBOL(obd_register_type);
875 EXPORT_SYMBOL(obd_unregister_type);
876
877 EXPORT_SYMBOL(obd_print_entry);
878 EXPORT_SYMBOL(obd_debug_level);
879 EXPORT_SYMBOL(obd_dev);
880
881 EXPORT_SYMBOL(gen_connect);
882 EXPORT_SYMBOL(gen_client);
883 EXPORT_SYMBOL(gen_cleanup);
884 EXPORT_SYMBOL(gen_disconnect);
885 EXPORT_SYMBOL(gen_copy_data); 
886
887 /* EXPORT_SYMBOL(gen_multi_attach); */
888 EXPORT_SYMBOL(gen_multi_setup);
889 EXPORT_SYMBOL(gen_multi_cleanup);
890
891
892 #ifdef MODULE
893 int init_module(void)
894 {
895         return init_obd();
896 }
897
898 void cleanup_module(void)
899 {
900         int i;
901         ENTRY;
902
903         unregister_chrdev(OBD_PSDEV_MAJOR, "obd_psdev");
904         for (i = 0; i < MAX_OBD_DEVICES; i++) {
905                 struct obd_device *obddev = &obd_dev[i];
906                 if ( obddev->obd_type && 
907                      (obddev->obd_flags & OBD_SET_UP) &&
908                      obddev->obd_type->typ_ops->o_detach ) {
909                         OBP(obddev, detach)(obddev);
910                 } 
911         }
912
913
914         obd_sysctl_clean();
915         obd_init_magic = 0;
916 }
917 #endif