Whamcloud - gitweb
class/obdcontrol: fixed read, write, create to work with obdos
[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 "presto_psdev_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         /* NOTE this must be larger than any of the ioctl data structs */
159         char buf[1024];
160         void *tmp_buf = buf;
161         struct obd_conn conn;
162         int err, dev;
163         long int cli_id; /* connect, disconnect */
164
165         if (!inode)
166                 return -EINVAL;
167
168         dev = MINOR(inode->i_rdev);
169         if (dev > MAX_OBD_DEVICES)
170                 return -ENODEV;
171         obddev = &obd_dev[dev];
172         conn.oc_dev = obddev;
173
174         switch (cmd) {
175         case TCGETS:
176                 return -EINVAL;
177         case OBD_IOC_ATTACH: {
178                 struct obd_type *type;
179                 struct oic_generic *input = tmp_buf;
180
181                 ENTRY;
182                 /* have we attached a type to this device */
183                 if ( obddev->obd_type || 
184                      (obddev->obd_flags & OBD_ATTACHED) ){
185                         CDEBUG(D_IOCTL,
186                                "OBD Device %d already attached to type %s.\n",
187                                dev, obddev->obd_type->typ_name);
188                         EXIT;
189                         return -EBUSY;
190                 }
191
192                 /* get data structures */
193                 err = copy_from_user(input, (void *)arg, sizeof(*input));
194                 if ( err ) {
195                         EXIT;
196                         return err;
197                 }
198
199                 err = getdata(input->att_typelen + 1, &input->att_type);
200                 if ( err ) {
201                         EXIT;
202                         return err;
203                 }
204
205                 /* find the type */
206                 type = obd_nm_to_type(input->att_type);
207                 OBD_FREE(input->att_type, input->att_typelen + 1);
208                 if ( !type ) {
209                         printk("Unknown obd type dev %d\n", dev);
210                         EXIT;
211                         return -EINVAL;
212                 }
213                 obddev->obd_type = type;
214                 
215                 /* get the attach data */
216                 err = getdata(input->att_datalen, &input->att_data);
217                 if ( err ) {
218                         EXIT;
219                         return err;
220                 }
221
222                 INIT_LIST_HEAD(&obddev->obd_gen_clients);
223                 obddev->obd_multi_count = 0;
224
225                 CDEBUG(D_IOCTL, "Attach %d, datalen %d, type %s\n", 
226                        dev, input->att_datalen, obddev->obd_type->typ_name);
227                 /* maybe we are done */
228                 if ( !OBT(obddev) || !OBP(obddev, attach) ) {
229                         obddev->obd_flags |=  OBD_ATTACHED;
230                         type->typ_refcnt++;
231                         CDEBUG(D_IOCTL, "Dev %d refcount now %d\n", dev,
232                                type->typ_refcnt);
233                         MOD_INC_USE_COUNT;
234                         EXIT;
235                         return 0;
236                 }
237
238                 /* do the attach */
239                 err = OBP(obddev, attach)(obddev, input->att_datalen,
240                                           input->att_data);
241                 OBD_FREE(input->att_data, input->att_datalen);
242
243                 if ( err ) {
244                         obddev->obd_flags &= ~OBD_ATTACHED;
245                         obddev->obd_type = NULL;
246                         EXIT;
247                 } else {
248                         obddev->obd_flags |=  OBD_ATTACHED;
249                         type->typ_refcnt++;
250                         CDEBUG(D_IOCTL, "Dev %d refcount now %d\n", dev,
251                                type->typ_refcnt);
252                         MOD_INC_USE_COUNT;
253                         EXIT;
254                 }
255                 return err;
256         }
257
258         case OBD_IOC_DETACH: {
259
260                 ENTRY;
261                 if (obddev->obd_flags & OBD_SET_UP) {
262                         EXIT;
263                         return -EBUSY;
264                 }
265                 if (! (obddev->obd_flags & OBD_ATTACHED) ) {
266                         CDEBUG(D_IOCTL, "Device not attached\n");
267                         EXIT;
268                         return -ENODEV;
269                 }
270                 if ( !list_empty(&obddev->obd_gen_clients) ) {
271                         CDEBUG(D_IOCTL, "Device has connected clients\n");
272                         EXIT;
273                         return -EBUSY;
274                 }
275
276                 CDEBUG(D_IOCTL, "Detach %d, type %s\n", dev,
277                        obddev->obd_type->typ_name);
278                 obddev->obd_flags &= ~OBD_ATTACHED;
279                 obddev->obd_type->typ_refcnt--;
280                 CDEBUG(D_IOCTL, "Dev %d refcount now %d\n", dev,
281                        obddev->obd_type->typ_refcnt);
282                 obddev->obd_type = NULL;
283                 MOD_DEC_USE_COUNT;
284                 EXIT;
285                 return 0;
286         }
287
288         case OBD_IOC_SETUP: {
289                 struct ioc_setup {
290                         int setup_datalen;
291                         void *setup_data;
292                 } *setup;
293                 setup = tmp_buf;
294
295                 ENTRY;
296                 /* have we attached a type to this device */
297                 if (!(obddev->obd_flags & OBD_ATTACHED)) {
298                         CDEBUG(D_IOCTL, "Device not attached\n");
299                         EXIT;
300                         return -ENODEV;
301                 }
302
303                 /* has this been done already? */
304                 if ( obddev->obd_flags & OBD_SET_UP ) {
305                         CDEBUG(D_IOCTL, "Device %d already setup (type %s)\n",
306                                dev, obddev->obd_type->typ_name);
307                         EXIT;
308                         return -EBUSY;
309                 }
310
311                 /* get main structure */
312                 err = copy_from_user(setup, (void *) arg, sizeof(*setup));
313                 if (err) {
314                         EXIT;
315                         return err;
316                 }
317
318                 err = getdata(setup->setup_datalen, &setup->setup_data);
319                 if (err) {
320                         EXIT;
321                         return err;
322                 }
323
324                 /* do the setup */
325                 CDEBUG(D_IOCTL, "Setup %d, type %s\n", dev, 
326                        obddev->obd_type->typ_name);
327                 if ( !OBT(obddev) || !OBP(obddev, setup) ) {
328                         obddev->obd_type->typ_refcnt++;
329                         CDEBUG(D_IOCTL, "Dev %d refcount now %d\n",
330                                dev, obddev->obd_type->typ_refcnt);
331                         obddev->obd_flags |= OBD_SET_UP;
332                         EXIT;
333                         return 0;
334                 }
335
336                 err = OBP(obddev, setup)(obddev, setup->setup_datalen,
337                                          setup->setup_data);
338
339                 if ( err )  {
340                         obddev->obd_flags &= ~OBD_SET_UP;
341                         EXIT;
342                 } else {
343                         obddev->obd_type->typ_refcnt++;
344                         CDEBUG(D_IOCTL, "Dev %d refcount now %d\n",
345                                dev, obddev->obd_type->typ_refcnt);
346                         obddev->obd_flags |= OBD_SET_UP;
347                         EXIT;
348                 }
349                 return err;
350         }
351         case OBD_IOC_CLEANUP: {
352                 ENTRY;
353                 /* has this minor been registered? */
354                 if (!obddev->obd_type) {
355                         CDEBUG(D_IOCTL, "OBD Device %d has no type.\n", dev);
356                         EXIT;
357                         return -ENODEV;
358                 }
359
360                 if ( !obddev->obd_type->typ_refcnt ) {
361                         printk("OBD_CLEANUP: Dev %d has refcount (%d)!\n",
362                                dev, obddev->obd_type->typ_refcnt);
363                         EXIT;
364                         return -EBUSY;
365                 }
366
367                 if ( (!(obddev->obd_flags & OBD_SET_UP)) ||
368                      (!(obddev->obd_flags & OBD_ATTACHED))) {
369                         CDEBUG(D_IOCTL, "Device not attached or set up\n");
370                         EXIT;
371                         return -ENODEV;
372                 }
373
374                 if ( !OBT(obddev) || !OBP(obddev, cleanup) )
375                         goto cleanup_out;
376
377                 /* cleanup has no argument */
378                 err = OBP(obddev, cleanup)(obddev);
379                 if ( err ) {
380                         EXIT;
381                         return err;
382                 }
383
384         cleanup_out: 
385                 obddev->obd_flags &= ~OBD_SET_UP;
386                 obddev->obd_type->typ_refcnt--;
387                 CDEBUG(D_IOCTL, "Dev %d refcount now %d\n", dev,
388                        obddev->obd_type->typ_refcnt);
389                 EXIT;
390                 return 0;
391         }
392         case OBD_IOC_CONNECT:
393         {
394                 if ( (!(obddev->obd_flags & OBD_SET_UP)) ||
395                      (!(obddev->obd_flags & OBD_ATTACHED))) {
396                         CDEBUG(D_IOCTL, "Device not attached or set up\n");
397                         return -ENODEV;
398                 }
399
400                 if ( !OBT(obddev) || !OBP(obddev, connect) )
401                         return -EOPNOTSUPP;
402                 
403                 err = OBP(obddev, connect)(&conn);
404                 if ( err )
405                         return err;
406
407                 return copy_to_user((int *)arg, &conn.oc_id,
408                                     sizeof(uint32_t));
409         }
410         case OBD_IOC_DISCONNECT:
411                 /* frees data structures */
412                 /* has this minor been registered? */
413                 if (!obddev->obd_type)
414                         return -ENODEV;
415
416                 get_user(cli_id, (int *) arg);
417                 conn.oc_id = cli_id;
418
419                 if ( !OBT(obddev) || !OBP(obddev, disconnect))
420                         return -EOPNOTSUPP;
421                 
422                 OBP(obddev, disconnect)(&conn);
423                 return 0;
424
425         case OBD_IOC_SYNC: {
426                 struct oic_range_s *range = tmp_buf;
427
428                 if (!obddev->obd_type)
429                         return -ENODEV;
430
431                 err = copy_from_user(range, (const void *)arg,  sizeof(*range));
432
433                 if ( err ) {
434                         EXIT;
435                         return err;
436                 }
437                         
438                 if ( !OBT(obddev) || !OBP(obddev, sync) ) {
439                         err = -EOPNOTSUPP;
440                         EXIT;
441                         return err;
442                 }
443
444                 /* XXX sync needs to be tested/verified */
445                 err = OBP(obddev, sync)(&conn, &range->obdo, range->count,
446                                         range->offset);
447
448                 if ( err ) {
449                         EXIT;
450                         return err;
451                 }
452                         
453                 return put_user(err, (int *) arg);
454         }
455         case OBD_IOC_CREATE: {
456                 struct oic_attr_s *attr = tmp_buf;
457
458                 err = copy_from_user(attr, (const void *)arg,  sizeof(*attr));
459                 if (err) {
460                         EXIT;
461                         return err;
462                 }
463
464                 /* has this minor been registered? */
465                 if ( !(obddev->obd_flags & OBD_ATTACHED) ||
466                      !(obddev->obd_flags & OBD_SET_UP)) {
467                         CDEBUG(D_IOCTL, "Device not attached or set up\n");
468                         return -ENODEV;
469                 }
470                 conn.oc_id = attr->conn_id;
471
472                 if ( !OBT(obddev) || !OBP(obddev, create) )
473                         return -EOPNOTSUPP;
474
475                 err = OBP(obddev, create)(&conn, &attr->obdo);
476                 if (err) {
477                         EXIT;
478                         return err;
479                 }
480
481                 err = copy_to_user((int *)arg, attr, sizeof(*attr));
482                 EXIT;
483                 return err;
484         }
485
486         case OBD_IOC_DESTROY: {
487                 struct oic_attr_s *attr = tmp_buf;
488                 
489                 /* has this minor been registered? */
490                 if (!obddev->obd_type)
491                         return -ENODEV;
492
493                 err = copy_from_user(attr, (int *)arg, sizeof(*attr));
494                 if ( err ) {
495                         EXIT;
496                         return err;
497                 }
498
499                 if ( !OBT(obddev) || !OBP(obddev, destroy) )
500                         return -EOPNOTSUPP;
501
502                 conn.oc_id = attr->conn_id;
503                 err = OBP(obddev, destroy)(&conn, &attr->obdo);
504                 EXIT;
505                 return err;
506         }
507
508         case OBD_IOC_SETATTR: {
509                 struct oic_attr_s *attr = tmp_buf;
510
511                 /* has this minor been registered? */
512                 if (!obddev->obd_type)
513                         return -ENODEV;
514
515                 err = copy_from_user(attr, (int *)arg, sizeof(*attr));
516                 if (err)
517                         return err;
518
519                 if ( !OBT(obddev) || !OBP(obddev, setattr) )
520                         return -EOPNOTSUPP;
521                 
522                 conn.oc_id = attr->conn_id;
523                 err = OBP(obddev, setattr)(&conn, &attr->obdo);
524                 EXIT;
525                 return err;
526         }
527
528         case OBD_IOC_GETATTR: {
529                 struct oic_attr_s *attr = tmp_buf;
530
531                 err = copy_from_user(attr, (int *)arg, sizeof(*attr));
532                 if (err)
533                         return err;
534
535                 conn.oc_id = attr->conn_id;
536                 ODEBUG(&attr->obdo);
537                 err = OBP(obddev, getattr)(&conn, &attr->obdo);
538                 if ( err ) {
539                         EXIT;
540                         return err;
541                 }
542
543                 err = copy_to_user((int *)arg, attr, sizeof(*attr));
544                 EXIT;
545                 return err;
546         }
547
548         case OBD_IOC_READ: {
549                 int err;
550                 struct oic_rw_s *rw_s = tmp_buf;  /* read, write ioctl str */
551
552                 err = copy_from_user(rw_s, (int *)arg, sizeof(*rw_s));
553                 if ( err ) {
554                         EXIT;
555                         return err;
556                 }
557
558                 conn.oc_id = rw_s->conn_id;
559
560                 if ( !OBT(obddev) || !OBP(obddev, read) ) {
561                         err = -EOPNOTSUPP;
562                         EXIT;
563                         return err;
564                 }
565
566
567                 err = OBP(obddev, read)(&conn, &rw_s->obdo, rw_s->buf, 
568                                         &rw_s->count, rw_s->offset);
569                 
570                 ODEBUG(&rw_s->obdo);
571                 CDEBUG(D_INODE, "READ: conn %d, count %Ld, offset %Ld, '%s'\n",
572                        rw_s->conn_id, rw_s->count, rw_s->offset, rw_s->buf);
573                 if ( err ) {
574                         EXIT;
575                         return err;
576                 }
577                         
578                 err = copy_to_user((int*)arg, &rw_s->count, sizeof(rw_s->count));
579                 EXIT;
580                 return err;
581         }
582
583         case OBD_IOC_WRITE: {
584                 struct oic_rw_s *rw_s = tmp_buf;  /* read, write ioctl str */
585
586                 err = copy_from_user(rw_s, (int *)arg, sizeof(*rw_s));
587                 if ( err ) {
588                         EXIT;
589                         return err;
590                 }
591
592                 conn.oc_id = rw_s->conn_id;
593
594                 if ( !OBT(obddev) || !OBP(obddev, write) ) {
595                         err = -EOPNOTSUPP;
596                         return err;
597                 }
598
599                 CDEBUG(D_INODE, "WRITE: conn %d, count %Ld, offset %Ld, '%s'\n",
600                        rw_s->conn_id, rw_s->count, rw_s->offset, rw_s->buf);
601                 err = OBP(obddev, write)(&conn, &rw_s->obdo, rw_s->buf, 
602                                          &rw_s->count, rw_s->offset);
603                 ODEBUG(&rw_s->obdo);
604                 if ( err ) {
605                         EXIT;
606                         return err;
607                 }
608
609                 err = copy_to_user((int *)arg, &rw_s->count,
610                                    sizeof(rw_s->count));
611                 EXIT;
612                 return err;
613         }
614         case OBD_IOC_PREALLOCATE: {
615                 struct oic_prealloc_s *prealloc = tmp_buf;
616
617                 /* has this minor been registered? */
618                 if (!obddev->obd_type)
619                         return -ENODEV;
620
621                 err = copy_from_user(prealloc, (int *)arg, sizeof(*prealloc));
622                 if (err) 
623                         return -EFAULT;
624
625                 if ( !(obddev->obd_flags & OBD_ATTACHED) ||
626                      !(obddev->obd_flags & OBD_SET_UP)) {
627                         CDEBUG(D_IOCTL, "Device not attached or set up\n");
628                         return -ENODEV;
629                 }
630
631                 if ( !OBT(obddev) || !OBP(obddev, preallocate) )
632                         return -EOPNOTSUPP;
633
634                 conn.oc_id = prealloc->conn_id;
635                 err = OBP(obddev, preallocate)(&conn, &prealloc->alloc,
636                                                prealloc->ids);
637                 if ( err ) {
638                         EXIT;
639                         return err;
640                 }
641
642                 err =copy_to_user((int *)arg, prealloc, sizeof(*prealloc));
643                 EXIT;
644                 return err;
645         }
646         case OBD_IOC_STATFS: {
647                 struct statfs *tmp;
648                 unsigned int conn_id;
649                 struct statfs buf;
650
651                 /* has this minor been registered? */
652                 if (!obddev->obd_type)
653                         return -ENODEV;
654
655                 tmp = (void *)arg + sizeof(unsigned int);
656                 get_user(conn_id, (int *) arg);
657
658                 if ( !OBT(obddev) || !OBP(obddev, statfs) )
659                         return -EOPNOTSUPP;
660
661                 conn.oc_id = conn_id;
662                 err = OBP(obddev, statfs)(&conn, &buf);
663                 if ( err ) {
664                         EXIT;
665                         return err;
666                 }
667                 err = copy_to_user(tmp, &buf, sizeof(buf));
668                 EXIT;
669                 return err;
670                 
671         }
672         case OBD_IOC_COPY: {
673                 struct ioc_mv_s *mvdata = tmp_buf;
674
675                 if ( (!(obddev->obd_flags & OBD_SET_UP)) ||
676                      (!(obddev->obd_flags & OBD_ATTACHED))) {
677                         CDEBUG(D_IOCTL, "Device not attached or set up\n");
678                         return -ENODEV;
679                 }
680
681                 /* get main structure */
682                 err = copy_from_user(mvdata, (void *) arg, sizeof(*mvdata));
683                 if (err) {
684                         EXIT;
685                         return err;
686                 }
687
688                 if ( !OBT(obddev) || !OBP(obddev, copy) )
689                         return -EOPNOTSUPP;
690
691                 /* do the partition */
692                 CDEBUG(D_IOCTL, "Copy %d, type %s dst %Ld src %Ld\n", dev, 
693                        obddev->obd_type->typ_name, mvdata->dst.o_id, 
694                        mvdata->src.o_id);
695
696                 conn.oc_id = mvdata->src_conn_id;
697
698                 err = OBP(obddev, copy)(&conn, &mvdata->dst, 
699                                         &conn, &mvdata->src, 
700                                         mvdata->src.o_size, 0);
701                 return err;
702         }
703
704         case OBD_IOC_MIGR: {
705                 struct ioc_mv_s *mvdata = tmp_buf;
706
707                 if ( (!(obddev->obd_flags & OBD_SET_UP)) ||
708                      (!(obddev->obd_flags & OBD_ATTACHED))) {
709                         CDEBUG(D_IOCTL, "Device not attached or set up\n");
710                         return -ENODEV;
711                 }
712
713                 err = copy_from_user(mvdata, (void *) arg, sizeof(*mvdata));
714                 if (err) {
715                         EXIT;
716                         return err;
717                 }
718
719                 CDEBUG(D_IOCTL, "Migrate copying %d bytes\n", sizeof(*mvdata));
720
721                 if ( !OBT(obddev) || !OBP(obddev, migrate) )
722                         return -EOPNOTSUPP;
723
724                 /* do the partition */
725                 CDEBUG(D_IOCTL, "Migrate %d, type %s conn %d src %Ld dst %Ld\n",
726                        dev, obddev->obd_type->typ_name, mvdata->src_conn_id,
727                        mvdata->src.o_id, mvdata->dst.o_id);
728
729                 conn.oc_id = mvdata->src_conn_id;
730                 err = OBP(obddev, migrate)(&conn, &mvdata->dst, &mvdata->src, 
731                                            mvdata->src.o_size, 0);
732
733                 return err;
734         }
735
736         default: {
737                 struct obd_type *type;
738                 struct oic_generic input;
739                 void *karg;
740
741                 /* get data structures */
742                 err = copy_from_user(&input, (void *)arg, sizeof(input));
743                 if ( err ) {
744                         EXIT;
745                         return err;
746                 }
747
748                 err = getdata(input.att_typelen + 1, &input.att_type);
749                 if ( err ) {
750                         EXIT;
751                         return err;
752                 }
753
754                 /* find the type */
755                 type = obd_nm_to_type(input.att_type);
756                 OBD_FREE(input.att_type, input.att_typelen + 1);
757                 if ( !type ) {
758                         printk("Unknown obd type dev %d\n", dev);
759                         EXIT;
760                         return -EINVAL;
761                 }
762                 
763                 if ( !type->typ_ops || !type->typ_ops->o_iocontrol ) {
764                         EXIT;
765                         return -EOPNOTSUPP;
766                 }
767                 conn.oc_id = input.att_connid;
768                 
769                 CDEBUG(D_IOCTL, "Calling ioctl %x for type %s, len %d\n",
770                        cmd, type->typ_name, input.att_datalen);
771
772                 /* get the generic data */
773                 karg = input.att_data;
774                 err = getdata(input.att_datalen, &karg);
775                 if ( err ) {
776                         EXIT;
777                         return err;
778                 }
779
780                 err = type->typ_ops->o_iocontrol(cmd, &conn, input.att_datalen, 
781                                                  karg, input.att_data);
782                 OBD_FREE(karg, input.att_datalen);
783
784                 EXIT;
785                 return err;
786         }
787         }
788 }
789
790 /* Driver interface done, utility functions follow */
791
792 int obd_register_type(struct obd_ops *ops, char *nm)
793 {
794         struct obd_type *type;
795
796
797         if (obd_init_magic != 0x11223344) {
798                 EXIT;
799                 return -EINVAL;
800         }
801
802         if  ( obd_nm_to_type(nm) ) {
803                 CDEBUG(D_IOCTL, "Type %s already registered\n", nm);
804                 EXIT;
805                 return -EEXIST;
806         }
807         
808         OBD_ALLOC(type, struct obd_type * , sizeof(*type));
809         if ( !type ) {
810                 EXIT;
811                 return -ENOMEM;
812         }
813         memset(type, 0, sizeof(*type));
814         INIT_LIST_HEAD(&type->typ_chain);
815         MOD_INC_USE_COUNT;
816         list_add(&type->typ_chain, obd_types.next);
817         type->typ_ops = ops;
818         type->typ_name = nm;
819         EXIT;
820         return 0;
821 }
822         
823 int obd_unregister_type(char *nm)
824 {
825         struct obd_type *type = obd_nm_to_type(nm);
826
827         if ( !type ) {
828                 MOD_DEC_USE_COUNT;
829                 printk("Unknown obd type\n");
830                 EXIT;
831                 return -EINVAL;
832         }
833
834         if ( type->typ_refcnt ) {
835                 MOD_DEC_USE_COUNT;
836                 printk("OBD: Type %s has refcount (%d)\n", nm,
837                        type->typ_refcnt);
838                 EXIT;
839                 return -EBUSY;
840         }
841
842         list_del(&type->typ_chain);
843         OBD_FREE(type, sizeof(*type));
844         MOD_DEC_USE_COUNT;
845         return 0;
846 }
847
848 /* declare character device */
849 static struct file_operations obd_psdev_fops = {
850         NULL,                  /* llseek */
851         NULL,                  /* read */
852         NULL,                  /* write */
853         NULL,                  /* presto_psdev_readdir */
854         NULL,                  /* poll */
855         obd_class_ioctl,       /* ioctl */
856         NULL,                  /* presto_psdev_mmap */
857         obd_class_open,        /* open */
858         NULL,
859         obd_class_release,     /* release */
860         NULL,                  /* fsync */
861         NULL,                  /* fasync */
862         NULL,                  /* check_media_change */
863         NULL,                  /* revalidate */
864         NULL                   /* lock */
865 };
866
867
868 /* modules setup */
869
870 int init_obd(void)
871 {
872         int err;
873         int i;
874
875         printk(KERN_INFO "OBD class driver  v0.01, braam@stelias.com\n");
876         
877         INIT_LIST_HEAD(&obd_types);
878         
879         if (register_chrdev(OBD_PSDEV_MAJOR,"obd_psdev", 
880                             &obd_psdev_fops)) {
881                 printk(KERN_ERR "obd_psdev: unable to get major %d\n", 
882                        OBD_PSDEV_MAJOR);
883                 return -EIO;
884         }
885
886         for (i = 0; i < MAX_OBD_DEVICES; i++) {
887                 memset(&(obd_dev[i]), 0, sizeof(obd_dev[i]));
888                 obd_dev[i].obd_minor = i;
889                 INIT_LIST_HEAD(&obd_dev[i].obd_gen_clients);
890         }
891
892         err = obd_init_obdo_cache();
893         if (err)
894                 return err;
895         obd_sysctl_init();
896         obd_init_magic = 0x11223344;
897         return 0;
898 }
899
900 EXPORT_SYMBOL(obd_register_type);
901 EXPORT_SYMBOL(obd_unregister_type);
902
903 EXPORT_SYMBOL(obd_print_entry);
904 EXPORT_SYMBOL(obd_debug_level);
905 EXPORT_SYMBOL(obd_dev);
906
907 EXPORT_SYMBOL(gen_connect);
908 EXPORT_SYMBOL(gen_client);
909 EXPORT_SYMBOL(gen_cleanup);
910 EXPORT_SYMBOL(gen_disconnect);
911 EXPORT_SYMBOL(gen_copy_data); 
912 EXPORT_SYMBOL(obdo_cachep);
913
914 /* EXPORT_SYMBOL(gen_multi_attach); */
915 EXPORT_SYMBOL(gen_multi_setup);
916 EXPORT_SYMBOL(gen_multi_cleanup);
917
918
919 #ifdef MODULE
920 int init_module(void)
921 {
922         return init_obd();
923 }
924
925 void cleanup_module(void)
926 {
927         int i;
928         ENTRY;
929
930         unregister_chrdev(OBD_PSDEV_MAJOR, "obd_psdev");
931         for (i = 0; i < MAX_OBD_DEVICES; i++) {
932                 struct obd_device *obddev = &obd_dev[i];
933                 if ( obddev->obd_type && 
934                      (obddev->obd_flags & OBD_SET_UP) &&
935                      OBT(obddev) && OBP(obddev, detach) ) {
936                         /* XXX should this call generic detach otherwise? */
937                         OBP(obddev, detach)(obddev);
938                 } 
939         }
940
941         obd_cleanup_obdo_cache();
942         obd_sysctl_clean();
943         obd_init_magic = 0;
944         EXIT;
945 }
946 #endif