Whamcloud - gitweb
demos/snaprest.sh: ensure client is disconnected after snaprestore
[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, "Dev %d refcount now %d\n", dev,
78                obd_dev[dev].obd_refcnt);
79
80         MOD_INC_USE_COUNT;
81         EXIT;
82         return 0;
83 }
84
85 /* called when closing /dev/obdNNN */
86 static int obd_class_release(struct inode * inode, struct file * file)
87 {
88         int dev;
89         ENTRY;
90
91         if (!inode)
92                 return -EINVAL;
93         dev = MINOR(inode->i_rdev);
94         if (dev >= MAX_OBD_DEVICES)
95                 return -ENODEV;
96         fsync_dev(inode->i_rdev);
97         if (obd_dev[dev].obd_refcnt <= 0)
98                 printk(KERN_ALERT "obd_class_release: refcount(%d) <= 0\n",
99                        obd_dev[dev].obd_refcnt);
100         obd_dev[dev].obd_refcnt--;
101
102         CDEBUG(D_PSDEV, "Dev %d refcount now %d\n", dev,
103                obd_dev[dev].obd_refcnt);
104         MOD_DEC_USE_COUNT;
105
106         EXIT;
107         return 0;
108 }
109
110 /* support function */
111 static struct obd_type *obd_nm_to_type(char *nm) 
112 {
113         struct list_head *tmp;
114         struct obd_type *type;
115         CDEBUG(D_IOCTL, "SEARCH %s\n", nm);
116         
117         tmp = &obd_types;
118         while ( (tmp = tmp->next) != &obd_types ) {
119                 type = list_entry(tmp, struct obd_type, typ_chain);
120                 CDEBUG(D_IOCTL, "TYP %s\n", type->typ_name);
121                 if (strlen(type->typ_name) == strlen(nm) &&
122                     strcmp(type->typ_name, nm) == 0 ) {
123                         return type;
124                 }
125         }
126         return NULL;
127 }
128
129
130 static int getdata(int len, void **data)
131 {
132         void *tmp = NULL;
133
134         if (!len) 
135                 return 0;
136
137         CDEBUG(D_IOCTL, "getdata: len %d, add %p\n", len, *data);
138
139         OBD_ALLOC(tmp, void *, len);
140         if ( !tmp )
141                 return -ENOMEM;
142         
143         memset(tmp, 0, len);
144         if ( copy_from_user(tmp, *data, len)) {
145                 OBD_FREE(tmp,len);
146                 return -EFAULT;
147         }
148         *data = tmp;
149
150         return 0;
151 }
152
153 /* to control /dev/obdNNN */
154 static int obd_class_ioctl (struct inode * inode, struct file * filp, 
155                             unsigned int cmd, unsigned long arg)
156 {
157         int err, i_ino, dev;
158         struct obd_device *obddev;
159         struct obd_conn conn;
160         long int cli_id; /* connect, disconnect */
161
162         if (!inode)
163                 return -EINVAL;
164
165         dev = MINOR(inode->i_rdev);
166         if (dev > MAX_OBD_DEVICES)
167                 return -ENODEV;
168         obddev = &obd_dev[dev];
169         conn.oc_dev = obddev;
170
171         switch (cmd) {
172         case TCGETS:
173                 return -EINVAL;
174         case OBD_IOC_ATTACH: {
175                 struct obd_type *type;
176                 struct oic_generic input;
177
178                 ENTRY;
179                 /* have we attached a type to this device */
180                 if ( obddev->obd_type || (obddev->obd_flags & OBD_ATTACHED) ){
181                         CDEBUG(D_IOCTL,
182                                "OBD Device %d already attached to type %s.\n",
183                                dev, obddev->obd_type->typ_name);
184                         EXIT;
185                         return -EINVAL;
186                 }
187
188                 /* get data structures */
189                 err = copy_from_user(&input, (void *)arg, sizeof(input));
190                 if ( err ) {
191                         EXIT;
192                         return err;
193                 }
194
195                 err = getdata(input.att_typelen + 1, &input.att_type);
196                 if ( err ) {
197                         EXIT;
198                         return err;
199                 }
200
201                 /* find the type */
202                 type = obd_nm_to_type(input.att_type);
203                 OBD_FREE(input.att_type, input.att_typelen + 1);
204                 if ( !type ) {
205                         printk("Unknown obd type dev %d\n", dev);
206                         EXIT;
207                         return -EINVAL;
208                 }
209                 obddev->obd_type = type;
210                 
211                 /* get the attach data */
212                 err = getdata(input.att_datalen, &input.att_data);
213                 if ( err ) {
214                         EXIT;
215                         return err;
216                 }
217
218                 INIT_LIST_HEAD(&obddev->obd_gen_clients);
219                 obddev->obd_multi_count = 0;
220
221                 CDEBUG(D_IOCTL, "Attach %d, datalen %d, type %s\n", 
222                        dev, input.att_datalen, obddev->obd_type->typ_name);
223                 if (!obddev->obd_type->typ_ops || !OBP(obddev,attach)) {
224                         obddev->obd_flags |=  OBD_ATTACHED;
225                         type->typ_refcnt++;
226                         CDEBUG(D_IOCTL, "Dev %d refcount now %d\n", dev,
227                                type->typ_refcnt);
228                         MOD_INC_USE_COUNT;
229                         EXIT;
230                         return 0;
231                 }
232
233                 /* do the attach */
234                 err = OBP(obddev,attach)(obddev,  
235                                          input.att_datalen, input.att_data);
236                 OBD_FREE(input.att_data, input.att_datalen);
237
238                 if ( err ) {
239                         obddev->obd_flags &= ~OBD_ATTACHED;
240                         obddev->obd_type = NULL;
241                         EXIT;
242                 } else {
243                         obddev->obd_flags |=  OBD_ATTACHED;
244                         type->typ_refcnt++;
245                         CDEBUG(D_IOCTL, "Dev %d refcount now %d\n", dev,
246                                type->typ_refcnt);
247                         MOD_INC_USE_COUNT;
248                         EXIT;
249                 }
250                 return err;
251         }
252
253         case OBD_IOC_DETACH: {
254
255                 ENTRY;
256                 if (obddev->obd_flags & OBD_SET_UP) {
257                         EXIT;
258                         return -EINVAL;
259                 }
260                 if (! (obddev->obd_flags & OBD_ATTACHED) ) {
261                         EXIT;
262                         return -EINVAL;
263                 }
264                 if ( !list_empty(&obddev->obd_gen_clients) ) {
265                         EXIT;
266                         return -EINVAL;
267                 }
268
269                 CDEBUG(D_IOCTL, "Detach %d, type %s\n", dev,
270                        obddev->obd_type->typ_name);
271                 obddev->obd_flags &= ~OBD_ATTACHED;
272                 obddev->obd_type->typ_refcnt--;
273                 CDEBUG(D_IOCTL, "Dev %d refcount now %d\n", dev,
274                        obddev->obd_type->typ_refcnt);
275                 obddev->obd_type = NULL;
276                 MOD_DEC_USE_COUNT;
277                 EXIT;
278                 return 0;
279         }
280
281         case OBD_IOC_FORMAT: {
282                 struct ioc_format {
283                         int format_datalen;
284                         void *format_data;
285                 } input;
286
287                 /* have we attached a type to this device */
288                 if ( !obddev->obd_type ) {
289                         CDEBUG(D_IOCTL, "OBD Device %d has no type.\n", dev);
290                         return -EINVAL;
291                 }
292
293                 /* get main structure */
294                 err = copy_from_user(&input, (void *) arg, sizeof(input));
295                 if (err) 
296                         return err;
297
298                 err = getdata(input.format_datalen, &input.format_data);
299                 if (err) 
300                         return err;
301
302                 if (!obddev->obd_type->typ_ops || 
303                     !obddev->obd_type->typ_ops->o_format )
304                         return -EOPNOTSUPP;
305
306                 /* do the format */
307                 CDEBUG(D_IOCTL, "Format %d, type %s\n", dev, 
308                        obddev->obd_type->typ_name);
309                 err = obddev->obd_type->typ_ops->o_format(obddev,
310                                                           input.format_datalen,
311                                                           input.format_data);
312
313                 OBD_FREE(input.format_data, input.format_datalen);
314                 return err;
315         }
316         case OBD_IOC_PARTITION: {
317                 struct ioc_part {
318                         int part_datalen;
319                         void *part_data;
320                 } input;
321
322                 /* have we attached a type to this device */
323                 if ( !obddev->obd_type ) {
324                         CDEBUG(D_IOCTL, "OBD Device %d has no type.\n", dev);
325                         return -EINVAL;
326                 }
327
328                 /* get main structure */
329                 err = copy_from_user(&input, (void *) arg, sizeof(input));
330                 if (err) 
331                         return err;
332
333                 err = getdata(input.part_datalen, &input.part_data);
334                 if (err) 
335                         return err;
336
337                 if (!obddev->obd_type->typ_ops || 
338                     !obddev->obd_type->typ_ops->o_partition )
339                         return -EOPNOTSUPP;
340
341                 /* do the partition */
342                 CDEBUG(D_IOCTL, "Partition %d, type %s\n", dev, 
343                        obddev->obd_type->typ_name);
344                 err = obddev->obd_type->typ_ops->o_partition(obddev,
345                                                              input.part_datalen,
346                                                              input.part_data);
347
348                 OBD_FREE(input.part_data, input.part_datalen);
349                 return err;
350         }
351
352         case OBD_IOC_COPY: {
353                 struct ioc_mv_s mvdata;
354                 struct ioc_part {
355                         int part_datalen;
356                         void *part_data;
357                 } input;
358                 obdattr *srcoa, *tgtoa;
359
360                 if ( (!(obddev->obd_flags & OBD_SET_UP)) ||
361                      (!(obddev->obd_flags & OBD_ATTACHED))) {
362                         CDEBUG(D_IOCTL, "Device not attached or set up\n");
363                         return -EINVAL;
364                 }
365
366                 /* get main structure */
367                 err = copy_from_user(&input, (void *) arg, sizeof(input));
368                 if (err) 
369                         return err;
370
371
372                 err = copy_from_user(&mvdata, input.part_data, sizeof(mvdata));
373                 if (err) 
374                         return err;
375
376                 if (!obddev->obd_type->typ_ops || 
377                     !obddev->obd_type->typ_ops->o_copy )
378                         return -EOPNOTSUPP;
379
380                 /* do the partition */
381                 CDEBUG(D_IOCTL, "Copy %d, type %s src %ld tgt %ld\n", dev, 
382                        obddev->obd_type->typ_name, mvdata.src, mvdata.tgt);
383
384                 conn.oc_id = mvdata.conn_id;
385                 srcoa = obd_oa_fromid(&conn, mvdata.src);
386                 if ( !srcoa ) 
387                         return -ENOENT;
388                 tgtoa = obd_oa_fromid(&conn, mvdata.tgt);
389                 if ( ! tgtoa ) {
390                         obd_free_oa(srcoa);
391                         return -ENOMEM;
392                 }
393
394                 err = obddev->obd_type->typ_ops->o_copy(&conn,srcoa, tgtoa);
395
396                 obd_free_oa(srcoa);
397                 obd_free_oa(tgtoa);
398                 return err;
399         }
400         case OBD_IOC_MIGR: {
401                 struct ioc_mv_s mvdata;
402                 struct ioc_part {
403                         int part_datalen;
404                         void *part_data;
405                 } input;
406                 obdattr *srcoa, *tgtoa;
407
408                 if ( (!(obddev->obd_flags & OBD_SET_UP)) ||
409                      (!(obddev->obd_flags & OBD_ATTACHED))) {
410                         CDEBUG(D_IOCTL, "Device not attached or set up\n");
411                         return -EINVAL;
412                 }
413
414                 /* get main structure */
415                 err = copy_from_user(&input, (void *) arg, sizeof(input));
416                 if (err) 
417                         return err;
418
419
420                 CDEBUG(D_IOCTL, "Migrate copying %d\n", sizeof(mvdata));
421                 err = copy_from_user(&mvdata, input.part_data, sizeof(mvdata));
422                 if (err) 
423                         return err;
424
425                 if (!obddev->obd_type->typ_ops || 
426                     !obddev->obd_type->typ_ops->o_copy )
427                         return -EOPNOTSUPP;
428
429                 /* do the partition */
430                 CDEBUG(D_IOCTL, "Migrate %d, type %s conn %d src %ld tgt %ld\n",
431                        dev, obddev->obd_type->typ_name, mvdata.conn_id,
432                        mvdata.src, mvdata.tgt);
433
434
435                 if ( ! (srcoa = obd_empty_oa()) ) 
436                         return -ENOMEM;
437                 if ( ! (tgtoa = obd_empty_oa()) ) {
438                         obd_free_oa(srcoa);
439                         return -ENOMEM;
440                 }
441
442                 srcoa->i_ino = mvdata.src;
443                 tgtoa->i_ino = mvdata.tgt;
444
445                 conn.oc_id = mvdata.conn_id;
446
447                 err = obddev->obd_type->typ_ops->o_migrate(&conn, tgtoa, srcoa);
448
449                 obd_free_oa(srcoa);
450                 obd_free_oa(tgtoa);
451                 return err;
452         }
453
454         case OBD_IOC_SETUP: {
455                 struct ioc_setup {
456                         int setup_datalen;
457                         void *setup_data;
458                 } input;
459
460                 ENTRY;
461                 /* have we attached a type to this device */
462                 if (!(obddev->obd_flags & OBD_ATTACHED)) {
463                         CDEBUG(D_IOCTL, "OBD Device %d has no type.\n", dev);
464                         EXIT;
465                         return -EINVAL;
466                 }
467
468                 /* has this been done already? */
469                 if ( obddev->obd_flags & OBD_SET_UP ) {
470                         CDEBUG(D_IOCTL, "Device %d already setup (type %s)\n",
471                                dev, obddev->obd_type->typ_name);
472                         EXIT;
473                         return -EINVAL;
474                 }
475
476                 /* get main structure */
477                 err = copy_from_user(&input, (void *) arg, sizeof(input));
478                 if (err) {
479                         EXIT;
480                         return err;
481                 }
482
483                 err = getdata(input.setup_datalen, &input.setup_data);
484                 if (err) {
485                         EXIT;
486                         return err;
487                 }
488
489                 /* do the setup */
490                 CDEBUG(D_IOCTL, "Setup %d, type %s\n", dev, 
491                        obddev->obd_type->typ_name);
492                 if ( !obddev->obd_type->typ_ops || 
493                      !obddev->obd_type->typ_ops->o_setup ) {
494                         obddev->obd_type->typ_refcnt++;
495                         CDEBUG(D_IOCTL, "Dev %d refcount now %d\n",
496                                dev, obddev->obd_type->typ_refcnt);
497                         obddev->obd_flags |= OBD_SET_UP;
498                         EXIT;
499                         return 0;
500                 }
501
502                 err = obddev->obd_type->typ_ops->o_setup(obddev,
503                                                          input.setup_datalen,
504                                                          input.setup_data);
505
506                 if ( err )  {
507                         obddev->obd_flags &= ~OBD_SET_UP;
508                         EXIT;
509                 } else {
510                         obddev->obd_type->typ_refcnt++;
511                         CDEBUG(D_IOCTL, "Dev %d refcount now %d\n",
512                                dev, obddev->obd_type->typ_refcnt);
513                         obddev->obd_flags |= OBD_SET_UP;
514                         EXIT;
515                 }
516                 return err;
517         }
518         case OBD_IOC_CLEANUP: {
519                 ENTRY;
520                 /* has this minor been registered? */
521                 if (!obddev->obd_type) {
522                         EXIT;
523                         return -ENODEV;
524                 }
525
526                 if ( !obddev->obd_type->typ_refcnt )
527                         printk("OBD_CLEANUP: Dev %d refcount wrap (%d)!\n",
528                                dev, obddev->obd_type->typ_refcnt);
529
530                 if ( !obddev->obd_flags & OBD_SET_UP ) {
531                         EXIT;
532                         return -EINVAL;
533                 }
534
535                 if ( !obddev->obd_type->typ_ops->o_cleanup )
536                         goto cleanup_out;
537
538                 /* cleanup has no argument */
539                 err = OBP(obddev, cleanup)(obddev);
540                 if ( err ) {
541                         EXIT;
542                         return err;
543                 }
544
545         cleanup_out: 
546                 obddev->obd_flags &= ~OBD_SET_UP;
547                 obddev->obd_type->typ_refcnt--;
548                 CDEBUG(D_IOCTL, "Dev %d refcount now %d\n", dev,
549                        obddev->obd_type->typ_refcnt);
550                 EXIT;
551                 return 0;
552         }
553         case OBD_IOC_CONNECT:
554         {
555                 if ( (!(obddev->obd_flags & OBD_SET_UP)) ||
556                      (!(obddev->obd_flags & OBD_ATTACHED))) {
557                         CDEBUG(D_IOCTL, "Device not attached or set up\n");
558                         return -EINVAL;
559                 }
560
561                 
562                 if (obddev->obd_type->typ_ops->o_connect(&conn))
563                         return -EINVAL;
564
565                 return copy_to_user((int *)arg, &conn.oc_id,
566                                     sizeof(int));
567         }
568         case OBD_IOC_DISCONNECT:
569                 /* frees data structures */
570                 /* has this minor been registered? */
571                 if (!obddev->obd_type)
572                         return -ENODEV;
573
574                 get_user(cli_id, (int *) arg);
575                 conn.oc_id = cli_id;
576
577                 OBP(obddev, disconnect)(&conn);
578                 return 0;
579
580         case OBD_IOC_SYNC: {
581                 /* sync doesn't need a connection ID, because it knows
582                  * what device it was called on, and can thus get the
583                  * superblock that it needs. */
584                 /* has this minor been registered? */
585                 if (!obddev->obd_type)
586                         return -ENODEV;
587
588                 if (!obddev->u.ext2.ext2_sb || !obddev->u.ext2.ext2_sb->s_dev) {
589                         CDEBUG(D_IOCTL, "fatal: device not initialized.\n");
590                         err = -EINVAL;
591                 } else {
592                         err = fsync_dev(obddev->u.ext2.ext2_sb->s_dev);
593                         if ( err )
594                                 CDEBUG(D_IOCTL, "sync: fsync_dev failure\n");
595                         else
596                                 CDEBUG(D_IOCTL, "sync: success\n");
597                 }
598
599                 return put_user(err, (int *) arg);
600         }
601         case OBD_IOC_CREATE: {
602                 struct oic_create_s foo;
603
604                 if ( copy_from_user(&foo, (const void *)arg, sizeof(foo)) )
605                         return -EFAULT;
606
607                 /* has this minor been registered? */
608                 if ( !(obddev->obd_flags & OBD_ATTACHED) ||
609                      !(obddev->obd_flags & OBD_SET_UP))
610                         return -ENODEV;
611                 conn.oc_id = foo.conn_id;
612
613                 i_ino = OBP(obddev, create)(&conn, foo.prealloc, &err);
614                 if (err) {
615                         CDEBUG(D_IOCTL, "create: obd_inode_new failure\n");
616                         /* 0 is the only error value */
617                         return put_user(0, (int *) arg);
618                 }
619
620                 return put_user(i_ino, (int *) arg);
621         }
622         case OBD_IOC_DESTROY: {
623                 struct destroy_s {
624                         unsigned int conn_id;
625                         unsigned int ino;
626                 } destroy;
627                 obdattr *oa;
628                 
629                 if ( ! (oa = obd_empty_oa()) ) 
630                         return -ENOMEM;
631
632                 /* has this minor been registered? */
633                 if (!obddev->obd_type)
634                         return -ENODEV;
635
636
637                 copy_from_user(&destroy, (int *)arg, sizeof(struct destroy_s));
638                 if ( !obddev->obd_type ||
639                      !obddev->obd_type->typ_ops->o_destroy)
640                         return -EINVAL;
641
642                 oa->i_ino = destroy.ino;
643                 conn.oc_id = destroy.conn_id;
644                 err = obddev->obd_type->typ_ops->o_destroy(&conn, oa);
645                 OBD_FREE(oa, sizeof(*oa));
646                 return err;
647         }
648         case OBD_IOC_SETATTR: {
649                 struct oic_attr_s foo;
650                 obdattr *oa;
651
652                 if ( ! (oa = obd_empty_oa()) ) 
653                         return -ENOMEM;
654
655                 /* has this minor been registered? */
656                 if (!obddev->obd_type)
657                         return -ENODEV;
658
659                 err = copy_from_user(&foo, (int *)arg, sizeof(foo));
660                 if (err)
661                         return err;
662
663                 if ( !obddev->obd_type ||
664                      !obddev->obd_type->typ_ops->o_setattr)
665                         return -EINVAL;
666                 
667                 oa->i_ino = foo.ino;
668                 inode_setattr(oa, &foo.iattr);
669                 conn.oc_id = foo.conn_id;
670                 err = obddev->obd_type->typ_ops->o_setattr(&conn, oa);
671                 OBD_FREE(oa, sizeof(*oa));
672                 return err;
673         }
674
675         case OBD_IOC_GETATTR: {
676                 struct oic_getattr {
677                         unsigned int conn_id;
678                         unsigned long ino;
679                 } foo;
680                 struct iattr iattr;
681                 obdattr *oa;
682
683                 err = copy_from_user(&foo, (int *)arg, sizeof(foo));
684                 if (err)
685                         return err;
686
687                 conn.oc_id = foo.conn_id;
688                 oa = obd_oa_fromid(&conn, foo.ino);
689                 if ( !oa ) 
690                         return -ENOENT;
691
692                 inode_to_iattr(oa, &iattr);
693                 err = copy_to_user((int *)arg, &iattr, sizeof(iattr));
694                 return err;
695         }
696
697         case OBD_IOC_READ: {
698                 obdattr *oa = NULL;
699                 int err;
700                 struct oic_rw_s rw_s;  /* read, write ioctl str */
701
702                 err = copy_from_user(&rw_s, (int *)arg, sizeof(rw_s));
703                 if ( err ) 
704                         goto READ_OUT;
705
706                 
707                 conn.oc_id = rw_s.conn_id;
708                 if ( ! (oa = obd_oa_fromid(&conn, rw_s.id)) ) 
709                         return -ENOENT;
710
711                 err = -EINVAL;
712                 if ( !obddev->obd_type->typ_ops || 
713                      !obddev->obd_type->typ_ops->o_read ) 
714                         goto READ_OUT;
715
716                 err = obddev->obd_type->typ_ops->o_read(&conn, oa, rw_s.buf,
717                                                         &rw_s.count,
718                                                         rw_s.offset);
719                 if ( err ) 
720                         goto READ_OUT;
721
722                 err = copy_to_user((int*)arg, &rw_s.count, sizeof(rw_s.count));
723
724         READ_OUT:
725                 if ( oa ) 
726                         OBD_FREE(oa, sizeof(*oa));
727                 return err;
728         }
729
730         case OBD_IOC_WRITE: {
731                 obdattr *oa = NULL;
732                 struct oic_rw_s rw_s;  /* read, write ioctl str */
733
734                 err = copy_from_user(&rw_s, (int *)arg, sizeof(rw_s));
735                 if ( err ) 
736                         goto WRITE_OUT;
737
738                 conn.oc_id = rw_s.conn_id;
739                 oa = obd_oa_fromid(&conn, rw_s.id);
740                 if ( !oa ) 
741                         return -ENOENT;
742
743                 err = -EINVAL;
744                 if ( !obddev->obd_type->typ_ops || 
745                      !obddev->obd_type->typ_ops->o_write ) 
746                         goto WRITE_OUT;
747
748                 err = obddev->obd_type->typ_ops->o_write(&conn, oa, rw_s.buf,
749                                                          &rw_s.count,
750                                                          rw_s.offset);
751                 if ( err ) 
752                         goto WRITE_OUT;
753
754                 err = copy_to_user((int*)arg, &rw_s.count, sizeof(rw_s.count));
755
756         WRITE_OUT:
757                 OBD_FREE(oa, sizeof(*oa));
758                 return err;
759         }
760         case OBD_IOC_PREALLOCATE: {
761                 struct oic_prealloc_s prealloc;
762
763                 /* has this minor been registered? */
764                 if (!obddev->obd_type)
765                         return -ENODEV;
766
767                 err = copy_from_user(&prealloc, (int *)arg, sizeof(prealloc));
768                 if (err) 
769                         return -ENOMEM;
770
771                 if ( !(obddev->obd_flags & OBD_ATTACHED) ||
772                      !(obddev->obd_flags & OBD_SET_UP)) {
773                         CDEBUG(D_IOCTL, "fatal: device not initialized.\n");
774                         return -EINVAL;
775                 }
776
777                 if (!obddev->obd_type || 
778                     !obddev->obd_type->typ_ops->o_preallocate)
779                         return -EOPNOTSUPP;
780                 conn.oc_id = prealloc.cli_id;
781                 err = obddev->obd_type->typ_ops->o_preallocate(&conn,
782                                                                &prealloc.alloc,
783                                                                prealloc.inodes);
784                 if ( err ) 
785                         return err;
786
787                 return copy_to_user((int *)arg, &prealloc, sizeof(prealloc));
788         }
789         case OBD_IOC_STATFS: {
790                 struct statfs *tmp;
791                 unsigned int conn_id;
792                 struct statfs buf;
793
794                 /* has this minor been registered? */
795                 if (!obddev->obd_type)
796                         return -ENODEV;
797
798                 tmp = (void *)arg + sizeof(unsigned int);
799                 get_user(conn_id, (int *) arg);
800                 if ( !obddev->obd_type ||
801                      !obddev->obd_type->typ_ops->o_statfs)
802                         return -EINVAL;
803
804                 conn.oc_id = conn_id;
805                 err = obddev->obd_type->typ_ops->o_statfs(&conn, &buf);
806                 if ( err ) 
807                         return err;
808                 err = copy_to_user(tmp, &buf, sizeof(buf));
809                 return err;
810                 
811         }
812         default: {
813                 struct obd_type *type;
814                 struct oic_generic input;
815                 void *karg;
816
817                 /* get data structures */
818                 err = copy_from_user(&input, (void *)arg, sizeof(input));
819                 if ( err ) {
820                         EXIT;
821                         return err;
822                 }
823
824                 err = getdata(input.att_typelen + 1, &input.att_type);
825                 if ( err ) {
826                         EXIT;
827                         return err;
828                 }
829
830                 /* find the type */
831                 type = obd_nm_to_type(input.att_type);
832                 OBD_FREE(input.att_type, input.att_typelen + 1);
833                 if ( !type ) {
834                         printk("Unknown obd type dev %d\n", dev);
835                         EXIT;
836                         return -EINVAL;
837                 }
838                 
839                 if ( !type->typ_ops->o_iocontrol ) {
840                         EXIT;
841                         return -EINVAL;
842                 }
843                 conn.oc_id = input.att_connid;
844                 
845                 CDEBUG(D_IOCTL, "Calling ioctl %x for type %s, len %d\n",
846                        cmd, type->typ_name, input.att_datalen);
847
848                 /* get the generic data */
849                 karg = input.att_data;
850                 err = getdata(input.att_datalen, &karg);
851                 if ( err ) {
852                         EXIT;
853                         return err;
854                 }
855
856                 err = type->typ_ops->o_iocontrol(cmd, &conn, input.att_datalen, 
857                                                  karg, input.att_data);
858                 OBD_FREE(karg, input.att_datalen);
859
860                 EXIT;
861                 return err;
862         }
863         }
864 }
865
866 /* Driver interface done, utility functions follow */
867
868 int obd_register_type(struct obd_ops *ops, char *nm)
869 {
870         struct obd_type *type;
871
872
873         if (obd_init_magic != 0x11223344) {
874                 EXIT;
875                 return -EINVAL;
876         }
877
878         if  ( obd_nm_to_type(nm) ) {
879                 CDEBUG(D_IOCTL, "Type %s already registered\n", nm);
880                 EXIT;
881                 return -EEXIST;
882         }
883         
884         OBD_ALLOC(type, struct obd_type * , sizeof(*type));
885         if ( !type ) {
886                 EXIT;
887                 return -ENOMEM;
888         }
889         memset(type, 0, sizeof(*type));
890         INIT_LIST_HEAD(&type->typ_chain);
891         MOD_INC_USE_COUNT;
892         list_add(&type->typ_chain, obd_types.next);
893         type->typ_ops = ops;
894         type->typ_name = nm;
895         EXIT;
896         return 0;
897 }
898         
899 int obd_unregister_type(char *nm)
900 {
901         struct obd_type *type = obd_nm_to_type(nm);
902
903         if ( !type ) {
904                 MOD_DEC_USE_COUNT;
905                 printk("OBD: NO TYPE\n");
906                 EXIT;
907                 return -1;
908         }
909
910         if ( type->typ_refcnt ) {
911                 MOD_DEC_USE_COUNT;
912                 printk("OBD: refcount wrap (%d)\n", type->typ_refcnt);
913                 EXIT;
914                 return -1;
915         }
916
917         list_del(&type->typ_chain);
918         OBD_FREE(type, sizeof(*type));
919         MOD_DEC_USE_COUNT;
920         return 0;
921 }
922
923 /* declare character device */
924 static struct file_operations obd_psdev_fops = {
925         NULL,                  /* llseek */
926         NULL,                  /* read */
927         NULL,                  /* write */
928         NULL,                  /* presto_psdev_readdir */
929         NULL,                  /* poll */
930         obd_class_ioctl,       /* ioctl */
931         NULL,                  /* presto_psdev_mmap */
932         obd_class_open,        /* open */
933         NULL,
934         obd_class_release,     /* release */
935         NULL,                  /* fsync */
936         NULL,                  /* fasync */
937         NULL,                  /* check_media_change */
938         NULL,                  /* revalidate */
939         NULL                   /* lock */
940 };
941
942
943 /* modules setup */
944
945 int init_obd(void)
946 {
947         int i;
948
949         printk(KERN_INFO "OBD class driver  v0.002, braam@stelias.com\n");
950         
951         INIT_LIST_HEAD(&obd_types);
952         
953         if (register_chrdev(OBD_PSDEV_MAJOR,"obd_psdev", 
954                             &obd_psdev_fops)) {
955                 printk(KERN_ERR "obd_psdev: unable to get major %d\n", 
956                        OBD_PSDEV_MAJOR);
957                 return -EIO;
958         }
959
960         for (i = 0; i < MAX_OBD_DEVICES; i++) {
961                 memset(&(obd_dev[i]), 0, sizeof(obd_dev[i]));
962                 obd_dev[i].obd_minor = i;
963                 INIT_LIST_HEAD(&obd_dev[i].obd_gen_clients);
964         }
965
966         obd_sysctl_init();
967         obd_init_magic = 0x11223344;
968         return 0;
969 }
970
971 EXPORT_SYMBOL(obd_register_type);
972 EXPORT_SYMBOL(obd_unregister_type);
973
974 EXPORT_SYMBOL(obd_print_entry);
975 EXPORT_SYMBOL(obd_debug_level);
976 EXPORT_SYMBOL(obd_dev);
977
978 EXPORT_SYMBOL(gen_connect);
979 EXPORT_SYMBOL(gen_client);
980 EXPORT_SYMBOL(gen_cleanup);
981 EXPORT_SYMBOL(gen_disconnect);
982 EXPORT_SYMBOL(gen_copy_data); 
983
984 /* EXPORT_SYMBOL(gen_multi_attach); */
985 EXPORT_SYMBOL(gen_multi_setup);
986 EXPORT_SYMBOL(gen_multi_cleanup);
987
988
989 #ifdef MODULE
990 int init_module(void)
991 {
992         return init_obd();
993 }
994
995 void cleanup_module(void)
996 {
997         int i;
998         ENTRY;
999
1000         unregister_chrdev(OBD_PSDEV_MAJOR, "obd_psdev");
1001         for (i = 0; i < MAX_OBD_DEVICES; i++) {
1002                 struct obd_device *obddev = &obd_dev[i];
1003                 if ( obddev->obd_type && 
1004                      (obddev->obd_flags & OBD_SET_UP) &&
1005                      obddev->obd_type->typ_ops->o_detach ) {
1006                         OBP(obddev, detach)(obddev);
1007                 } 
1008         }
1009
1010
1011         obd_sysctl_clean();
1012         obd_init_magic = 0;
1013 }
1014 #endif