Whamcloud - gitweb
ext2obd/ext2_obd.c, snap/snap.c: change parameters for create
[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         struct obd_device *obddev;
158         struct obd_conn conn;
159         int err, dev;
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 -EBUSY;
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 ( !OBT(obddev) || !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, input.att_datalen,
235                                           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 -EBUSY;
259                 }
260                 if (! (obddev->obd_flags & OBD_ATTACHED) ) {
261                         CDEBUG(D_IOCTL, "Device not attached\n");
262                         EXIT;
263                         return -ENODEV;
264                 }
265                 if ( !list_empty(&obddev->obd_gen_clients) ) {
266                         CDEBUG(D_IOCTL, "Device has connected clients\n");
267                         EXIT;
268                         return -EBUSY;
269                 }
270
271                 CDEBUG(D_IOCTL, "Detach %d, type %s\n", dev,
272                        obddev->obd_type->typ_name);
273                 obddev->obd_flags &= ~OBD_ATTACHED;
274                 obddev->obd_type->typ_refcnt--;
275                 CDEBUG(D_IOCTL, "Dev %d refcount now %d\n", dev,
276                        obddev->obd_type->typ_refcnt);
277                 obddev->obd_type = NULL;
278                 MOD_DEC_USE_COUNT;
279                 EXIT;
280                 return 0;
281         }
282
283         case OBD_IOC_FORMAT: {
284                 struct ioc_format {
285                         int format_datalen;
286                         void *format_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 -ENODEV;
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.format_datalen, &input.format_data);
301                 if (err) 
302                         return err;
303
304                 if ( !OBT(obddev) || !OBP(obddev, format) )
305                         return -EOPNOTSUPP;
306
307                 /* do the format */
308                 CDEBUG(D_IOCTL, "Format %d, type %s\n", dev, 
309                        obddev->obd_type->typ_name);
310                 err = OBP(obddev, format)(obddev, 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 -ENODEV;
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 ( !OBT(obddev) || !OBP(obddev, partition) )
338                         return -EOPNOTSUPP;
339
340                 /* do the partition */
341                 CDEBUG(D_IOCTL, "Partition %d, type %s\n", dev, 
342                        obddev->obd_type->typ_name);
343                 err = OBP(obddev, partition)(obddev, input.part_datalen,
344                                              input.part_data);
345
346                 OBD_FREE(input.part_data, input.part_datalen);
347                 return err;
348         }
349
350         case OBD_IOC_COPY: {
351                 struct ioc_mv_s mvdata;
352                 struct ioc_part {
353                         int part_datalen;
354                         void *part_data;
355                 } input;
356                 obdattr *src, *dst;
357
358                 if ( (!(obddev->obd_flags & OBD_SET_UP)) ||
359                      (!(obddev->obd_flags & OBD_ATTACHED))) {
360                         CDEBUG(D_IOCTL, "Device not attached or set up\n");
361                         return -ENODEV;
362                 }
363
364                 /* get main structure */
365                 err = copy_from_user(&input, (void *) arg, sizeof(input));
366                 if (err) 
367                         return err;
368
369                 err = copy_from_user(&mvdata, input.part_data, sizeof(mvdata));
370                 if (err) 
371                         return err;
372
373                 if ( !OBT(obddev) || !OBP(obddev, copy) )
374                         return -EOPNOTSUPP;
375
376                 /* do the partition */
377                 CDEBUG(D_IOCTL, "Copy %d, type %s dst %ld src %ld\n", dev, 
378                        obddev->obd_type->typ_name, mvdata.dst, mvdata.src);
379
380                 conn.oc_id = mvdata.conn_id;
381                 src = obd_oa_fromid(&conn, mvdata.src);
382                 if ( !src ) 
383                         return -ENOENT;
384                 dst = obd_oa_fromid(&conn, mvdata.dst);
385                 if ( ! dst ) {
386                         obd_free_oa(src);
387                         return -ENOENT;
388                 }
389
390                 err = OBP(obddev, copy)(&conn, dst, src);
391
392                 obd_free_oa(src);
393                 obd_free_oa(dst);
394                 return err;
395         }
396         case OBD_IOC_MIGR: {
397                 struct ioc_mv_s mvdata;
398                 struct ioc_part {
399                         int part_datalen;
400                         void *part_data;
401                 } input;
402                 obdattr *src, *dst;
403
404                 if ( (!(obddev->obd_flags & OBD_SET_UP)) ||
405                      (!(obddev->obd_flags & OBD_ATTACHED))) {
406                         CDEBUG(D_IOCTL, "Device not attached or set up\n");
407                         return -ENODEV;
408                 }
409
410                 /* get main structure */
411                 err = copy_from_user(&input, (void *) arg, sizeof(input));
412                 if (err) 
413                         return err;
414
415
416                 CDEBUG(D_IOCTL, "Migrate copying %d\n", sizeof(mvdata));
417                 err = copy_from_user(&mvdata, input.part_data, sizeof(mvdata));
418                 if (err) 
419                         return err;
420
421                 if ( !OBT(obddev) || !OBP(obddev, migrate) )
422                         return -EOPNOTSUPP;
423
424                 /* do the partition */
425                 CDEBUG(D_IOCTL, "Migrate %d, type %s conn %d src %ld dst %ld\n",
426                        dev, obddev->obd_type->typ_name, mvdata.conn_id,
427                        mvdata.src, mvdata.dst);
428
429
430                 if ( ! (src = obd_empty_oa()) ) 
431                         return -ENOMEM;
432                 if ( ! (dst = obd_empty_oa()) ) {
433                         obd_free_oa(src);
434                         return -ENOMEM;
435                 }
436
437                 src->i_ino = mvdata.src;
438                 dst->i_ino = mvdata.dst;
439
440                 conn.oc_id = mvdata.conn_id;
441
442                 err = OBP(obddev, migrate)(&conn, dst, src);
443
444                 obd_free_oa(src);
445                 obd_free_oa(dst);
446                 return err;
447         }
448
449         case OBD_IOC_SETUP: {
450                 struct ioc_setup {
451                         int setup_datalen;
452                         void *setup_data;
453                 } input;
454
455                 ENTRY;
456                 /* have we attached a type to this device */
457                 if (!(obddev->obd_flags & OBD_ATTACHED)) {
458                         CDEBUG(D_IOCTL, "Device not attached\n");
459                         EXIT;
460                         return -ENODEV;
461                 }
462
463                 /* has this been done already? */
464                 if ( obddev->obd_flags & OBD_SET_UP ) {
465                         CDEBUG(D_IOCTL, "Device %d already setup (type %s)\n",
466                                dev, obddev->obd_type->typ_name);
467                         EXIT;
468                         return -EBUSY;
469                 }
470
471                 /* get main structure */
472                 err = copy_from_user(&input, (void *) arg, sizeof(input));
473                 if (err) {
474                         EXIT;
475                         return err;
476                 }
477
478                 err = getdata(input.setup_datalen, &input.setup_data);
479                 if (err) {
480                         EXIT;
481                         return err;
482                 }
483
484                 /* do the setup */
485                 CDEBUG(D_IOCTL, "Setup %d, type %s\n", dev, 
486                        obddev->obd_type->typ_name);
487                 if ( !OBT(obddev) || !OBP(obddev, setup) ) {
488                         obddev->obd_type->typ_refcnt++;
489                         CDEBUG(D_IOCTL, "Dev %d refcount now %d\n",
490                                dev, obddev->obd_type->typ_refcnt);
491                         obddev->obd_flags |= OBD_SET_UP;
492                         EXIT;
493                         return 0;
494                 }
495
496                 err = OBP(obddev, setup)(obddev, input.setup_datalen,
497                                          input.setup_data);
498
499                 if ( err )  {
500                         obddev->obd_flags &= ~OBD_SET_UP;
501                         EXIT;
502                 } else {
503                         obddev->obd_type->typ_refcnt++;
504                         CDEBUG(D_IOCTL, "Dev %d refcount now %d\n",
505                                dev, obddev->obd_type->typ_refcnt);
506                         obddev->obd_flags |= OBD_SET_UP;
507                         EXIT;
508                 }
509                 return err;
510         }
511         case OBD_IOC_CLEANUP: {
512                 ENTRY;
513                 /* has this minor been registered? */
514                 if (!obddev->obd_type) {
515                         CDEBUG(D_IOCTL, "OBD Device %d has no type.\n", dev);
516                         EXIT;
517                         return -ENODEV;
518                 }
519
520                 if ( !obddev->obd_type->typ_refcnt ) {
521                         printk("OBD_CLEANUP: Dev %d has refcount (%d)!\n",
522                                dev, obddev->obd_type->typ_refcnt);
523                         EXIT;
524                         return -EBUSY;
525                 }
526
527                 if ( (!(obddev->obd_flags & OBD_SET_UP)) ||
528                      (!(obddev->obd_flags & OBD_ATTACHED))) {
529                         CDEBUG(D_IOCTL, "Device not attached or set up\n");
530                         EXIT;
531                         return -ENODEV;
532                 }
533
534                 if ( !OBT(obddev) || !OBP(obddev, cleanup) )
535                         goto cleanup_out;
536
537                 /* cleanup has no argument */
538                 err = OBP(obddev, cleanup)(obddev);
539                 if ( err ) {
540                         EXIT;
541                         return err;
542                 }
543
544         cleanup_out: 
545                 obddev->obd_flags &= ~OBD_SET_UP;
546                 obddev->obd_type->typ_refcnt--;
547                 CDEBUG(D_IOCTL, "Dev %d refcount now %d\n", dev,
548                        obddev->obd_type->typ_refcnt);
549                 EXIT;
550                 return 0;
551         }
552         case OBD_IOC_CONNECT:
553         {
554                 if ( (!(obddev->obd_flags & OBD_SET_UP)) ||
555                      (!(obddev->obd_flags & OBD_ATTACHED))) {
556                         CDEBUG(D_IOCTL, "Device not attached or set up\n");
557                         return -ENODEV;
558                 }
559
560                 if ( !OBT(obddev) || !OBP(obddev, connect) )
561                         return -EOPNOTSUPP;
562                 
563                 err = OBP(obddev, connect)(&conn);
564                 if ( err )
565                         return err;
566
567                 return copy_to_user((int *)arg, &conn.oc_id,
568                                     sizeof(int));
569         }
570         case OBD_IOC_DISCONNECT:
571                 /* frees data structures */
572                 /* has this minor been registered? */
573                 if (!obddev->obd_type)
574                         return -ENODEV;
575
576                 get_user(cli_id, (int *) arg);
577                 conn.oc_id = cli_id;
578
579                 if ( !OBT(obddev) || !OBP(obddev, disconnect))
580                         return -EOPNOTSUPP;
581                 
582                 OBP(obddev, disconnect)(&conn);
583                 return 0;
584
585         case OBD_IOC_SYNC: {
586                 /* sync doesn't need a connection ID, because it knows
587                  * what device it was called on, and can thus get the
588                  * superblock that it needs. */
589                 /* has this minor been registered? */
590                 if (!obddev->obd_type)
591                         return -ENODEV;
592
593                 if (!obddev->u.ext2.ext2_sb || !obddev->u.ext2.ext2_sb->s_dev) {
594                         CDEBUG(D_IOCTL, "fatal: device not initialized.\n");
595                         err = -ENODEV;
596                 } else {
597                         err = fsync_dev(obddev->u.ext2.ext2_sb->s_dev);
598                         if ( err )
599                                 CDEBUG(D_IOCTL, "sync: fsync_dev failure\n");
600                         else
601                                 CDEBUG(D_IOCTL, "sync: success\n");
602                 }
603
604                 return put_user(err, (int *) arg);
605         }
606         case OBD_IOC_CREATE: {
607                 struct oic_create_s foo;
608                 objid id;
609
610                 if ( copy_from_user(&foo, (const void *)arg, sizeof(foo)) )
611                         return -EFAULT;
612
613                 /* has this minor been registered? */
614                 if ( !(obddev->obd_flags & OBD_ATTACHED) ||
615                      !(obddev->obd_flags & OBD_SET_UP)) {
616                         CDEBUG(D_IOCTL, "Device not attached or set up\n");
617                         return -ENODEV;
618                 }
619                 conn.oc_id = foo.conn_id;
620
621                 if ( !OBT(obddev) || !OBP(obddev, create) )
622                         return -EOPNOTSUPP;
623
624                 err = OBP(obddev, create)(&conn, foo.prealloc, &id);
625                 if (err) {
626                         CDEBUG(D_IOCTL, "create: obd_inode_new failure\n");
627                         /* 0 is the only error value */
628                         put_user(0, (int *) arg);
629                         return err;
630                 }
631
632                 return put_user(id, (int *) arg);
633         }
634         case OBD_IOC_DESTROY: {
635                 struct destroy_s {
636                         unsigned int conn_id;
637                         unsigned int ino;
638                 } destroy;
639                 obdattr *oa;
640                 
641                 if ( ! (oa = obd_empty_oa()) ) 
642                         return -ENOMEM;
643
644                 /* has this minor been registered? */
645                 if (!obddev->obd_type)
646                         return -ENODEV;
647
648                 copy_from_user(&destroy, (int *)arg, sizeof(struct destroy_s));
649                 if ( !OBT(obddev) || !OBP(obddev, destroy) )
650                         return -EOPNOTSUPP;
651
652                 oa->i_ino = destroy.ino;
653                 conn.oc_id = destroy.conn_id;
654                 err = OBP(obddev, destroy)(&conn, oa);
655                 OBD_FREE(oa, sizeof(*oa));
656                 return err;
657         }
658         case OBD_IOC_SETATTR: {
659                 struct oic_attr_s foo;
660                 obdattr *oa;
661
662                 if ( ! (oa = obd_empty_oa()) ) 
663                         return -ENOMEM;
664
665                 /* has this minor been registered? */
666                 if (!obddev->obd_type)
667                         return -ENODEV;
668
669                 err = copy_from_user(&foo, (int *)arg, sizeof(foo));
670                 if (err)
671                         return err;
672
673                 if ( !OBT(obddev) || !OBP(obddev, setattr) )
674                         return -EOPNOTSUPP;
675                 
676                 oa->i_ino = foo.ino;
677                 inode_setattr(oa, &foo.iattr);
678                 conn.oc_id = foo.conn_id;
679                 err = OBP(obddev, setattr)(&conn, oa);
680                 OBD_FREE(oa, sizeof(*oa));
681                 return err;
682         }
683
684         case OBD_IOC_GETATTR: {
685                 struct oic_getattr {
686                         unsigned int conn_id;
687                         unsigned long ino;
688                 } foo;
689                 struct iattr iattr;
690                 obdattr *oa;
691
692                 err = copy_from_user(&foo, (int *)arg, sizeof(foo));
693                 if (err)
694                         return err;
695
696                 conn.oc_id = foo.conn_id;
697                 oa = obd_oa_fromid(&conn, foo.ino);
698                 if ( !oa ) 
699                         return -ENOENT;
700
701                 inode_to_iattr(oa, &iattr);
702                 err = copy_to_user((int *)arg, &iattr, sizeof(iattr));
703                 return err;
704         }
705
706         case OBD_IOC_READ: {
707                 obdattr *oa = NULL;
708                 int err;
709                 struct oic_rw_s rw_s;  /* read, write ioctl str */
710
711                 err = copy_from_user(&rw_s, (int *)arg, sizeof(rw_s));
712                 if ( err ) 
713                         goto READ_OUT;
714
715                 conn.oc_id = rw_s.conn_id;
716                 if ( ! (oa = obd_oa_fromid(&conn, rw_s.id)) ) 
717                         return -ENOENT;
718
719                 if ( !OBT(obddev) || !OBP(obddev, read) ) {
720                         err = -EOPNOTSUPP;
721                         goto READ_OUT;
722                 }
723
724                 err = OBP(obddev, read)(&conn, oa, rw_s.buf, &rw_s.count,
725                                         rw_s.offset);
726                 if ( err ) 
727                         goto READ_OUT;
728
729                 err = copy_to_user((int*)arg, &rw_s.count, sizeof(rw_s.count));
730
731         READ_OUT:
732                 if ( oa ) 
733                         OBD_FREE(oa, sizeof(*oa));
734                 return err;
735         }
736
737         case OBD_IOC_WRITE: {
738                 obdattr *oa = NULL;
739                 struct oic_rw_s rw_s;  /* read, write ioctl str */
740
741                 err = copy_from_user(&rw_s, (int *)arg, sizeof(rw_s));
742                 if ( err ) 
743                         goto WRITE_OUT;
744
745                 conn.oc_id = rw_s.conn_id;
746                 oa = obd_oa_fromid(&conn, rw_s.id);
747                 if ( !oa ) 
748                         return -ENOENT;
749
750                 if ( !OBT(obddev) || !OBP(obddev, write) ) {
751                         err = -EOPNOTSUPP;
752                         goto WRITE_OUT;
753                 }
754
755                 err = OBP(obddev, write)(&conn, oa, rw_s.buf, &rw_s.count,
756                                          rw_s.offset);
757                 if ( err ) 
758                         goto WRITE_OUT;
759
760                 err = copy_to_user((int*)arg, &rw_s.count, sizeof(rw_s.count));
761
762         WRITE_OUT:
763                 OBD_FREE(oa, sizeof(*oa));
764                 return err;
765         }
766         case OBD_IOC_PREALLOCATE: {
767                 struct oic_prealloc_s prealloc;
768
769                 /* has this minor been registered? */
770                 if (!obddev->obd_type)
771                         return -ENODEV;
772
773                 err = copy_from_user(&prealloc, (int *)arg, sizeof(prealloc));
774                 if (err) 
775                         return -EFAULT;
776
777                 if ( !(obddev->obd_flags & OBD_ATTACHED) ||
778                      !(obddev->obd_flags & OBD_SET_UP)) {
779                         CDEBUG(D_IOCTL, "Device not attached or set up\n");
780                         return -ENODEV;
781                 }
782
783                 if ( !OBT(obddev) || !OBP(obddev, preallocate) )
784                         return -EOPNOTSUPP;
785
786                 conn.oc_id = prealloc.cli_id;
787                 err = OBP(obddev, preallocate)(&conn, &prealloc.alloc,
788                                                prealloc.inodes);
789                 if ( err ) 
790                         return err;
791
792                 return copy_to_user((int *)arg, &prealloc, sizeof(prealloc));
793         }
794         case OBD_IOC_STATFS: {
795                 struct statfs *tmp;
796                 unsigned int conn_id;
797                 struct statfs buf;
798
799                 /* has this minor been registered? */
800                 if (!obddev->obd_type)
801                         return -ENODEV;
802
803                 tmp = (void *)arg + sizeof(unsigned int);
804                 get_user(conn_id, (int *) arg);
805
806                 if ( !OBT(obddev) || !OBP(obddev, statfs) )
807                         return -EOPNOTSUPP;
808
809                 conn.oc_id = conn_id;
810                 err = OBP(obddev, statfs)(&conn, &buf);
811                 if ( err ) 
812                         return err;
813                 err = copy_to_user(tmp, &buf, sizeof(buf));
814                 return err;
815                 
816         }
817         default: {
818                 struct obd_type *type;
819                 struct oic_generic input;
820                 void *karg;
821
822                 /* get data structures */
823                 err = copy_from_user(&input, (void *)arg, sizeof(input));
824                 if ( err ) {
825                         EXIT;
826                         return err;
827                 }
828
829                 err = getdata(input.att_typelen + 1, &input.att_type);
830                 if ( err ) {
831                         EXIT;
832                         return err;
833                 }
834
835                 /* find the type */
836                 type = obd_nm_to_type(input.att_type);
837                 OBD_FREE(input.att_type, input.att_typelen + 1);
838                 if ( !type ) {
839                         printk("Unknown obd type dev %d\n", dev);
840                         EXIT;
841                         return -EINVAL;
842                 }
843                 
844                 if ( !type->typ_ops || !type->typ_ops->o_iocontrol ) {
845                         EXIT;
846                         return -EOPNOTSUPP;
847                 }
848                 conn.oc_id = input.att_connid;
849                 
850                 CDEBUG(D_IOCTL, "Calling ioctl %x for type %s, len %d\n",
851                        cmd, type->typ_name, input.att_datalen);
852
853                 /* get the generic data */
854                 karg = input.att_data;
855                 err = getdata(input.att_datalen, &karg);
856                 if ( err ) {
857                         EXIT;
858                         return err;
859                 }
860
861                 err = type->typ_ops->o_iocontrol(cmd, &conn, input.att_datalen, 
862                                                  karg, input.att_data);
863                 OBD_FREE(karg, input.att_datalen);
864
865                 EXIT;
866                 return err;
867         }
868         }
869 }
870
871 /* Driver interface done, utility functions follow */
872
873 int obd_register_type(struct obd_ops *ops, char *nm)
874 {
875         struct obd_type *type;
876
877
878         if (obd_init_magic != 0x11223344) {
879                 EXIT;
880                 return -EINVAL;
881         }
882
883         if  ( obd_nm_to_type(nm) ) {
884                 CDEBUG(D_IOCTL, "Type %s already registered\n", nm);
885                 EXIT;
886                 return -EEXIST;
887         }
888         
889         OBD_ALLOC(type, struct obd_type * , sizeof(*type));
890         if ( !type ) {
891                 EXIT;
892                 return -ENOMEM;
893         }
894         memset(type, 0, sizeof(*type));
895         INIT_LIST_HEAD(&type->typ_chain);
896         MOD_INC_USE_COUNT;
897         list_add(&type->typ_chain, obd_types.next);
898         type->typ_ops = ops;
899         type->typ_name = nm;
900         EXIT;
901         return 0;
902 }
903         
904 int obd_unregister_type(char *nm)
905 {
906         struct obd_type *type = obd_nm_to_type(nm);
907
908         if ( !type ) {
909                 MOD_DEC_USE_COUNT;
910                 printk("Unknown obd type\n");
911                 EXIT;
912                 return -EINVAL;
913         }
914
915         if ( type->typ_refcnt ) {
916                 MOD_DEC_USE_COUNT;
917                 printk("OBD: Type %s has refcount (%d)\n", nm,
918                        type->typ_refcnt);
919                 EXIT;
920                 return -EBUSY;
921         }
922
923         list_del(&type->typ_chain);
924         OBD_FREE(type, sizeof(*type));
925         MOD_DEC_USE_COUNT;
926         return 0;
927 }
928
929 /* declare character device */
930 static struct file_operations obd_psdev_fops = {
931         NULL,                  /* llseek */
932         NULL,                  /* read */
933         NULL,                  /* write */
934         NULL,                  /* presto_psdev_readdir */
935         NULL,                  /* poll */
936         obd_class_ioctl,       /* ioctl */
937         NULL,                  /* presto_psdev_mmap */
938         obd_class_open,        /* open */
939         NULL,
940         obd_class_release,     /* release */
941         NULL,                  /* fsync */
942         NULL,                  /* fasync */
943         NULL,                  /* check_media_change */
944         NULL,                  /* revalidate */
945         NULL                   /* lock */
946 };
947
948
949 /* modules setup */
950
951 int init_obd(void)
952 {
953         int i;
954
955         printk(KERN_INFO "OBD class driver  v0.002, braam@stelias.com\n");
956         
957         INIT_LIST_HEAD(&obd_types);
958         
959         if (register_chrdev(OBD_PSDEV_MAJOR,"obd_psdev", 
960                             &obd_psdev_fops)) {
961                 printk(KERN_ERR "obd_psdev: unable to get major %d\n", 
962                        OBD_PSDEV_MAJOR);
963                 return -EIO;
964         }
965
966         for (i = 0; i < MAX_OBD_DEVICES; i++) {
967                 memset(&(obd_dev[i]), 0, sizeof(obd_dev[i]));
968                 obd_dev[i].obd_minor = i;
969                 INIT_LIST_HEAD(&obd_dev[i].obd_gen_clients);
970         }
971
972         obd_sysctl_init();
973         obd_init_magic = 0x11223344;
974         return 0;
975 }
976
977 EXPORT_SYMBOL(obd_register_type);
978 EXPORT_SYMBOL(obd_unregister_type);
979
980 EXPORT_SYMBOL(obd_print_entry);
981 EXPORT_SYMBOL(obd_debug_level);
982 EXPORT_SYMBOL(obd_dev);
983
984 EXPORT_SYMBOL(gen_connect);
985 EXPORT_SYMBOL(gen_client);
986 EXPORT_SYMBOL(gen_cleanup);
987 EXPORT_SYMBOL(gen_disconnect);
988 EXPORT_SYMBOL(gen_copy_data); 
989
990 /* EXPORT_SYMBOL(gen_multi_attach); */
991 EXPORT_SYMBOL(gen_multi_setup);
992 EXPORT_SYMBOL(gen_multi_cleanup);
993
994
995 #ifdef MODULE
996 int init_module(void)
997 {
998         return init_obd();
999 }
1000
1001 void cleanup_module(void)
1002 {
1003         int i;
1004         ENTRY;
1005
1006         unregister_chrdev(OBD_PSDEV_MAJOR, "obd_psdev");
1007         for (i = 0; i < MAX_OBD_DEVICES; i++) {
1008                 struct obd_device *obddev = &obd_dev[i];
1009                 if ( obddev->obd_type && 
1010                      (obddev->obd_flags & OBD_SET_UP) &&
1011                      OBT(obddev) && OBP(obddev, detach) ) {
1012                         /* XXX should this call generic detach otherwise? */
1013                         OBP(obddev, detach)(obddev);
1014                 } 
1015         }
1016
1017
1018         obd_sysctl_clean();
1019         obd_init_magic = 0;
1020 }
1021 #endif