Whamcloud - gitweb
69731015af1ae57eccda8845aaa788b19a69fd45
[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 int           obd_print_entry = 1;
60 int           obd_debug_level = 4095;
61 struct obd_device obd_dev[MAX_OBD_DEVICES];
62 struct list_head obd_types;
63
64 /* called when opening /dev/obdNNN */
65 static int obd_class_open(struct inode * inode, struct file * file)
66 {
67         int dev;
68         ENTRY;
69
70         if (!inode)
71                 return -EINVAL;
72         dev = MINOR(inode->i_rdev);
73         if (dev >= MAX_OBD_DEVICES)
74                 return -ENODEV;
75         obd_dev[dev].obd_refcnt++;
76         CDEBUG(D_PSDEV, "Refcount now %d\n", obd_dev[dev].obd_refcnt++);
77
78         MOD_INC_USE_COUNT;
79         EXIT;
80         return 0;
81 }
82
83 /* called when closing /dev/obdNNN */
84 static int obd_class_release(struct inode * inode, struct file * file)
85 {
86         int dev;
87         ENTRY;
88
89         if (!inode)
90                 return -EINVAL;
91         dev = MINOR(inode->i_rdev);
92         if (dev >= MAX_OBD_DEVICES)
93                 return -ENODEV;
94         fsync_dev(inode->i_rdev);
95         if (obd_dev[dev].obd_refcnt <= 0)
96                 printk(KERN_ALERT "presto_psdev_release: refcount(%d) <= 0\n",
97                        obd_dev[dev].obd_refcnt);
98         obd_dev[dev].obd_refcnt--;
99
100         CDEBUG(D_PSDEV, "Refcount now %d\n", obd_dev[dev].obd_refcnt++);
101
102         MOD_DEC_USE_COUNT;
103
104         EXIT;
105         return 0;
106 }
107
108 /* support function */
109 static struct obd_type *obd_nm_to_type(char *nm) 
110 {
111         struct list_head *tmp;
112         struct obd_type *type;
113         
114         tmp = &obd_types;
115         while ( (tmp = tmp->next) != &obd_types ) {
116                 type = list_entry(tmp, struct obd_type, typ_chain);
117                 if (strlen(type->typ_name) == strlen(nm) &&
118                     strcmp(type->typ_name, nm) == 0 ) {
119                         return type;
120                 }
121         }
122         return NULL;
123 }
124
125
126 static int getdata(int len, void **data)
127 {
128         void *tmp = NULL;
129
130         if (!len) 
131                 return 0;
132
133         OBD_ALLOC(tmp, void *, len);
134         if ( !tmp )
135                 return -ENOMEM;
136         
137         memset(tmp, 0, len);
138         if ( copy_from_user(tmp, *data, len)) {
139                 OBD_FREE(tmp,len);
140                 return -EFAULT;
141         }
142         *data = tmp;
143
144         return 0;
145 }
146
147 /* to control /dev/obdNNN */
148 static int obd_class_ioctl (struct inode * inode, struct file * filp, 
149                             unsigned int cmd, unsigned long arg)
150 {
151         int err, i_ino, dev;
152         struct obd_device *obddev;
153         struct oic_rw_s rw_s; /* read, write */
154         long int cli_id; /* connect, disconnect */
155
156         struct oic_prealloc_s prealloc; /* preallocate */
157
158         if (!inode)
159                 return -EINVAL;
160
161         dev = MINOR(inode->i_rdev);
162         if (dev > MAX_OBD_DEVICES)
163                 return -ENODEV;
164         obddev = &obd_dev[dev];
165
166         switch (cmd) {
167         case OBD_IOC_ATTACH: {
168                 struct obd_type *type;
169                 struct oic_attach input;
170
171                 /* have we attached a type to this device */
172                 if ( obddev->obd_type || (obddev->obd_flags & OBD_ATTACHED) ){
173                         CDEBUG(D_IOCTL, "OBD Device %d already attached to type %s.\n", dev, obddev->obd_type->typ_name);
174                         return -EINVAL;
175                 }
176
177                 /* get data structures */
178                 err = copy_from_user(&input, (void *) arg, sizeof(input));
179                 if (err)
180                         return err;
181
182                 if ( (err = getdata(input.att_typelen + 1, &input.att_type)) )
183                         return err;
184
185                 /* find the type */
186                 err = -EINVAL;
187                 type = obd_nm_to_type(input.att_type);
188                 OBD_FREE(input.att_type, input.att_typelen + 1);
189                 if ( !type ) {
190                         printk("Unknown obd type dev %d\n", dev);
191                         return err;
192                 }
193                 obddev->obd_type = type;
194                 
195                 /* get the attach data */
196                 if ( (err = getdata(input.att_datalen, &input.att_data)) ) {
197                         return err;
198                 }
199
200                 CDEBUG(D_IOCTL, "Attach %d, type %s\n", 
201                        dev, obddev->obd_type->typ_name);
202                 if (!obddev->obd_type->typ_ops || !OBP(obddev,attach)) {
203                         obddev->obd_flags |=  OBD_ATTACHED;
204                         type->typ_refcnt++;
205                         MOD_INC_USE_COUNT;
206                         return 0;
207                 }
208
209                 /* do the attach */
210                 err = OBP(obddev,attach)(obddev,  
211                                          input.att_datalen, &input.att_data);
212                 OBD_FREE(input.att_data, input.att_datalen);
213
214                 if ( err ) {
215                         obddev->obd_flags &= ~OBD_ATTACHED;
216                         obddev->obd_type = NULL;
217                 } else {
218                         obddev->obd_flags |=  OBD_ATTACHED;
219                         type->typ_refcnt++;
220                         MOD_INC_USE_COUNT;
221                 }
222                 return err;
223         }
224         case OBD_IOC_FORMAT: {
225                 struct ioc_format {
226                         int format_datalen;
227                         void *format_data;
228                 } input;
229
230                 /* have we attached a type to this device */
231                 if ( !obddev->obd_type ) {
232                         CDEBUG(D_IOCTL, "OBD Device %d has no type.\n", dev);
233                         return -EINVAL;
234                 }
235
236                 /* get main structure */
237                 err = copy_from_user(&input, (void *) arg, sizeof(input));
238                 if (err) 
239                         return err;
240
241                 err = getdata(input.format_datalen, &input.format_data);
242                 if (err) 
243                         return err;
244
245                 if (!obddev->obd_type->typ_ops || 
246                     !obddev->obd_type->typ_ops->o_format )
247                         return -EOPNOTSUPP;
248
249                 /* do the format */
250                 CDEBUG(D_IOCTL, "Format %d, type %s\n", dev, 
251                        obddev->obd_type->typ_name);
252                 err = obddev->obd_type->typ_ops->o_format
253                         (obddev, input.format_datalen, input.format_data);
254
255                 OBD_FREE(input.format_data, input.format_datalen);
256                 return err;
257         }
258         case OBD_IOC_PARTITION: {
259                 struct ioc_part {
260                         int part_datalen;
261                         void *part_data;
262                 } input;
263
264                 /* have we attached a type to this device */
265                 if ( !obddev->obd_type ) {
266                         CDEBUG(D_IOCTL, "OBD Device %d has no type.\n", dev);
267                         return -EINVAL;
268                 }
269
270                 /* get main structure */
271                 err = copy_from_user(&input, (void *) arg, sizeof(input));
272                 if (err) 
273                         return err;
274
275                 err = getdata(input.part_datalen, &input.part_data);
276                 if (err) 
277                         return err;
278
279                 if (!obddev->obd_type->typ_ops || 
280                     !obddev->obd_type->typ_ops->o_partition )
281                         return -EOPNOTSUPP;
282
283                 /* do the partition */
284                 CDEBUG(D_IOCTL, "Partition %d, type %s\n", dev, 
285                        obddev->obd_type->typ_name);
286                 err = obddev->obd_type->typ_ops->o_partition
287                         (obddev, input.part_datalen, input.part_data);
288
289                 OBD_FREE(input.part_data, input.part_datalen);
290                 return err;
291         }
292         case OBD_IOC_SETUP_OBDDEV: {
293                 struct ioc_setup {
294                         int setup_datalen;
295                         void *setup_data;
296                 } input;
297
298                 /* have we attached a type to this device */
299                 if (!(obddev->obd_flags & OBD_ATTACHED)) {
300                         CDEBUG(D_IOCTL, "OBD Device %d has no type.\n", dev);
301                         return -EINVAL;
302                 }
303
304                 /* has this been done already? */
305                 if ( obddev->obd_flags & OBD_SET_UP ) {
306                         CDEBUG(D_IOCTL, "Device %d already setup (type %s)\n",
307                                dev, obddev->obd_type->typ_name);
308                         return -EINVAL;
309                 }
310
311                 /* get main structure */
312                 err = copy_from_user(&input, (void *) arg, sizeof(input));
313                 if (err) 
314                         return err;
315
316                 err = getdata(input.setup_datalen, &input.setup_data);
317                 if (err) 
318                         return err;
319
320                 /* do the setup */
321                 CDEBUG(D_IOCTL, "Setup %d, type %s\n", dev, 
322                        obddev->obd_type->typ_name);
323                 if ( !obddev->obd_type->typ_ops || 
324                      !obddev->obd_type->typ_ops->o_setup ) {
325                         obddev->obd_flags |= OBD_SET_UP;
326                         return 0;
327                 }
328
329                 err = obddev->obd_type->typ_ops->o_setup
330                         (obddev, input.setup_datalen, input.setup_data);
331
332                 if ( err ) 
333                         obddev->obd_flags &= ~OBD_SET_UP;
334                 else 
335                         obddev->obd_flags |= OBD_SET_UP;
336                 return err;
337         }
338         case OBD_IOC_CLEANUP: {
339                 int rc;
340
341                 /* has this minor been registered? */
342                 if (!obddev->obd_type)
343                         return -ENODEV;
344
345                 if ( !obddev->obd_type->typ_refcnt ) 
346                         printk("OBD_CLEANUP: refcount wrap!\n");
347
348                 if ( !obddev->obd_type->typ_ops->o_cleanup )
349                         goto cleanup_out;
350
351                 /* cleanup has no argument */
352                 rc = OBP(obddev, cleanup)(obddev);
353                 if ( rc )
354                         return rc;
355
356         cleanup_out: 
357                 obddev->obd_flags = 0;
358                 obddev->obd_type->typ_refcnt--;
359                 obddev->obd_type = NULL;
360                 MOD_DEC_USE_COUNT;
361                 return 0;
362         }
363         case OBD_IOC_CONNECT:
364         {
365                 struct obd_conn_info conninfo;
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                         return -EINVAL;
371                 }
372
373                 if (obddev->obd_type->typ_ops->o_connect(obddev, &conninfo))
374                         return -EINVAL;
375
376                 return copy_to_user((int *)arg, &conninfo,
377                                     sizeof(struct obd_conn_info));
378         }
379         case OBD_IOC_DISCONNECT:
380                 /* frees data structures */
381                 /* has this minor been registered? */
382                 if (!obddev->obd_type)
383                         return -ENODEV;
384
385                 get_user(cli_id, (int *) arg);
386
387                 OBP(obddev, disconnect)(cli_id);
388                 return 0;
389
390         case OBD_IOC_SYNC: {
391                 /* sync doesn't need a connection ID, because it knows
392                  * what device it was called on, and can thus get the
393                  * superblock that it needs. */
394                 /* has this minor been registered? */
395                 if (!obddev->obd_type)
396                         return -ENODEV;
397
398                 if (!obddev->u.sim.sim_sb || !obddev->u.sim.sim_sb->s_dev) {
399                         CDEBUG(D_IOCTL, "fatal: device not initialized.\n");
400                         err = -EINVAL;
401                 } else {
402                         if ((err = fsync_dev(obddev->u.sim.sim_sb->s_dev)))
403                                 CDEBUG(D_IOCTL, "sync: fsync_dev failure\n");
404                         else
405                                 CDEBUG(D_IOCTL, "sync: success\n");
406                 }
407
408                 return put_user(err, (int *) arg);
409         }
410         case OBD_IOC_CREATE: {
411                 int err;
412                 struct oic_create_s foo;
413
414                 if ( copy_from_user(&foo, (const void *)arg, sizeof(foo)) )
415                         return -EFAULT;
416
417                 /* has this minor been registered? */
418                 if ( !(obddev->obd_flags & OBD_ATTACHED) ||
419                      !(obddev->obd_flags & OBD_SET_UP))
420                         return -ENODEV;
421
422
423                 if (!obddev->u.sim.sim_sb) {
424                         CDEBUG(D_IOCTL, "fatal: device not initialized.\n");
425                         return put_user(-EINVAL, (int *) arg);
426                 }
427
428                 i_ino = OBP(obddev, create)(foo.conn_id, foo.prealloc, &err);
429                 if (err) {
430                         CDEBUG(D_IOCTL, "create: obd_inode_new failure\n");
431                         /* 0 is the only error value */
432                         return put_user(0, (int *) arg);
433                 }
434
435                 return put_user(i_ino, (int *) arg);
436         }
437         case OBD_IOC_DESTROY:
438         {
439                 struct destroy_s {
440                         unsigned int conn_id;
441                         unsigned int ino;
442                 } destroy;
443
444                 /* has this minor been registered? */
445                 if (!obddev->obd_type)
446                         return -ENODEV;
447
448
449                 copy_from_user(&destroy, (int *)arg, sizeof(struct destroy_s));
450                 if ( !obddev->obd_type ||
451                      !obddev->obd_type->typ_ops->o_destroy)
452                         return -EINVAL;
453
454                 return obddev->obd_type->typ_ops->o_destroy(destroy.conn_id, destroy.ino);
455         }
456         case OBD_IOC_SETATTR:
457         {
458                 int err;
459                 struct oic_attr_s foo;
460                 struct inode holder;
461
462                 /* has this minor been registered? */
463                 if (!obddev->obd_type)
464                         return -ENODEV;
465
466
467                 err= copy_from_user(&foo, (int *)arg, sizeof(foo));
468                 if (err)
469                         return err;
470
471                 if ( !obddev->obd_type ||
472                      !obddev->obd_type->typ_ops->o_setattr)
473                         return -EINVAL;
474                 
475                 inode_setattr(&holder, &foo.iattr);
476                 return obddev->obd_type->typ_ops->o_setattr(foo.conn_id, foo.ino, &holder);
477         }
478
479         case OBD_IOC_GETATTR:
480         {
481                 int err;
482                 struct tmp {
483                         unsigned int conn_id;
484                         unsigned long ino;
485                 } foo;
486                 struct iattr iattr;
487                 struct inode holder;
488                 copy_from_user(&foo, (int *)arg, sizeof(struct tmp));
489
490                 if ( !obddev->obd_type ||
491                      !obddev->obd_type->typ_ops->o_getattr)
492                         return -EINVAL;
493
494                 if (obddev->obd_type->typ_ops->o_getattr(foo.conn_id, 
495                                                          foo.ino, &holder))
496                         return -EINVAL;
497
498                 inode_to_iattr(&holder, &iattr);
499                 err = copy_to_user((int *)arg, &iattr, sizeof(iattr));
500                 return err;
501         }
502
503         case OBD_IOC_READ2:
504         {
505                 int err;
506
507                 /* has this minor been registered? */
508                 if (!obddev->obd_type)
509                         return -ENODEV;
510
511                 err = copy_from_user(&rw_s, (int *)arg, sizeof(struct oic_rw_s));
512                 if ( err ) 
513                         return err;
514
515                 if ( !obddev->obd_type->typ_ops || 
516                      !obddev->obd_type->typ_ops->o_read ) 
517                         return -EINVAL;
518
519                 rw_s.count = obddev->obd_type->typ_ops->o_read2(rw_s.conn_id, 
520                                        rw_s.inode, 
521                                        rw_s.buf,
522                                        rw_s.count, 
523                                        rw_s.offset, 
524                                        &err);
525                 if ( err ) 
526                         return err;
527
528                 err = copy_to_user((int*)arg, &rw_s.count, 
529                                    sizeof(unsigned long));
530                 return err;
531         }
532
533
534         case OBD_IOC_READ:
535         {
536                 int err;
537                 /* has this minor been registered? */
538                 if (!obddev->obd_type)
539                         return -ENODEV;
540
541
542                 err = copy_from_user(&rw_s, (int *)arg, sizeof(struct oic_rw_s));
543                 if ( err ) 
544                         return err;
545
546                 if ( !obddev->obd_type->typ_ops || 
547                      !obddev->obd_type->typ_ops->o_read ) 
548                         return -EINVAL;
549
550                 rw_s.count = obddev->obd_type->typ_ops->o_read(rw_s.conn_id, 
551                                                                rw_s.inode, 
552                                                                rw_s.buf,
553                                                                rw_s.count, 
554                                                                rw_s.offset, 
555                                                                &err);
556                 if ( err ) 
557                         return err;
558
559                 err = copy_to_user((int*)arg, &rw_s.count, 
560                                    sizeof(unsigned long));
561                 return err;
562         }
563
564         case OBD_IOC_WRITE:
565         {
566                 int err;
567                 /* has this minor been registered? */
568                 if (!obddev->obd_type)
569                         return -ENODEV;
570
571
572                 copy_from_user(&rw_s, (int *)arg, sizeof(struct oic_rw_s));
573                 CDEBUG(D_IOCTL, "\n");
574                 if ( !obddev->obd_type->typ_ops->o_write ) 
575                         return -EINVAL;
576                 rw_s.count = 
577                         obddev->obd_type->typ_ops->o_write(rw_s.conn_id,
578                                                            rw_s.inode, 
579                                                            rw_s.buf,
580                                                            rw_s.count, 
581                                                            rw_s.offset, 
582                                                            &err);
583
584                 printk("Result rw_s.count %ld\n", rw_s.count);
585                 return (int)rw_s.count;
586                 copy_to_user((int *)arg, &rw_s.count, 
587                              sizeof(unsigned long));
588                 return err;
589         }
590         case OBD_IOC_PREALLOCATE:
591                 /* has this minor been registered? */
592                 if (!obddev->obd_type)
593                         return -ENODEV;
594
595
596                 copy_from_user(&prealloc, (int *)arg,
597                                sizeof(struct oic_prealloc_s));
598
599                 if (!obddev->u.sim.sim_sb || !obddev->u.sim.sim_sb->s_dev) {
600                         CDEBUG(D_IOCTL, "fatal: device not initialized.\n");
601                         return -EINVAL;
602                 }
603
604                 if (!obddev->obd_type || 
605                     !obddev->obd_type->typ_ops->o_preallocate)
606                         return -EINVAL;
607
608                 prealloc.alloc =
609                         obddev->obd_type->typ_ops->o_preallocate(prealloc.cli_id, prealloc.alloc,
610                                                prealloc.inodes, &err);
611                 if ( err ) 
612                         return err;
613                 return copy_to_user((int *)arg, &prealloc,
614                                     sizeof(struct oic_prealloc_s));
615         case OBD_IOC_STATFS:
616         {
617                 struct statfs *tmp;
618                 unsigned int conn_id;
619                 struct statfs buf;
620                 int rc;
621
622                 /* has this minor been registered? */
623                 if (!obddev->obd_type)
624                         return -ENODEV;
625
626                 tmp = (void *)arg + sizeof(unsigned int);
627                 get_user(conn_id, (int *) arg);
628                 if ( !obddev->obd_type ||
629                      !obddev->obd_type->typ_ops->o_statfs)
630                         return -EINVAL;
631
632                 rc = obddev->obd_type->typ_ops->o_statfs(conn_id, &buf);
633                 if ( rc ) 
634                         return rc;
635                 rc = copy_to_user(tmp, &buf, sizeof(buf));
636                 return rc;
637                 
638         }
639         default:
640                 printk("invalid ioctl: cmd = %x, arg = %lx\n", cmd, arg);
641                 return -ENOTTY;
642         }
643 }
644
645 /* Driver interface done, utility functions follow */
646
647 int obd_register_type(struct obd_ops *ops, char *nm)
648 {
649         struct obd_type *type;
650
651         if  ( obd_nm_to_type(nm) ) {
652                 CDEBUG(D_IOCTL, "Type %s already registered\n", nm);
653                 return -1;
654         }
655
656         OBD_ALLOC(type, struct obd_type * , sizeof(*type));
657         if ( !type ) 
658                 return -ENOMEM;
659         memset(type, 0, sizeof(*type));
660         INIT_LIST_HEAD(&type->typ_chain);
661
662         list_add(&type->typ_chain, obd_types.next);
663         type->typ_ops = ops;
664         type->typ_name = nm;
665         return 0;
666 }
667         
668 int obd_unregister_type(char *nm)
669 {
670         struct obd_type *type = obd_nm_to_type(nm);
671
672         if ( !type ) 
673                 return -1;
674
675         if ( type->typ_refcnt ) 
676                 return -1;
677
678         list_del(&type->typ_chain);
679         OBD_FREE(type, sizeof(*type));
680         return 0;
681 }
682
683 /* declare character device */
684 static struct file_operations obd_psdev_fops = {
685         NULL,                  /* llseek */
686         NULL,                  /* read */
687         NULL,                  /* write */
688         NULL,                  /* presto_psdev_readdir */
689         NULL,                  /* poll */
690         obd_class_ioctl,       /* ioctl */
691         NULL,                  /* presto_psdev_mmap */
692         obd_class_open,        /* open */
693         NULL,
694         obd_class_release,     /* release */
695         NULL,                  /* fsync */
696         NULL,                  /* fasync */
697         NULL,                  /* check_media_change */
698         NULL,                  /* revalidate */
699         NULL                   /* lock */
700 };
701
702
703 /* modules setup */
704
705 int init_obd(void)
706 {
707         int i;
708
709         printk(KERN_INFO "OBD class driver  v0.002, braam@stelias.com\n");
710
711         INIT_LIST_HEAD(&obd_types);
712
713         if (register_chrdev(OBD_PSDEV_MAJOR,"obd_psdev", 
714                             &obd_psdev_fops)) {
715                 printk(KERN_ERR "obd_psdev: unable to get major %d\n", 
716                        OBD_PSDEV_MAJOR);
717                 return -EIO;
718         }
719
720         for (i = 0; i < MAX_OBD_DEVICES; i++) {
721                 memset(&(obd_dev[i]), 0, sizeof(obd_dev[i]));
722                 INIT_LIST_HEAD(&obd_dev[i].obd_gen_clients);
723         }
724
725         obd_sysctl_init();
726
727         return 0;
728 }
729
730 EXPORT_SYMBOL(obd_register_type);
731 EXPORT_SYMBOL(obd_unregister_type);
732
733 EXPORT_SYMBOL(obd_print_entry);
734 EXPORT_SYMBOL(obd_debug_level);
735 EXPORT_SYMBOL(obd_dev);
736
737 EXPORT_SYMBOL(gen_connect);
738 EXPORT_SYMBOL(gen_client);
739 EXPORT_SYMBOL(gen_cleanup);
740 EXPORT_SYMBOL(gen_disconnect);
741
742 EXPORT_SYMBOL(gen_multi_attach);
743 EXPORT_SYMBOL(gen_multi_setup);
744 EXPORT_SYMBOL(gen_multi_cleanup);
745
746
747 #ifdef MODULE
748 int init_module(void)
749 {
750         return init_obd();
751 }
752
753 void cleanup_module(void)
754 {
755         int i;
756         ENTRY;
757
758         unregister_chrdev(OBD_PSDEV_MAJOR, "obd_psdev");
759         for (i = 0; i < MAX_OBD_DEVICES; i++) {
760                 struct obd_device *obddev = &obd_dev[i];
761                 if ( obddev->obd_type && 
762                      obddev->obd_type->typ_ops->o_cleanup_device )
763                         OBP(obddev, cleanup_device)(obddev);
764         }
765
766         obd_sysctl_clean();
767 }
768 #endif