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 -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 -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.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 -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 ( !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 *srcoa, *tgtoa;
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 src %ld tgt %ld\n", dev, 
378                        obddev->obd_type->typ_name, mvdata.src, mvdata.tgt);
379
380                 conn.oc_id = mvdata.conn_id;
381                 srcoa = obd_oa_fromid(&conn, mvdata.src);
382                 if ( !srcoa ) 
383                         return -ENOENT;
384                 tgtoa = obd_oa_fromid(&conn, mvdata.tgt);
385                 if ( ! tgtoa ) {
386                         obd_free_oa(srcoa);
387                         return -ENOENT;
388                 }
389
390                 err = OBP(obddev, copy)(&conn, srcoa, tgtoa);
391
392                 obd_free_oa(srcoa);
393                 obd_free_oa(tgtoa);
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 *srcoa, *tgtoa;
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 tgt %ld\n",
426                        dev, obddev->obd_type->typ_name, mvdata.conn_id,
427                        mvdata.src, mvdata.tgt);
428
429
430                 if ( ! (srcoa = obd_empty_oa()) ) 
431                         return -ENOMEM;
432                 if ( ! (tgtoa = obd_empty_oa()) ) {
433                         obd_free_oa(srcoa);
434                         return -ENOMEM;
435                 }
436
437                 srcoa->i_ino = mvdata.src;
438                 tgtoa->i_ino = mvdata.tgt;
439
440                 conn.oc_id = mvdata.conn_id;
441
442                 err = OBP(obddev, migrate)(&conn, tgtoa, srcoa);
443
444                 obd_free_oa(srcoa);
445                 obd_free_oa(tgtoa);
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 -EINVAL;
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                 if (OBP(obddev, connect)(&conn))
564                         return -EINVAL;
565
566                 return copy_to_user((int *)arg, &conn.oc_id,
567                                     sizeof(int));
568         }
569         case OBD_IOC_DISCONNECT:
570                 /* frees data structures */
571                 /* has this minor been registered? */
572                 if (!obddev->obd_type)
573                         return -EINVAL;
574
575                 get_user(cli_id, (int *) arg);
576                 conn.oc_id = cli_id;
577
578                 if ( !OBT(obddev) || !OBP(obddev, disconnect))
579                         return -EOPNOTSUPP;
580                 
581                 OBP(obddev, disconnect)(&conn);
582                 return 0;
583
584         case OBD_IOC_SYNC: {
585                 /* sync doesn't need a connection ID, because it knows
586                  * what device it was called on, and can thus get the
587                  * superblock that it needs. */
588                 /* has this minor been registered? */
589                 if (!obddev->obd_type)
590                         return -EINVAL;
591
592                 if (!obddev->u.ext2.ext2_sb || !obddev->u.ext2.ext2_sb->s_dev) {
593                         CDEBUG(D_IOCTL, "fatal: device not initialized.\n");
594                         err = -ENODEV;
595                 } else {
596                         err = fsync_dev(obddev->u.ext2.ext2_sb->s_dev);
597                         if ( err )
598                                 CDEBUG(D_IOCTL, "sync: fsync_dev failure\n");
599                         else
600                                 CDEBUG(D_IOCTL, "sync: success\n");
601                 }
602
603                 return put_user(err, (int *) arg);
604         }
605         case OBD_IOC_CREATE: {
606                 struct oic_create_s foo;
607
608                 if ( copy_from_user(&foo, (const void *)arg, sizeof(foo)) )
609                         return -EFAULT;
610
611                 /* has this minor been registered? */
612                 if ( !(obddev->obd_flags & OBD_ATTACHED) ||
613                      !(obddev->obd_flags & OBD_SET_UP)) {
614                         CDEBUG(D_IOCTL, "Device not attached or set up\n");
615                         return -ENODEV;
616                 }
617                 conn.oc_id = foo.conn_id;
618
619                 if ( !OBT(obddev) || !OBP(obddev, create) )
620                         return -EOPNOTSUPP;
621
622                 i_ino = OBP(obddev, create)(&conn, foo.prealloc, &err);
623                 if (err) {
624                         CDEBUG(D_IOCTL, "create: obd_inode_new failure\n");
625                         /* 0 is the only error value */
626                         return put_user(0, (int *) arg);
627                 }
628
629                 return put_user(i_ino, (int *) arg);
630         }
631         case OBD_IOC_DESTROY: {
632                 struct destroy_s {
633                         unsigned int conn_id;
634                         unsigned int ino;
635                 } destroy;
636                 obdattr *oa;
637                 
638                 if ( ! (oa = obd_empty_oa()) ) 
639                         return -ENOMEM;
640
641                 /* has this minor been registered? */
642                 if (!obddev->obd_type)
643                         return -EINVAL;
644
645                 copy_from_user(&destroy, (int *)arg, sizeof(struct destroy_s));
646                 if ( !OBT(obddev) || !OBP(obddev, destroy) )
647                         return -EOPNOTSUPP;
648
649                 oa->i_ino = destroy.ino;
650                 conn.oc_id = destroy.conn_id;
651                 err = OBP(obddev, destroy)(&conn, oa);
652                 OBD_FREE(oa, sizeof(*oa));
653                 return err;
654         }
655         case OBD_IOC_SETATTR: {
656                 struct oic_attr_s foo;
657                 obdattr *oa;
658
659                 if ( ! (oa = obd_empty_oa()) ) 
660                         return -ENOMEM;
661
662                 /* has this minor been registered? */
663                 if (!obddev->obd_type)
664                         return -EINVAL;
665
666                 err = copy_from_user(&foo, (int *)arg, sizeof(foo));
667                 if (err)
668                         return err;
669
670                 if ( !OBT(obddev) || !OBP(obddev, setattr) )
671                         return -EOPNOTSUPP;
672                 
673                 oa->i_ino = foo.ino;
674                 inode_setattr(oa, &foo.iattr);
675                 conn.oc_id = foo.conn_id;
676                 err = OBP(obddev, setattr)(&conn, oa);
677                 OBD_FREE(oa, sizeof(*oa));
678                 return err;
679         }
680
681         case OBD_IOC_GETATTR: {
682                 struct oic_getattr {
683                         unsigned int conn_id;
684                         unsigned long ino;
685                 } foo;
686                 struct iattr iattr;
687                 obdattr *oa;
688
689                 err = copy_from_user(&foo, (int *)arg, sizeof(foo));
690                 if (err)
691                         return err;
692
693                 conn.oc_id = foo.conn_id;
694                 oa = obd_oa_fromid(&conn, foo.ino);
695                 if ( !oa ) 
696                         return -ENOENT;
697
698                 inode_to_iattr(oa, &iattr);
699                 err = copy_to_user((int *)arg, &iattr, sizeof(iattr));
700                 return err;
701         }
702
703         case OBD_IOC_READ: {
704                 obdattr *oa = NULL;
705                 int err;
706                 struct oic_rw_s rw_s;  /* read, write ioctl str */
707
708                 err = copy_from_user(&rw_s, (int *)arg, sizeof(rw_s));
709                 if ( err ) 
710                         goto READ_OUT;
711
712                 conn.oc_id = rw_s.conn_id;
713                 if ( ! (oa = obd_oa_fromid(&conn, rw_s.id)) ) 
714                         return -ENOENT;
715
716                 if ( !OBT(obddev) || !OBP(obddev, read) ) {
717                         err = -EOPNOTSUPP;
718                         goto READ_OUT;
719                 }
720
721                 err = OBP(obddev, read)(&conn, oa, rw_s.buf, &rw_s.count,
722                                         rw_s.offset);
723                 if ( err ) 
724                         goto READ_OUT;
725
726                 err = copy_to_user((int*)arg, &rw_s.count, sizeof(rw_s.count));
727
728         READ_OUT:
729                 if ( oa ) 
730                         OBD_FREE(oa, sizeof(*oa));
731                 return err;
732         }
733
734         case OBD_IOC_WRITE: {
735                 obdattr *oa = NULL;
736                 struct oic_rw_s rw_s;  /* read, write ioctl str */
737
738                 err = copy_from_user(&rw_s, (int *)arg, sizeof(rw_s));
739                 if ( err ) 
740                         goto WRITE_OUT;
741
742                 conn.oc_id = rw_s.conn_id;
743                 oa = obd_oa_fromid(&conn, rw_s.id);
744                 if ( !oa ) 
745                         return -ENOENT;
746
747                 if ( !OBT(obddev) || !OBP(obddev, write) ) {
748                         err = -EOPNOTSUPP;
749                         goto WRITE_OUT;
750                 }
751
752                 err = OBP(obddev, write)(&conn, oa, rw_s.buf, &rw_s.count,
753                                          rw_s.offset);
754                 if ( err ) 
755                         goto WRITE_OUT;
756
757                 err = copy_to_user((int*)arg, &rw_s.count, sizeof(rw_s.count));
758
759         WRITE_OUT:
760                 OBD_FREE(oa, sizeof(*oa));
761                 return err;
762         }
763         case OBD_IOC_PREALLOCATE: {
764                 struct oic_prealloc_s prealloc;
765
766                 /* has this minor been registered? */
767                 if (!obddev->obd_type)
768                         return -EINVAL;
769
770                 err = copy_from_user(&prealloc, (int *)arg, sizeof(prealloc));
771                 if (err) 
772                         return -EFAULT;
773
774                 if ( !(obddev->obd_flags & OBD_ATTACHED) ||
775                      !(obddev->obd_flags & OBD_SET_UP)) {
776                         CDEBUG(D_IOCTL, "Device not attached or set up\n");
777                         return -ENODEV;
778                 }
779
780                 if ( !OBT(obddev) || !OBP(obddev, preallocate) )
781                         return -EOPNOTSUPP;
782
783                 conn.oc_id = prealloc.cli_id;
784                 err = OBP(obddev, preallocate)(&conn, &prealloc.alloc,
785                                                prealloc.inodes);
786                 if ( err ) 
787                         return err;
788
789                 return copy_to_user((int *)arg, &prealloc, sizeof(prealloc));
790         }
791         case OBD_IOC_STATFS: {
792                 struct statfs *tmp;
793                 unsigned int conn_id;
794                 struct statfs buf;
795
796                 /* has this minor been registered? */
797                 if (!obddev->obd_type)
798                         return -EINVAL;
799
800                 tmp = (void *)arg + sizeof(unsigned int);
801                 get_user(conn_id, (int *) arg);
802
803                 if ( !OBT(obddev) || !OBP(obddev, statfs) )
804                         return -EOPNOTSUPP;
805
806                 conn.oc_id = conn_id;
807                 err = OBP(obddev, statfs)(&conn, &buf);
808                 if ( err ) 
809                         return err;
810                 err = copy_to_user(tmp, &buf, sizeof(buf));
811                 return err;
812                 
813         }
814         default: {
815                 struct obd_type *type;
816                 struct oic_generic input;
817                 void *karg;
818
819                 /* get data structures */
820                 err = copy_from_user(&input, (void *)arg, sizeof(input));
821                 if ( err ) {
822                         EXIT;
823                         return err;
824                 }
825
826                 err = getdata(input.att_typelen + 1, &input.att_type);
827                 if ( err ) {
828                         EXIT;
829                         return err;
830                 }
831
832                 /* find the type */
833                 type = obd_nm_to_type(input.att_type);
834                 OBD_FREE(input.att_type, input.att_typelen + 1);
835                 if ( !type ) {
836                         printk("Unknown obd type dev %d\n", dev);
837                         EXIT;
838                         return -EINVAL;
839                 }
840                 
841                 if ( !type->typ_ops || !type->typ_ops->o_iocontrol ) {
842                         EXIT;
843                         return -EOPNOTSUPP;
844                 }
845                 conn.oc_id = input.att_connid;
846                 
847                 CDEBUG(D_IOCTL, "Calling ioctl %x for type %s, len %d\n",
848                        cmd, type->typ_name, input.att_datalen);
849
850                 /* get the generic data */
851                 karg = input.att_data;
852                 err = getdata(input.att_datalen, &karg);
853                 if ( err ) {
854                         EXIT;
855                         return err;
856                 }
857
858                 err = type->typ_ops->o_iocontrol(cmd, &conn, input.att_datalen, 
859                                                  karg, input.att_data);
860                 OBD_FREE(karg, input.att_datalen);
861
862                 EXIT;
863                 return err;
864         }
865         }
866 }
867
868 /* Driver interface done, utility functions follow */
869
870 int obd_register_type(struct obd_ops *ops, char *nm)
871 {
872         struct obd_type *type;
873
874
875         if (obd_init_magic != 0x11223344) {
876                 EXIT;
877                 return -EINVAL;
878         }
879
880         if  ( obd_nm_to_type(nm) ) {
881                 CDEBUG(D_IOCTL, "Type %s already registered\n", nm);
882                 EXIT;
883                 return -EEXIST;
884         }
885         
886         OBD_ALLOC(type, struct obd_type * , sizeof(*type));
887         if ( !type ) {
888                 EXIT;
889                 return -ENOMEM;
890         }
891         memset(type, 0, sizeof(*type));
892         INIT_LIST_HEAD(&type->typ_chain);
893         MOD_INC_USE_COUNT;
894         list_add(&type->typ_chain, obd_types.next);
895         type->typ_ops = ops;
896         type->typ_name = nm;
897         EXIT;
898         return 0;
899 }
900         
901 int obd_unregister_type(char *nm)
902 {
903         struct obd_type *type = obd_nm_to_type(nm);
904
905         if ( !type ) {
906                 MOD_DEC_USE_COUNT;
907                 printk("Unknown obd type\n");
908                 EXIT;
909                 return -EINVAL;
910         }
911
912         if ( type->typ_refcnt ) {
913                 MOD_DEC_USE_COUNT;
914                 printk("OBD: Type %s has refcount (%d)\n", nm,
915                        type->typ_refcnt);
916                 EXIT;
917                 return -EBUSY;
918         }
919
920         list_del(&type->typ_chain);
921         OBD_FREE(type, sizeof(*type));
922         MOD_DEC_USE_COUNT;
923         return 0;
924 }
925
926 /* declare character device */
927 static struct file_operations obd_psdev_fops = {
928         NULL,                  /* llseek */
929         NULL,                  /* read */
930         NULL,                  /* write */
931         NULL,                  /* presto_psdev_readdir */
932         NULL,                  /* poll */
933         obd_class_ioctl,       /* ioctl */
934         NULL,                  /* presto_psdev_mmap */
935         obd_class_open,        /* open */
936         NULL,
937         obd_class_release,     /* release */
938         NULL,                  /* fsync */
939         NULL,                  /* fasync */
940         NULL,                  /* check_media_change */
941         NULL,                  /* revalidate */
942         NULL                   /* lock */
943 };
944
945
946 /* modules setup */
947
948 int init_obd(void)
949 {
950         int i;
951
952         printk(KERN_INFO "OBD class driver  v0.002, braam@stelias.com\n");
953         
954         INIT_LIST_HEAD(&obd_types);
955         
956         if (register_chrdev(OBD_PSDEV_MAJOR,"obd_psdev", 
957                             &obd_psdev_fops)) {
958                 printk(KERN_ERR "obd_psdev: unable to get major %d\n", 
959                        OBD_PSDEV_MAJOR);
960                 return -EIO;
961         }
962
963         for (i = 0; i < MAX_OBD_DEVICES; i++) {
964                 memset(&(obd_dev[i]), 0, sizeof(obd_dev[i]));
965                 obd_dev[i].obd_minor = i;
966                 INIT_LIST_HEAD(&obd_dev[i].obd_gen_clients);
967         }
968
969         obd_sysctl_init();
970         obd_init_magic = 0x11223344;
971         return 0;
972 }
973
974 EXPORT_SYMBOL(obd_register_type);
975 EXPORT_SYMBOL(obd_unregister_type);
976
977 EXPORT_SYMBOL(obd_print_entry);
978 EXPORT_SYMBOL(obd_debug_level);
979 EXPORT_SYMBOL(obd_dev);
980
981 EXPORT_SYMBOL(gen_connect);
982 EXPORT_SYMBOL(gen_client);
983 EXPORT_SYMBOL(gen_cleanup);
984 EXPORT_SYMBOL(gen_disconnect);
985 EXPORT_SYMBOL(gen_copy_data); 
986
987 /* EXPORT_SYMBOL(gen_multi_attach); */
988 EXPORT_SYMBOL(gen_multi_setup);
989 EXPORT_SYMBOL(gen_multi_cleanup);
990
991
992 #ifdef MODULE
993 int init_module(void)
994 {
995         return init_obd();
996 }
997
998 void cleanup_module(void)
999 {
1000         int i;
1001         ENTRY;
1002
1003         unregister_chrdev(OBD_PSDEV_MAJOR, "obd_psdev");
1004         for (i = 0; i < MAX_OBD_DEVICES; i++) {
1005                 struct obd_device *obddev = &obd_dev[i];
1006                 if ( obddev->obd_type && 
1007                      (obddev->obd_flags & OBD_SET_UP) &&
1008                      OBT(obddev) && OBP(obddev, detach) ) {
1009                         /* XXX should this call generic detach otherwise? */
1010                         OBP(obddev, detach)(obddev);
1011                 } 
1012         }
1013
1014
1015         obd_sysctl_clean();
1016         obd_init_magic = 0;
1017 }
1018 #endif