Whamcloud - gitweb
3202dff032b0275f69014f1abdcb8dc791de2f40
[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  *              version 2 as published by the Free Software Foundation.
10  * 
11  *              Adapted to become the Linux 2.0 Coda pseudo device
12  *              Peter  Braam  <braam@maths.ox.ac.uk> 
13  *              Michael Callahan <mjc@emmy.smith.edu>           
14  *
15  *              Changes for Linux 2.1
16  *              Copyright (c) 1997 Carnegie-Mellon University
17  *
18  *              Redone again for Intermezzo
19  *              Copyright (c) 1998 Peter J. Braam
20  *
21  *              Hacked up again for simulated OBD
22  *              Copyright (c) 1999 Stelias Computing, Inc.
23  *                (authors {pschwan,braam}@stelias.com)
24  *              Copyright (C) 1999 Seagate Technology, Inc.
25  *              Copyright (C) 2001 Cluster File Systems, Inc.
26  *
27  * 
28  */
29
30 #define EXPORT_SYMTAB
31 #include <linux/config.h> /* for CONFIG_PROC_FS */
32 #include <linux/module.h>
33 #include <linux/errno.h>
34 #include <linux/kernel.h>
35 #include <linux/major.h>
36 #include <linux/kmod.h>   /* for request_module() */
37 #include <linux/sched.h>
38 #include <linux/lp.h>
39 #include <linux/slab.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/system.h>
52 #include <asm/poll.h>
53 #include <asm/uaccess.h>
54 #include <linux/miscdevice.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 = ~0;
62 long obd_memory = 0;
63 struct obd_device obd_dev[MAX_OBD_DEVICES];
64 struct list_head obd_types;
65
66 /*  opening /dev/obd */
67 static int obd_class_open(struct inode * inode, struct file * file)
68 {
69         ENTRY;
70
71         file->private_data = NULL;
72         MOD_INC_USE_COUNT;
73         EXIT;
74         return 0;
75 }
76
77 /*  closing /dev/obd */
78 static int obd_class_release(struct inode * inode, struct file * file)
79 {
80         ENTRY;
81
82         if (file->private_data)
83                 file->private_data = NULL;
84
85         MOD_DEC_USE_COUNT;
86         EXIT;
87         return 0;
88 }
89
90 /* 
91  * support functions: we could use inter-module communication, but this 
92  * is more portable to other OS's
93  */
94 static struct obd_type *obd_search_type(char *nm)
95 {
96         struct list_head *tmp;
97         struct obd_type *type;
98         CDEBUG(D_INFO, "SEARCH %s\n", nm);
99         
100         tmp = &obd_types;
101         while ( (tmp = tmp->next) != &obd_types ) {
102                 type = list_entry(tmp, struct obd_type, typ_chain);
103                 CDEBUG(D_INFO, "TYP %s\n", type->typ_name);
104                 if (strlen(type->typ_name) == strlen(nm) &&
105                     strcmp(type->typ_name, nm) == 0 ) {
106                         return type;
107                 }
108         }
109         return NULL;
110 }
111
112 static struct obd_type *obd_nm_to_type(char *nm) 
113 {
114         struct obd_type *type = obd_search_type(nm);
115
116 #ifdef CONFIG_KMOD
117         if ( !type ) {
118                 if ( !request_module(nm) ) {
119                         CDEBUG(D_PSDEV, "Loaded module '%s'\n", nm);
120                         type = obd_search_type(nm);
121                 } else {
122                         CDEBUG(D_PSDEV, "Can't load module '%s'\n", nm);
123                 }
124         }
125 #endif
126         return type;
127 }
128
129 /* to control /dev/obd */
130 static int obd_class_ioctl (struct inode * inode, struct file * filp, 
131                             unsigned int cmd, unsigned long arg)
132 {
133         /* NOTE this must be larger than any of the ioctl data structs */
134         char buf[1024];
135         struct obd_ioctl_data *data;
136         struct obd_device *obd = filp->private_data;
137         struct obd_conn conn;
138         int err = 0;
139         ENTRY;
140
141         memset(buf, 0, sizeof(buf));
142
143         if (!obd && cmd != OBD_IOC_DEVICE && cmd != TCGETS) {
144                 printk("OBD ioctl: No device\n");
145                 return -EINVAL;
146         } 
147         if (obd_ioctl_getdata(buf, buf + 800, (void *)arg)) { 
148                 printk("OBD ioctl: data error\n");
149                 return -EINVAL;
150         }
151         data = (struct obd_ioctl_data *)buf;
152
153         switch (cmd) {
154         case TCGETS: { 
155                 EXIT;
156                 return -EINVAL;
157         }
158         case OBD_IOC_DEVICE: { 
159                 CDEBUG(D_IOCTL, "\n");
160                 if (data->ioc_dev >= MAX_OBD_DEVICES ||
161                     data->ioc_dev < 0) { 
162                         printk("OBD ioctl: DEVICE insufficient devices\n");
163                         return -EINVAL;
164                 }
165                 CDEBUG(D_IOCTL, "device %d\n", data->ioc_dev);
166
167                 filp->private_data = &obd_dev[data->ioc_dev];
168                 EXIT;
169                 return 0;
170         }
171
172         case OBD_IOC_ATTACH: {
173                 struct obd_type *type;
174
175                 ENTRY;
176                 /* have we attached a type to this device */
177                 if ( obd->obd_type ||  (obd->obd_flags & OBD_ATTACHED) ){
178                         printk("OBD: Device %d already typed as  %s.\n",
179                                obd->obd_minor, MKSTR(obd->obd_type->typ_name));
180                         return -EBUSY;
181                 }
182
183                 printk("-----> attach %s %s\n",  MKSTR(data->ioc_inlbuf1), 
184                        MKSTR(data->ioc_inlbuf2));
185
186                 /* find the type */
187                 type = obd_nm_to_type(data->ioc_inlbuf1);
188                 if ( !type ) {
189                         printk("OBD: unknown type dev %d\n", obd->obd_minor);
190                         return -EINVAL;
191                 }
192
193                 obd->obd_type = type;
194                 obd->obd_multi_count = 0;
195                 INIT_LIST_HEAD(&obd->obd_gen_clients);
196
197                 /* do the attach */
198                 if ( OBT(obd) && OBP(obd, attach) ) {
199                         err = OBP(obd, attach)(obd, sizeof(*data), data);
200                 }
201
202                 if ( err ) {
203                         obd->obd_flags &= ~OBD_ATTACHED;
204                         obd->obd_type = NULL;
205                         EXIT;
206                 } else {
207                         obd->obd_flags |=  OBD_ATTACHED;
208                         type->typ_refcnt++;
209                         printk("OBD: dev %d attached type %s\n", 
210                                obd->obd_minor, data->ioc_inlbuf1);
211                         obd->obd_proc_entry = 
212                                 proc_lustre_register_obd_device(obd);
213                         MOD_INC_USE_COUNT;
214                         EXIT;
215                 }
216
217                 return err;
218         }
219
220         case OBD_IOC_DETACH: {
221                 ENTRY;
222                 if (obd->obd_flags & OBD_SET_UP) {
223                         printk("OBD device %d still set up\n", obd->obd_minor);
224                         return -EBUSY;
225                 }
226                 if (! (obd->obd_flags & OBD_ATTACHED) ) {
227                         printk("OBD device %d not attached\n", obd->obd_minor);
228                         return -ENODEV;
229                 }
230                 if ( !list_empty(&obd->obd_gen_clients) ) {
231                         printk("OBD device %d has connected clients\n", obd->obd_minor);
232                         return -EBUSY;
233                 }
234
235                 if (obd->obd_proc_entry)
236                         proc_lustre_release_obd_device(obd);
237
238                 obd->obd_flags &= ~OBD_ATTACHED;
239                 obd->obd_type->typ_refcnt--;
240                 obd->obd_type = NULL;
241                 MOD_DEC_USE_COUNT;
242                 EXIT;
243                 return 0;
244         }
245
246         case OBD_IOC_SETUP: {
247                 ENTRY;
248                 /* have we attached a type to this device? */
249                 if (!(obd->obd_flags & OBD_ATTACHED)) {
250                         printk("Device %d not attached\n", obd->obd_minor);
251                         return -ENODEV;
252                 }
253
254                 /* has this been done already? */
255                 if ( obd->obd_flags & OBD_SET_UP ) {
256                         printk("Device %d already setup (type %s)\n",
257                                obd->obd_minor, obd->obd_type->typ_name);
258                         return -EBUSY;
259                 }
260
261                 if ( OBT(obd) && OBP(obd, setup) )
262                         err = OBP(obd, setup)(obd, sizeof(*data), data);
263
264                 if (!err) { 
265                         obd->obd_type->typ_refcnt++;
266                         obd->obd_flags |= OBD_SET_UP;
267                         EXIT;
268                 }
269
270                 return err;
271         }
272         case OBD_IOC_CLEANUP: {
273                 ENTRY;
274
275                 err = obd_cleanup(obd);
276                 if ( err ) {
277                         EXIT;
278                         return err;
279                 }
280
281                 obd->obd_flags &= ~OBD_SET_UP;
282                 obd->obd_type->typ_refcnt--;
283                 EXIT;
284                 return 0;
285         }
286
287         case OBD_IOC_CONNECT:
288         {
289                 conn.oc_id = data->ioc_conn1;
290                 conn.oc_dev = obd; 
291
292                 err = obd_connect(&conn);
293
294                 CDEBUG(D_IOCTL, "assigned connection %d\n", conn.oc_id);
295                 data->ioc_conn1 = conn.oc_id;
296                 if ( err )
297                         return err;
298
299                 return copy_to_user((int *)arg, data, sizeof(*data));
300         }
301
302         case OBD_IOC_DISCONNECT: { 
303                 conn.oc_id = data->ioc_conn1;
304                 conn.oc_dev = obd;
305
306                 err = obd_disconnect(&conn);
307                 return err;
308         }               
309
310         case OBD_IOC_DEC_USE_COUNT: { 
311                 MOD_DEC_USE_COUNT;
312                 return 0;
313         }
314
315         case OBD_IOC_CREATE: {
316                 conn.oc_id = data->ioc_conn1;
317                 conn.oc_dev = obd;
318
319                 err = obd_create(&conn, &data->ioc_obdo1);
320                 if (err) {
321                         EXIT;
322                         return err;
323                 }
324
325                 err = copy_to_user((int *)arg, data, sizeof(*data));
326                 EXIT;
327                 return err;
328         }
329
330         case OBD_IOC_GETATTR: {
331                 conn.oc_id = data->ioc_conn1;
332                 conn.oc_dev = obd;
333
334                 err = obd_getattr(&conn, &data->ioc_obdo1);
335                 if (err) {
336                         EXIT;
337                         return err;
338                 }
339
340                 err = copy_to_user((int *)arg, data, sizeof(*data));
341                 EXIT;
342                 return err;
343         }
344
345         case OBD_IOC_SETATTR: {
346                 conn.oc_id = data->ioc_conn1;
347                 conn.oc_dev = obd;
348
349                 err = obd_setattr(&conn, &data->ioc_obdo1);
350                 if (err) {
351                         EXIT;
352                         return err;
353                 }
354
355                 err = copy_to_user((int *)arg, data, sizeof(*data));
356                 EXIT;
357                 return err;
358         }
359
360         case OBD_IOC_DESTROY: {
361                 conn.oc_id = data->ioc_conn1;
362                 conn.oc_dev = obd;
363
364                 err = obd_destroy(&conn, &data->ioc_obdo1);
365                 if (err) {
366                         EXIT;
367                         return err;
368                 }
369
370                 err = copy_to_user((int *)arg, data, sizeof(*data));
371                 EXIT;
372                 return err;
373         }
374
375 #if 0
376         case OBD_IOC_SYNC: {
377                 struct oic_range_s *range = tmp_buf;
378
379                 if (!obd->obd_type)
380                         return -ENODEV;
381
382                 err = copy_from_user(range, (const void *)arg,  sizeof(*range));
383
384                 if ( err ) {
385                         EXIT;
386                         return err;
387                 }
388                         
389                 if ( !OBT(obd) || !OBP(obd, sync) ) {
390                         err = -EOPNOTSUPP;
391                         EXIT;
392                         return err;
393                 }
394
395                 /* XXX sync needs to be tested/verified */
396                 err = OBP(obd, sync)(&conn, &range->obdo, range->count,
397                                         range->offset);
398
399                 if ( err ) {
400                         EXIT;
401                         return err;
402                 }
403                         
404                 return put_user(err, (int *) arg);
405         }
406
407         case OBD_IOC_READ: {
408                 int err;
409                 struct oic_rw_s *rw_s = tmp_buf;  /* read, write ioctl str */
410
411                 err = copy_from_user(rw_s, (int *)arg, sizeof(*rw_s));
412                 if ( err ) {
413                         EXIT;
414                         return err;
415                 }
416
417                 conn.oc_id = rw_s->conn_id;
418
419                 if ( !OBT(obd) || !OBP(obd, read) ) {
420                         err = -EOPNOTSUPP;
421                         EXIT;
422                         return err;
423                 }
424
425
426                 err = OBP(obd, read)(&conn, &rw_s->obdo, rw_s->buf, 
427                                         &rw_s->count, rw_s->offset);
428                 
429                 ODEBUG(&rw_s->obdo);
430                 CDEBUG(D_INFO, "READ: conn %d, count %Ld, offset %Ld, '%s'\n",
431                        rw_s->conn_id, rw_s->count, rw_s->offset, rw_s->buf);
432                 if ( err ) {
433                         EXIT;
434                         return err;
435                 }
436                         
437                 err = copy_to_user((int*)arg, &rw_s->count, sizeof(rw_s->count));
438                 EXIT;
439                 return err;
440         }
441
442         case OBD_IOC_WRITE: {
443                 struct oic_rw_s *rw_s = tmp_buf;  /* read, write ioctl str */
444
445                 err = copy_from_user(rw_s, (int *)arg, sizeof(*rw_s));
446                 if ( err ) {
447                         EXIT;
448                         return err;
449                 }
450
451                 conn.oc_id = rw_s->conn_id;
452
453                 if ( !OBT(obd) || !OBP(obd, write) ) {
454                         err = -EOPNOTSUPP;
455                         return err;
456                 }
457
458                 CDEBUG(D_INFO, "WRITE: conn %d, count %Ld, offset %Ld, '%s'\n",
459                        rw_s->conn_id, rw_s->count, rw_s->offset, rw_s->buf);
460
461                 err = OBP(obd, write)(&conn, &rw_s->obdo, rw_s->buf, 
462                                          &rw_s->count, rw_s->offset);
463                 ODEBUG(&rw_s->obdo);
464                 if ( err ) {
465                         EXIT;
466                         return err;
467                 }
468
469                 err = copy_to_user((int *)arg, &rw_s->count,
470                                    sizeof(rw_s->count));
471                 EXIT;
472                 return err;
473         }
474         case OBD_IOC_PREALLOCATE: {
475                 struct oic_prealloc_s *prealloc = tmp_buf;
476
477                 /* has this minor been registered? */
478                 if (!obd->obd_type)
479                         return -ENODEV;
480
481                 err = copy_from_user(prealloc, (int *)arg, sizeof(*prealloc));
482                 if (err) 
483                         return -EFAULT;
484
485                 if ( !(obd->obd_flags & OBD_ATTACHED) ||
486                      !(obd->obd_flags & OBD_SET_UP)) {
487                         CDEBUG(D_IOCTL, "Device not attached or set up\n");
488                         return -ENODEV;
489                 }
490
491                 if ( !OBT(obd) || !OBP(obd, preallocate) )
492                         return -EOPNOTSUPP;
493
494                 conn.oc_id = prealloc->conn_id;
495                 err = OBP(obd, preallocate)(&conn, &prealloc->alloc,
496                                                prealloc->ids);
497                 if ( err ) {
498                         EXIT;
499                         return err;
500                 }
501
502                 err =copy_to_user((int *)arg, prealloc, sizeof(*prealloc));
503                 EXIT;
504                 return err;
505         }
506         case OBD_IOC_STATFS: {
507                 struct statfs *tmp;
508                 unsigned int conn_id;
509                 struct statfs buf;
510
511                 /* has this minor been registered? */
512                 if (!obd->obd_type)
513                         return -ENODEV;
514
515                 tmp = (void *)arg + sizeof(unsigned int);
516                 get_user(conn_id, (int *) arg);
517
518                 if ( !OBT(obd) || !OBP(obd, statfs) )
519                         return -EOPNOTSUPP;
520
521                 conn.oc_id = conn_id;
522                 err = OBP(obd, statfs)(&conn, &buf);
523                 if ( err ) {
524                         EXIT;
525                         return err;
526                 }
527                 err = copy_to_user(tmp, &buf, sizeof(buf));
528                 EXIT;
529                 return err;
530                 
531         }
532         case OBD_IOC_COPY: {
533                 struct ioc_mv_s *mvdata = tmp_buf;
534
535                 if ( (!(obd->obd_flags & OBD_SET_UP)) ||
536                      (!(obd->obd_flags & OBD_ATTACHED))) {
537                         CDEBUG(D_IOCTL, "Device not attached or set up\n");
538                         return -ENODEV;
539                 }
540
541                 /* get main structure */
542                 err = copy_from_user(mvdata, (void *) arg, sizeof(*mvdata));
543                 if (err) {
544                         EXIT;
545                         return err;
546                 }
547
548                 if ( !OBT(obd) || !OBP(obd, copy) )
549                         return -EOPNOTSUPP;
550
551                 /* do the partition */
552                 CDEBUG(D_INFO, "Copy %d, type %s dst %Ld src %Ld\n", dev, 
553                        obd->obd_type->typ_name, mvdata->dst.o_id, 
554                        mvdata->src.o_id);
555
556                 conn.oc_id = mvdata->src_conn_id;
557
558                 err = OBP(obd, copy)(&conn, &mvdata->dst, 
559                                         &conn, &mvdata->src, 
560                                         mvdata->src.o_size, 0);
561                 return err;
562         }
563
564         case OBD_IOC_MIGR: {
565                 struct ioc_mv_s *mvdata = tmp_buf;
566
567                 if ( (!(obd->obd_flags & OBD_SET_UP)) ||
568                      (!(obd->obd_flags & OBD_ATTACHED))) {
569                         CDEBUG(D_IOCTL, "Device not attached or set up\n");
570                         return -ENODEV;
571                 }
572
573                 err = copy_from_user(mvdata, (void *) arg, sizeof(*mvdata));
574                 if (err) {
575                         EXIT;
576                         return err;
577                 }
578
579                 CDEBUG(D_INFO, "Migrate copying %d bytes\n", sizeof(*mvdata));
580
581                 if ( !OBT(obd) || !OBP(obd, migrate) )
582                         return -EOPNOTSUPP;
583
584                 /* do the partition */
585                 CDEBUG(D_INFO, "Migrate %d, type %s conn %d src %Ld dst %Ld\n",
586                        dev, obd->obd_type->typ_name, mvdata->src_conn_id,
587                        mvdata->src.o_id, mvdata->dst.o_id);
588
589                 conn.oc_id = mvdata->src_conn_id;
590                 err = OBP(obd, migrate)(&conn, &mvdata->dst, &mvdata->src, 
591                                            mvdata->src.o_size, 0);
592
593                 return err;
594         }
595         case OBD_IOC_PUNCH: {
596                 struct oic_rw_s *rw_s = tmp_buf;  /* read, write ioctl str */
597
598                 err = copy_from_user(rw_s, (int *)arg, sizeof(*rw_s));
599                 if ( err ) {
600                         EXIT;
601                         return err;
602                 }
603
604                 conn.oc_id = rw_s->conn_id;
605
606                 if ( !OBT(obd) || !OBP(obd, punch) ) {
607                         err = -EOPNOTSUPP;
608                         return err;
609                 }
610
611                 CDEBUG(D_INFO, "PUNCH: conn %d, count %Ld, offset %Ld\n",
612                        rw_s->conn_id, rw_s->count, rw_s->offset);
613                 err = OBP(obd, punch)(&conn, &rw_s->obdo, rw_s->count,
614                                          rw_s->offset);
615                 ODEBUG(&rw_s->obdo);
616                 if ( err ) {
617                         EXIT;
618                         return err;
619                 }
620                 EXIT;
621                 return err;
622         }
623
624         default: {
625                 struct obd_type *type;
626                 struct oic_generic input;
627                 char *nm;
628                 void *karg;
629
630                 /* get data structures */
631                 err = copy_from_user(&input, (void *)arg, sizeof(input));
632                 if ( err ) {
633                         EXIT;
634                         return err;
635                 }
636
637                 err = getdata(input.att_typelen + 1, &input.att_type);
638                 if ( err ) {
639                         EXIT;
640                         return err;
641                 }
642
643                 /* find the type */
644                 nm = input.att_type;
645                 type = obd_nm_to_type(nm);
646 #ifdef CONFIG_KMOD
647                 if ( !type ) {
648                         if ( !request_module(nm) ) {
649                                 CDEBUG(D_PSDEV, "Loaded module '%s'\n", nm);
650                                 type = obd_nm_to_type(nm);
651                         } else {
652                                 CDEBUG(D_PSDEV, "Can't load module '%s'\n", nm);
653                         }
654                 }
655 #endif
656                 OBD_FREE(input.att_type, input.att_typelen + 1);
657                 if ( !type ) {
658                         printk(__FUNCTION__ ": unknown obd type dev %d\n", dev);
659                         EXIT;
660                         return -EINVAL;
661                 }
662                 
663                 if ( !type->typ_ops || !type->typ_ops->o_iocontrol ) {
664                         EXIT;
665                         return -EOPNOTSUPP;
666                 }
667                 conn.oc_id = input.att_connid;
668                 
669                 CDEBUG(D_INFO, "Calling ioctl %x for type %s, len %d\n",
670                        cmd, type->typ_name, input.att_datalen);
671
672                 /* get the generic data */
673                 karg = input.att_data;
674                 err = getdata(input.att_datalen, &karg);
675                 if ( err ) {
676                         EXIT;
677                         return err;
678                 }
679
680                 err = type->typ_ops->o_iocontrol(cmd, &conn, input.att_datalen, 
681                                                  karg, input.att_data);
682                 OBD_FREE(karg, input.att_datalen);
683
684                 EXIT;
685                 return err;
686         }
687 #endif 
688         default:
689                 return -EINVAL;
690
691         }
692 } /* obd_class_ioctl */
693
694
695 /* Driver interface done, utility functions follow */
696 int obd_register_type(struct obd_ops *ops, char *nm)
697 {
698         struct obd_type *type;
699
700
701         if (obd_init_magic != 0x11223344) {
702                 printk(__FUNCTION__ ": bad magic for type\n");
703                 EXIT;
704                 return -EINVAL;
705         }
706
707         if  ( obd_nm_to_type(nm) ) {
708                 CDEBUG(D_IOCTL, "Type %s already registered\n", nm);
709                 EXIT;
710                 return -EEXIST;
711         }
712         
713         OBD_ALLOC(type, struct obd_type * , sizeof(*type));
714         if ( !type ) {
715                 EXIT;
716                 return -ENOMEM;
717         }
718         memset(type, 0, sizeof(*type));
719         INIT_LIST_HEAD(&type->typ_chain);
720         MOD_INC_USE_COUNT;
721         list_add(&type->typ_chain, obd_types.next);
722         type->typ_ops = ops;
723         type->typ_name = nm;
724         EXIT;
725         return 0;
726 }
727         
728 int obd_unregister_type(char *nm)
729 {
730         struct obd_type *type = obd_nm_to_type(nm);
731
732         if ( !type ) {
733                 MOD_DEC_USE_COUNT;
734                 printk(KERN_INFO __FUNCTION__ ": unknown obd type\n");
735                 EXIT;
736                 return -EINVAL;
737         }
738
739         if ( type->typ_refcnt ) {
740                 MOD_DEC_USE_COUNT;
741                 printk(KERN_ALERT __FUNCTION__ ":type %s has refcount "
742                        "(%d)\n", nm, type->typ_refcnt);
743                 EXIT;
744                 return -EBUSY;
745         }
746
747         list_del(&type->typ_chain);
748         OBD_FREE(type, sizeof(*type));
749         MOD_DEC_USE_COUNT;
750         return 0;
751 } /* obd_unregister_type */
752
753 /* declare character device */
754 static struct file_operations obd_psdev_fops = {
755         ioctl: obd_class_ioctl,       /* ioctl */
756         open: obd_class_open,        /* open */
757         release: obd_class_release,     /* release */
758 };
759
760
761 /* modules setup */
762 #define OBD_MINOR 241
763 static struct miscdevice obd_psdev = {
764         OBD_MINOR,
765         "obd_psdev",
766         &obd_psdev_fops
767 };
768
769 int init_obd(void)
770 {
771         int err;
772         int i;
773
774         printk(KERN_INFO "OBD class driver  v0.01, braam@stelias.com\n");
775         
776         INIT_LIST_HEAD(&obd_types);
777         
778         if ( (err = misc_register(&obd_psdev)) ) { 
779                 printk(KERN_ERR __FUNCTION__ ": cannot register %d err %d\n", 
780                        OBD_MINOR, err);
781                 return -EIO;
782         }
783
784         for (i = 0; i < MAX_OBD_DEVICES; i++) {
785                 memset(&(obd_dev[i]), 0, sizeof(obd_dev[i]));
786                 obd_dev[i].obd_minor = i;
787                 INIT_LIST_HEAD(&obd_dev[i].obd_gen_clients);
788         }
789
790         err = obd_init_obdo_cache();
791         if (err)
792                 return err;
793         obd_sysctl_init();
794         obd_init_magic = 0x11223344;
795         return 0;
796 }
797
798 EXPORT_SYMBOL(obd_register_type);
799 EXPORT_SYMBOL(obd_unregister_type);
800
801 EXPORT_SYMBOL(obd_print_entry);
802 EXPORT_SYMBOL(obd_debug_level);
803 EXPORT_SYMBOL(obd_dev);
804
805 EXPORT_SYMBOL(gen_connect);
806 EXPORT_SYMBOL(gen_client);
807 EXPORT_SYMBOL(gen_cleanup);
808 EXPORT_SYMBOL(gen_disconnect);
809 EXPORT_SYMBOL(gen_copy_data); 
810 EXPORT_SYMBOL(obdo_cachep);
811
812 /* EXPORT_SYMBOL(gen_multi_attach); */
813 EXPORT_SYMBOL(gen_multi_setup);
814 EXPORT_SYMBOL(gen_multi_cleanup);
815
816
817 #ifdef MODULE
818 int init_module(void)
819 {
820         return init_obd();
821 }
822
823 void cleanup_module(void)
824 {
825         int i;
826         ENTRY;
827
828         misc_deregister(&obd_psdev);
829         for (i = 0; i < MAX_OBD_DEVICES; i++) {
830                 struct obd_device *obd = &obd_dev[i];
831                 if ( obd->obd_type && 
832                      (obd->obd_flags & OBD_SET_UP) &&
833                      OBT(obd) && OBP(obd, detach) ) {
834                         /* XXX should this call generic detach otherwise? */
835                         OBP(obd, detach)(obd);
836                 } 
837         }
838
839         obd_cleanup_obdo_cache();
840         obd_sysctl_clean();
841         CDEBUG(D_MALLOC, "CLASS mem used %ld\n", obd_memory);
842         obd_init_magic = 0;
843         EXIT;
844 }
845 #endif