Whamcloud - gitweb
Fixes to get things running on 2.4.3.
[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  *              Copyright (C) 2001 Cluster File Systems, Inc.
27  *
28  * 
29  */
30
31 #define EXPORT_SYMTAB
32
33 #include <linux/config.h> /* for CONFIG_PROC_FS */
34 #include <linux/module.h>
35 #include <linux/errno.h>
36 #include <linux/kernel.h>
37 #include <linux/major.h>
38 #include <linux/kmod.h>   /* for request_module() */
39 #include <linux/sched.h>
40 #include <linux/lp.h>
41 #include <linux/slab.h>
42 #include <linux/ioport.h>
43 #include <linux/fcntl.h>
44 #include <linux/delay.h>
45 #include <linux/skbuff.h>
46 #include <linux/proc_fs.h>
47 #include <linux/vmalloc.h>
48 #include <linux/fs.h>
49 #include <linux/poll.h>
50 #include <linux/init.h>
51 #include <linux/list.h>
52 #include <asm/io.h>
53 #include <asm/segment.h>
54 #include <asm/system.h>
55 #include <asm/poll.h>
56 #include <asm/uaccess.h>
57
58 #include <linux/obd_support.h>
59 #include <linux/obd_class.h>
60
61 static int obd_init_magic;
62 int obd_print_entry = 1;
63 int obd_debug_level = ~0;
64 long obd_memory = 0;
65 struct obd_device obd_dev[MAX_OBD_DEVICES];
66 struct list_head obd_types;
67
68 /* called when opening /dev/obdNNN */
69 static int obd_class_open(struct inode * inode, struct file * file)
70 {
71         int dev;
72         ENTRY;
73
74         if (!inode)
75                 return -EINVAL;
76         dev = MINOR(inode->i_rdev);
77         if (dev >= MAX_OBD_DEVICES)
78                 return -ENODEV;
79         obd_dev[dev].obd_refcnt++;
80         CDEBUG(D_PSDEV, "Dev %d refcount now %d\n", dev,
81                obd_dev[dev].obd_refcnt);
82
83         obd_dev[dev].obd_proc_entry = 
84                 proc_lustre_register_obd_device(&obd_dev[dev]);
85
86         MOD_INC_USE_COUNT;
87         EXIT;
88         return 0;
89 }
90
91 /* called when closing /dev/obdNNN */
92 static int obd_class_release(struct inode * inode, struct file * file)
93 {
94         int dev;
95         ENTRY;
96
97         if (!inode)
98                 return -EINVAL;
99         dev = MINOR(inode->i_rdev);
100         if (dev >= MAX_OBD_DEVICES)
101                 return -ENODEV;
102         fsync_dev(inode->i_rdev);
103         if (obd_dev[dev].obd_refcnt <= 0)
104                 printk(KERN_ALERT __FUNCTION__ ": refcount(%d) <= 0\n",
105                        obd_dev[dev].obd_refcnt);
106         obd_dev[dev].obd_refcnt--;
107
108         if (obd_dev[dev].obd_proc_entry && (obd_dev[dev].obd_refcnt==0))
109                 proc_lustre_release_obd_device(&obd_dev[dev]);
110
111         CDEBUG(D_PSDEV, "Dev %d refcount now %d\n", dev,
112                obd_dev[dev].obd_refcnt);
113         MOD_DEC_USE_COUNT;
114
115         EXIT;
116         return 0;
117 }
118
119 /* 
120  * support functions: we could use inter-module communication, but this 
121  * is more portable to other OS's
122  */
123 static struct obd_type *obd_search_type(char *nm)
124 {
125         struct list_head *tmp;
126         struct obd_type *type;
127         CDEBUG(D_INFO, "SEARCH %s\n", nm);
128         
129         tmp = &obd_types;
130         while ( (tmp = tmp->next) != &obd_types ) {
131                 type = list_entry(tmp, struct obd_type, typ_chain);
132                 CDEBUG(D_INFO, "TYP %s\n", type->typ_name);
133                 if (strlen(type->typ_name) == strlen(nm) &&
134                     strcmp(type->typ_name, nm) == 0 ) {
135                         return type;
136                 }
137         }
138         return NULL;
139 }
140
141 static struct obd_type *obd_nm_to_type(char *nm) 
142 {
143         struct obd_type *type = obd_search_type(nm);
144
145 #ifdef CONFIG_KMOD
146         if ( !type ) {
147                 if ( !request_module(nm) ) {
148                         CDEBUG(D_PSDEV, "Loaded module '%s'\n", nm);
149                         type = obd_search_type(nm);
150                 } else {
151                         CDEBUG(D_PSDEV, "Can't load module '%s'\n", nm);
152                 }
153         }
154 #endif
155         return type;
156 }
157
158
159 static int getdata(int len, void **data)
160 {
161         void *tmp = NULL;
162
163         if (!len) {
164                 *data = NULL;
165                 return 0;
166         }
167
168         CDEBUG(D_MALLOC, "len %d, add %p\n", len, *data);
169
170         OBD_ALLOC(tmp, void *, len);
171         if ( !tmp )
172                 return -ENOMEM;
173         
174         memset(tmp, 0, len);
175         if ( copy_from_user(tmp, *data, len)) {
176                 OBD_FREE(tmp, len);
177                 return -EFAULT;
178         }
179         *data = tmp;
180
181         return 0;
182 }
183
184
185 static int obd_devicename_from_path(obd_devicename* whoami, 
186                                     uint32_t klen,
187                                     char* kname, char *user_path)
188 {
189         int err;
190         struct nameidata nd;
191         whoami->len = klen;
192         whoami->name = kname;
193
194 #if (LINUX_VERSION_CODE <=  0x20403)
195
196         err = user_path_walk(user_path, &nd);
197         if (!err) {
198                 CDEBUG(D_INFO, "found dentry for %s\n", kname);
199                 whoami->dentry = nd.dentry;
200                 path_release(&nd);
201         }
202         return err;
203 #endif 
204         return 0;
205 }
206
207
208
209 /* to control /dev/obdNNN */
210 static int obd_class_ioctl (struct inode * inode, struct file * filp, 
211                             unsigned int cmd, unsigned long arg)
212 {
213         struct obd_device *obddev;
214         /* NOTE this must be larger than any of the ioctl data structs */
215         char buf[1024];
216         void *tmp_buf = buf;
217         struct obd_conn conn;
218         int err, dev;
219         long int cli_id; /* connect, disconnect */
220
221         if (!inode) {
222                 CDEBUG(D_IOCTL, "invalid inode\n");
223                 return -EINVAL;
224         }
225
226         dev = MINOR(inode->i_rdev);
227         if (dev > MAX_OBD_DEVICES)
228                 return -ENODEV;
229         obddev = &obd_dev[dev];
230         conn.oc_dev = obddev;
231
232         switch (cmd) {
233         case TCGETS:
234                 return -EINVAL;
235         case OBD_IOC_ATTACH: {
236                 struct obd_type *type;
237                 struct oic_generic *input = tmp_buf;
238                 char *nm;
239
240                 ENTRY;
241                 /* have we attached a type to this device */
242                 if ( obddev->obd_type || 
243                      (obddev->obd_flags & OBD_ATTACHED) ){
244                         CDEBUG(D_IOCTL,
245                                "OBD Device %d already attached to type %s.\n",
246                                dev, obddev->obd_type->typ_name);
247                         EXIT;
248                         return -EBUSY;
249                 }
250
251                 /* get data structures */
252                 err = copy_from_user(input, (void *)arg, sizeof(*input));
253                 if ( err ) {
254                         EXIT;
255                         return err;
256                 }
257
258                 err = getdata(input->att_typelen + 1, &input->att_type);
259                 if ( err ) {
260                         EXIT;
261                         return err;
262                 }
263
264                 /* find the type */
265                 nm = input->att_type;
266                 type = obd_nm_to_type(nm);
267
268                 OBD_FREE(input->att_type, input->att_typelen + 1);
269                 if ( !type ) {
270                         printk(__FUNCTION__ ": unknown obd type dev %d\n",
271                                dev);
272                         EXIT;
273                         return -EINVAL;
274                 }
275                 obddev->obd_type = type;
276                 
277                 /* get the attach data */
278                 err = getdata(input->att_datalen, &input->att_data);
279                 if ( err ) {
280                         EXIT;
281                         return err;
282                 }
283
284                 INIT_LIST_HEAD(&obddev->obd_gen_clients);
285                 obddev->obd_multi_count = 0;
286
287                 CDEBUG(D_IOCTL, "Attach %d, datalen %d, type %s\n", 
288                        dev, input->att_datalen, obddev->obd_type->typ_name);
289                 /* maybe we are done */
290                 if ( !OBT(obddev) || !OBP(obddev, attach) ) {
291                         obddev->obd_flags |= OBD_ATTACHED;
292                         type->typ_refcnt++;
293                         CDEBUG(D_PSDEV, "Dev %d refcount now %d\n", dev,
294                                type->typ_refcnt);
295                         if (input->att_data)
296                                 OBD_FREE(input->att_data, input->att_datalen);
297                         MOD_INC_USE_COUNT;
298                         EXIT;
299                         return 0;
300                 }
301
302                 /* do the attach */
303                 err = OBP(obddev, attach)(obddev, input->att_datalen,
304                                           input->att_data);
305                 if (input->att_data)
306                         OBD_FREE(input->att_data, input->att_datalen);
307
308                 if ( err ) {
309                         obddev->obd_flags &= ~OBD_ATTACHED;
310                         obddev->obd_type = NULL;
311                         EXIT;
312                 } else {
313                         obddev->obd_flags |=  OBD_ATTACHED;
314                         type->typ_refcnt++;
315                         CDEBUG(D_PSDEV, "Dev %d refcount now %d\n", dev,
316                                type->typ_refcnt);
317                         MOD_INC_USE_COUNT;
318                         EXIT;
319                 }
320                 return err;
321         }
322
323         case OBD_IOC_DETACH: {
324
325                 ENTRY;
326                 if (obddev->obd_flags & OBD_SET_UP) {
327                         EXIT;
328                         return -EBUSY;
329                 }
330                 if (! (obddev->obd_flags & OBD_ATTACHED) ) {
331                         CDEBUG(D_IOCTL, "Device not attached\n");
332                         EXIT;
333                         return -ENODEV;
334                 }
335                 if ( !list_empty(&obddev->obd_gen_clients) ) {
336                         CDEBUG(D_IOCTL, "Device has connected clients\n");
337                         EXIT;
338                         return -EBUSY;
339                 }
340
341                 CDEBUG(D_PSDEV, "Detach %d, type %s\n", dev,
342                        obddev->obd_type->typ_name);
343                 obddev->obd_flags &= ~OBD_ATTACHED;
344                 obddev->obd_type->typ_refcnt--;
345                 CDEBUG(D_PSDEV, "Dev %d refcount now %d\n", dev,
346                        obddev->obd_type->typ_refcnt);
347                 obddev->obd_type = NULL;
348                 MOD_DEC_USE_COUNT;
349                 EXIT;
350                 return 0;
351         }
352
353         case OBD_IOC_SETUP: {
354                 struct ioc_setup {
355                         int setup_datalen;
356                         void *setup_data;
357                 } *setup;
358                 char *user_path;
359
360                 setup = tmp_buf;
361
362
363                 ENTRY;
364                 /* have we attached a type to this device */
365                 if (!(obddev->obd_flags & OBD_ATTACHED)) {
366                         CDEBUG(D_IOCTL, "Device not attached\n");
367                         EXIT;
368                         return -ENODEV;
369                 }
370
371                 /* has this been done already? */
372                 if ( obddev->obd_flags & OBD_SET_UP ) {
373                         CDEBUG(D_IOCTL, "Device %d already setup (type %s)\n",
374                                dev, obddev->obd_type->typ_name);
375                         EXIT;
376                         return -EBUSY;
377                 }
378
379
380
381                 /* get main structure */
382                 err = copy_from_user(setup, (void *) arg, sizeof(*setup));
383                 if (err) {
384                   EXIT;
385                   return err;
386                 }
387                 user_path = setup->setup_data;
388
389                 /* get the attach data */
390                 err = getdata(setup->setup_datalen, &setup->setup_data);
391                 if ( err ) {
392                         EXIT;
393                         return err;
394                 }
395
396                 err = obd_devicename_from_path(&(obddev->obd_fsname),
397                                                setup->setup_datalen,
398                                                (char*) setup->setup_data, 
399                                                user_path);
400                 if (err) {
401                   memset(&(obddev->obd_fsname), 0, sizeof(obd_devicename));
402                   EXIT;
403                   return err;
404                 }
405                 
406                 /* do the setup */
407                 CDEBUG(D_PSDEV, "Setup %d, type %s\n", dev, 
408                        obddev->obd_type->typ_name);
409                 if ( !OBT(obddev) || !OBP(obddev, setup) ) {
410                         obddev->obd_type->typ_refcnt++;
411                         CDEBUG(D_PSDEV, "Dev %d refcount now %d\n",
412                                dev, obddev->obd_type->typ_refcnt);
413                         if (setup->setup_data)
414                                 OBD_FREE(setup->setup_data,
415                                          setup->setup_datalen);
416                         obddev->obd_flags |= OBD_SET_UP;
417                         EXIT;
418                         return 0;
419                 }
420
421                 err = OBP(obddev, setup)(obddev, 0, NULL);
422                           
423                 if ( err )  {
424                         obddev->obd_flags &= ~OBD_SET_UP;
425                         EXIT;
426                 } else {
427                         obddev->obd_type->typ_refcnt++;
428                         CDEBUG(D_PSDEV, "Dev %d refcount now %d\n",
429                                dev, obddev->obd_type->typ_refcnt);
430                         obddev->obd_flags |= OBD_SET_UP;
431                         EXIT;
432                 }
433
434                 return err;
435         }
436         case OBD_IOC_CLEANUP: {
437                 ENTRY;
438                 /* has this minor been registered? */
439                 if (!obddev->obd_type) {
440                         CDEBUG(D_IOCTL, "OBD Device %d has no type.\n", dev);
441                         EXIT;
442                         return -ENODEV;
443                 }
444
445                 if ( !obddev->obd_type->typ_refcnt ) {
446                         CDEBUG(D_IOCTL, "dev %d has refcount (%d)!\n",
447                                dev, obddev->obd_type->typ_refcnt);
448                         EXIT;
449                         return -EBUSY;
450                 }
451
452                 if ( (!(obddev->obd_flags & OBD_SET_UP)) ||
453                      (!(obddev->obd_flags & OBD_ATTACHED))) {
454                         CDEBUG(D_IOCTL, "device not attached or set up\n");
455                         EXIT;
456                         return -ENODEV;
457                 }
458
459                 if ( !OBT(obddev) || !OBP(obddev, cleanup) )
460                         goto cleanup_out;
461
462                 /* cleanup has no argument */
463                 err = OBP(obddev, cleanup)(obddev);
464                 if ( err ) {
465                         EXIT;
466                         return err;
467                 }
468
469         cleanup_out: 
470                 obddev->obd_flags &= ~OBD_SET_UP;
471                 obddev->obd_type->typ_refcnt--;
472                 CDEBUG(D_PSDEV, "Dev %d refcount now %d\n", dev,
473                        obddev->obd_type->typ_refcnt);
474                 EXIT;
475                 return 0;
476         }
477         case OBD_IOC_CONNECT:
478         {
479                 if ( (!(obddev->obd_flags & OBD_SET_UP)) ||
480                      (!(obddev->obd_flags & OBD_ATTACHED))) {
481                         CDEBUG(D_IOCTL, "Device not attached or set up\n");
482                         return -ENODEV;
483                 }
484
485                 if ( !OBT(obddev) || !OBP(obddev, connect) )
486                         return -EOPNOTSUPP;
487                 
488                 err = OBP(obddev, connect)(&conn);
489                 if ( err )
490                         return err;
491
492                 return copy_to_user((int *)arg, &conn.oc_id,
493                                     sizeof(uint32_t));
494         }
495         case OBD_IOC_DISCONNECT:
496                 /* frees data structures */
497                 /* has this minor been registered? */
498                 if (!obddev->obd_type)
499                         return -ENODEV;
500
501                 get_user(cli_id, (int *) arg);
502                 conn.oc_id = cli_id;
503
504                 if ( !OBT(obddev) || !OBP(obddev, disconnect))
505                         return -EOPNOTSUPP;
506                 
507                 OBP(obddev, disconnect)(&conn);
508                 return 0;
509
510         case OBD_IOC_SYNC: {
511                 struct oic_range_s *range = tmp_buf;
512
513                 if (!obddev->obd_type)
514                         return -ENODEV;
515
516                 err = copy_from_user(range, (const void *)arg,  sizeof(*range));
517
518                 if ( err ) {
519                         EXIT;
520                         return err;
521                 }
522                         
523                 if ( !OBT(obddev) || !OBP(obddev, sync) ) {
524                         err = -EOPNOTSUPP;
525                         EXIT;
526                         return err;
527                 }
528
529                 /* XXX sync needs to be tested/verified */
530                 err = OBP(obddev, sync)(&conn, &range->obdo, range->count,
531                                         range->offset);
532
533                 if ( err ) {
534                         EXIT;
535                         return err;
536                 }
537                         
538                 return put_user(err, (int *) arg);
539         }
540         case OBD_IOC_CREATE: {
541                 struct oic_attr_s *attr = tmp_buf;
542
543                 err = copy_from_user(attr, (const void *)arg,  sizeof(*attr));
544                 if (err) {
545                         EXIT;
546                         return err;
547                 }
548
549                 /* has this minor been registered? */
550                 if ( !(obddev->obd_flags & OBD_ATTACHED) ||
551                      !(obddev->obd_flags & OBD_SET_UP)) {
552                         CDEBUG(D_IOCTL, "Device not attached or set up\n");
553                         return -ENODEV;
554                 }
555                 conn.oc_id = attr->conn_id;
556
557                 if ( !OBT(obddev) || !OBP(obddev, create) )
558                         return -EOPNOTSUPP;
559
560                 err = OBP(obddev, create)(&conn, &attr->obdo);
561                 if (err) {
562                         EXIT;
563                         return err;
564                 }
565
566                 err = copy_to_user((int *)arg, attr, sizeof(*attr));
567                 EXIT;
568                 return err;
569         }
570
571         case OBD_IOC_DESTROY: {
572                 struct oic_attr_s *attr = tmp_buf;
573                 
574                 /* has this minor been registered? */
575                 if (!obddev->obd_type)
576                         return -ENODEV;
577
578                 err = copy_from_user(attr, (int *)arg, sizeof(*attr));
579                 if ( err ) {
580                         EXIT;
581                         return err;
582                 }
583
584                 if ( !OBT(obddev) || !OBP(obddev, destroy) )
585                         return -EOPNOTSUPP;
586
587                 conn.oc_id = attr->conn_id;
588                 err = OBP(obddev, destroy)(&conn, &attr->obdo);
589                 EXIT;
590                 return err;
591         }
592
593         case OBD_IOC_SETATTR: {
594                 struct oic_attr_s *attr = tmp_buf;
595
596                 /* has this minor been registered? */
597                 if (!obddev->obd_type)
598                         return -ENODEV;
599
600                 err = copy_from_user(attr, (int *)arg, sizeof(*attr));
601                 if (err)
602                         return err;
603
604                 if ( !OBT(obddev) || !OBP(obddev, setattr) )
605                         return -EOPNOTSUPP;
606                 
607                 conn.oc_id = attr->conn_id;
608                 err = OBP(obddev, setattr)(&conn, &attr->obdo);
609                 EXIT;
610                 return err;
611         }
612
613         case OBD_IOC_GETATTR: {
614                 struct oic_attr_s *attr = tmp_buf;
615
616                 err = copy_from_user(attr, (int *)arg, sizeof(*attr));
617                 if (err)
618                         return err;
619
620                 conn.oc_id = attr->conn_id;
621                 ODEBUG(&attr->obdo);
622                 err = OBP(obddev, getattr)(&conn, &attr->obdo);
623                 if ( err ) {
624                         EXIT;
625                         return err;
626                 }
627
628                 err = copy_to_user((int *)arg, attr, sizeof(*attr));
629                 EXIT;
630                 return err;
631         }
632
633         case OBD_IOC_READ: {
634                 int err;
635                 struct oic_rw_s *rw_s = tmp_buf;  /* read, write ioctl str */
636
637                 err = copy_from_user(rw_s, (int *)arg, sizeof(*rw_s));
638                 if ( err ) {
639                         EXIT;
640                         return err;
641                 }
642
643                 conn.oc_id = rw_s->conn_id;
644
645                 if ( !OBT(obddev) || !OBP(obddev, read) ) {
646                         err = -EOPNOTSUPP;
647                         EXIT;
648                         return err;
649                 }
650
651
652                 err = OBP(obddev, read)(&conn, &rw_s->obdo, rw_s->buf, 
653                                         &rw_s->count, rw_s->offset);
654                 
655                 ODEBUG(&rw_s->obdo);
656                 CDEBUG(D_INFO, "READ: conn %d, count %Ld, offset %Ld, '%s'\n",
657                        rw_s->conn_id, rw_s->count, rw_s->offset, rw_s->buf);
658                 if ( err ) {
659                         EXIT;
660                         return err;
661                 }
662                         
663                 err = copy_to_user((int*)arg, &rw_s->count, sizeof(rw_s->count));
664                 EXIT;
665                 return err;
666         }
667
668         case OBD_IOC_WRITE: {
669                 struct oic_rw_s *rw_s = tmp_buf;  /* read, write ioctl str */
670
671                 err = copy_from_user(rw_s, (int *)arg, sizeof(*rw_s));
672                 if ( err ) {
673                         EXIT;
674                         return err;
675                 }
676
677                 conn.oc_id = rw_s->conn_id;
678
679                 if ( !OBT(obddev) || !OBP(obddev, write) ) {
680                         err = -EOPNOTSUPP;
681                         return err;
682                 }
683
684                 CDEBUG(D_INFO, "WRITE: conn %d, count %Ld, offset %Ld, '%s'\n",
685                        rw_s->conn_id, rw_s->count, rw_s->offset, rw_s->buf);
686
687                 err = OBP(obddev, write)(&conn, &rw_s->obdo, rw_s->buf, 
688                                          &rw_s->count, rw_s->offset);
689                 ODEBUG(&rw_s->obdo);
690                 if ( err ) {
691                         EXIT;
692                         return err;
693                 }
694
695                 err = copy_to_user((int *)arg, &rw_s->count,
696                                    sizeof(rw_s->count));
697                 EXIT;
698                 return err;
699         }
700         case OBD_IOC_PREALLOCATE: {
701                 struct oic_prealloc_s *prealloc = tmp_buf;
702
703                 /* has this minor been registered? */
704                 if (!obddev->obd_type)
705                         return -ENODEV;
706
707                 err = copy_from_user(prealloc, (int *)arg, sizeof(*prealloc));
708                 if (err) 
709                         return -EFAULT;
710
711                 if ( !(obddev->obd_flags & OBD_ATTACHED) ||
712                      !(obddev->obd_flags & OBD_SET_UP)) {
713                         CDEBUG(D_IOCTL, "Device not attached or set up\n");
714                         return -ENODEV;
715                 }
716
717                 if ( !OBT(obddev) || !OBP(obddev, preallocate) )
718                         return -EOPNOTSUPP;
719
720                 conn.oc_id = prealloc->conn_id;
721                 err = OBP(obddev, preallocate)(&conn, &prealloc->alloc,
722                                                prealloc->ids);
723                 if ( err ) {
724                         EXIT;
725                         return err;
726                 }
727
728                 err =copy_to_user((int *)arg, prealloc, sizeof(*prealloc));
729                 EXIT;
730                 return err;
731         }
732         case OBD_IOC_STATFS: {
733                 struct statfs *tmp;
734                 unsigned int conn_id;
735                 struct statfs buf;
736
737                 /* has this minor been registered? */
738                 if (!obddev->obd_type)
739                         return -ENODEV;
740
741                 tmp = (void *)arg + sizeof(unsigned int);
742                 get_user(conn_id, (int *) arg);
743
744                 if ( !OBT(obddev) || !OBP(obddev, statfs) )
745                         return -EOPNOTSUPP;
746
747                 conn.oc_id = conn_id;
748                 err = OBP(obddev, statfs)(&conn, &buf);
749                 if ( err ) {
750                         EXIT;
751                         return err;
752                 }
753                 err = copy_to_user(tmp, &buf, sizeof(buf));
754                 EXIT;
755                 return err;
756                 
757         }
758         case OBD_IOC_COPY: {
759                 struct ioc_mv_s *mvdata = tmp_buf;
760
761                 if ( (!(obddev->obd_flags & OBD_SET_UP)) ||
762                      (!(obddev->obd_flags & OBD_ATTACHED))) {
763                         CDEBUG(D_IOCTL, "Device not attached or set up\n");
764                         return -ENODEV;
765                 }
766
767                 /* get main structure */
768                 err = copy_from_user(mvdata, (void *) arg, sizeof(*mvdata));
769                 if (err) {
770                         EXIT;
771                         return err;
772                 }
773
774                 if ( !OBT(obddev) || !OBP(obddev, copy) )
775                         return -EOPNOTSUPP;
776
777                 /* do the partition */
778                 CDEBUG(D_INFO, "Copy %d, type %s dst %Ld src %Ld\n", dev, 
779                        obddev->obd_type->typ_name, mvdata->dst.o_id, 
780                        mvdata->src.o_id);
781
782                 conn.oc_id = mvdata->src_conn_id;
783
784                 err = OBP(obddev, copy)(&conn, &mvdata->dst, 
785                                         &conn, &mvdata->src, 
786                                         mvdata->src.o_size, 0);
787                 return err;
788         }
789
790         case OBD_IOC_MIGR: {
791                 struct ioc_mv_s *mvdata = tmp_buf;
792
793                 if ( (!(obddev->obd_flags & OBD_SET_UP)) ||
794                      (!(obddev->obd_flags & OBD_ATTACHED))) {
795                         CDEBUG(D_IOCTL, "Device not attached or set up\n");
796                         return -ENODEV;
797                 }
798
799                 err = copy_from_user(mvdata, (void *) arg, sizeof(*mvdata));
800                 if (err) {
801                         EXIT;
802                         return err;
803                 }
804
805                 CDEBUG(D_INFO, "Migrate copying %d bytes\n", sizeof(*mvdata));
806
807                 if ( !OBT(obddev) || !OBP(obddev, migrate) )
808                         return -EOPNOTSUPP;
809
810                 /* do the partition */
811                 CDEBUG(D_INFO, "Migrate %d, type %s conn %d src %Ld dst %Ld\n",
812                        dev, obddev->obd_type->typ_name, mvdata->src_conn_id,
813                        mvdata->src.o_id, mvdata->dst.o_id);
814
815                 conn.oc_id = mvdata->src_conn_id;
816                 err = OBP(obddev, migrate)(&conn, &mvdata->dst, &mvdata->src, 
817                                            mvdata->src.o_size, 0);
818
819                 return err;
820         }
821         case OBD_IOC_PUNCH: {
822                 struct oic_rw_s *rw_s = tmp_buf;  /* read, write ioctl str */
823
824                 err = copy_from_user(rw_s, (int *)arg, sizeof(*rw_s));
825                 if ( err ) {
826                         EXIT;
827                         return err;
828                 }
829
830                 conn.oc_id = rw_s->conn_id;
831
832                 if ( !OBT(obddev) || !OBP(obddev, punch) ) {
833                         err = -EOPNOTSUPP;
834                         return err;
835                 }
836
837                 CDEBUG(D_INFO, "PUNCH: conn %d, count %Ld, offset %Ld\n",
838                        rw_s->conn_id, rw_s->count, rw_s->offset);
839                 err = OBP(obddev, punch)(&conn, &rw_s->obdo, rw_s->count,
840                                          rw_s->offset);
841                 ODEBUG(&rw_s->obdo);
842                 if ( err ) {
843                         EXIT;
844                         return err;
845                 }
846                 EXIT;
847                 return err;
848         }
849
850         default: {
851                 struct obd_type *type;
852                 struct oic_generic input;
853                 char *nm;
854                 void *karg;
855
856                 /* get data structures */
857                 err = copy_from_user(&input, (void *)arg, sizeof(input));
858                 if ( err ) {
859                         EXIT;
860                         return err;
861                 }
862
863                 err = getdata(input.att_typelen + 1, &input.att_type);
864                 if ( err ) {
865                         EXIT;
866                         return err;
867                 }
868
869                 /* find the type */
870                 nm = input.att_type;
871                 type = obd_nm_to_type(nm);
872 #ifdef CONFIG_KMOD
873                 if ( !type ) {
874                         if ( !request_module(nm) ) {
875                                 CDEBUG(D_PSDEV, "Loaded module '%s'\n", nm);
876                                 type = obd_nm_to_type(nm);
877                         } else {
878                                 CDEBUG(D_PSDEV, "Can't load module '%s'\n", nm);
879                         }
880                 }
881 #endif
882                 OBD_FREE(input.att_type, input.att_typelen + 1);
883                 if ( !type ) {
884                         printk(__FUNCTION__ ": unknown obd type dev %d\n", dev);
885                         EXIT;
886                         return -EINVAL;
887                 }
888                 
889                 if ( !type->typ_ops || !type->typ_ops->o_iocontrol ) {
890                         EXIT;
891                         return -EOPNOTSUPP;
892                 }
893                 conn.oc_id = input.att_connid;
894                 
895                 CDEBUG(D_INFO, "Calling ioctl %x for type %s, len %d\n",
896                        cmd, type->typ_name, input.att_datalen);
897
898                 /* get the generic data */
899                 karg = input.att_data;
900                 err = getdata(input.att_datalen, &karg);
901                 if ( err ) {
902                         EXIT;
903                         return err;
904                 }
905
906                 err = type->typ_ops->o_iocontrol(cmd, &conn, input.att_datalen, 
907                                                  karg, input.att_data);
908                 OBD_FREE(karg, input.att_datalen);
909
910                 EXIT;
911                 return err;
912         }
913         }
914 } /* obd_class_ioctl */
915
916 /* Driver interface done, utility functions follow */
917
918 int obd_register_type(struct obd_ops *ops, char *nm)
919 {
920         struct obd_type *type;
921
922
923         if (obd_init_magic != 0x11223344) {
924                 printk(__FUNCTION__ ": bad magic for type\n");
925                 EXIT;
926                 return -EINVAL;
927         }
928
929         if  ( obd_nm_to_type(nm) ) {
930                 CDEBUG(D_IOCTL, "Type %s already registered\n", nm);
931                 EXIT;
932                 return -EEXIST;
933         }
934         
935         OBD_ALLOC(type, struct obd_type * , sizeof(*type));
936         if ( !type ) {
937                 EXIT;
938                 return -ENOMEM;
939         }
940         memset(type, 0, sizeof(*type));
941         INIT_LIST_HEAD(&type->typ_chain);
942         MOD_INC_USE_COUNT;
943         list_add(&type->typ_chain, obd_types.next);
944         type->typ_ops = ops;
945         type->typ_name = nm;
946         EXIT;
947         return 0;
948 }
949         
950 int obd_unregister_type(char *nm)
951 {
952         struct obd_type *type = obd_nm_to_type(nm);
953
954         if ( !type ) {
955                 MOD_DEC_USE_COUNT;
956                 printk(KERN_INFO __FUNCTION__ ": unknown obd type\n");
957                 EXIT;
958                 return -EINVAL;
959         }
960
961         if ( type->typ_refcnt ) {
962                 MOD_DEC_USE_COUNT;
963                 printk(KERN_ALERT __FUNCTION__ ":type %s has refcount "
964                        "(%d)\n", nm, type->typ_refcnt);
965                 EXIT;
966                 return -EBUSY;
967         }
968
969         list_del(&type->typ_chain);
970         OBD_FREE(type, sizeof(*type));
971         MOD_DEC_USE_COUNT;
972         return 0;
973 } /* obd_unregister_type */
974
975 /* declare character device */
976 static struct file_operations obd_psdev_fops = {
977         ioctl: obd_class_ioctl,       /* ioctl */
978         open: obd_class_open,        /* open */
979         release: obd_class_release,     /* release */
980 };
981
982
983 /* modules setup */
984
985 int init_obd(void)
986 {
987         int err;
988         int i;
989
990         printk(KERN_INFO "OBD class driver  v0.01, braam@stelias.com\n");
991         
992         INIT_LIST_HEAD(&obd_types);
993         
994         if (register_chrdev(OBD_PSDEV_MAJOR,"obd_psdev", 
995                             &obd_psdev_fops)) {
996                 printk(KERN_ERR __FUNCTION__ ": unable to get major %d\n", 
997                        OBD_PSDEV_MAJOR);
998                 return -EIO;
999         }
1000
1001         for (i = 0; i < MAX_OBD_DEVICES; i++) {
1002                 memset(&(obd_dev[i]), 0, sizeof(obd_dev[i]));
1003                 obd_dev[i].obd_minor = i;
1004                 INIT_LIST_HEAD(&obd_dev[i].obd_gen_clients);
1005         }
1006
1007         err = obd_init_obdo_cache();
1008         if (err)
1009                 return err;
1010         obd_sysctl_init();
1011         obd_init_magic = 0x11223344;
1012         return 0;
1013 }
1014
1015 EXPORT_SYMBOL(obd_register_type);
1016 EXPORT_SYMBOL(obd_unregister_type);
1017
1018 EXPORT_SYMBOL(obd_print_entry);
1019 EXPORT_SYMBOL(obd_debug_level);
1020 EXPORT_SYMBOL(obd_dev);
1021
1022 EXPORT_SYMBOL(gen_connect);
1023 EXPORT_SYMBOL(gen_client);
1024 EXPORT_SYMBOL(gen_cleanup);
1025 EXPORT_SYMBOL(gen_disconnect);
1026 EXPORT_SYMBOL(gen_copy_data); 
1027 EXPORT_SYMBOL(obdo_cachep);
1028
1029 /* EXPORT_SYMBOL(gen_multi_attach); */
1030 EXPORT_SYMBOL(gen_multi_setup);
1031 EXPORT_SYMBOL(gen_multi_cleanup);
1032
1033
1034 #ifdef MODULE
1035 int init_module(void)
1036 {
1037         return init_obd();
1038 }
1039
1040 void cleanup_module(void)
1041 {
1042         int i;
1043         ENTRY;
1044
1045         unregister_chrdev(OBD_PSDEV_MAJOR, "obd_psdev");
1046         for (i = 0; i < MAX_OBD_DEVICES; i++) {
1047                 struct obd_device *obddev = &obd_dev[i];
1048                 if ( obddev->obd_type && 
1049                      (obddev->obd_flags & OBD_SET_UP) &&
1050                      OBT(obddev) && OBP(obddev, detach) ) {
1051                         /* XXX should this call generic detach otherwise? */
1052                         OBP(obddev, detach)(obddev);
1053                 } 
1054         }
1055
1056         obd_cleanup_obdo_cache();
1057         obd_sysctl_clean();
1058         CDEBUG(D_MALLOC, "CLASS mem used %ld\n", obd_memory);
1059         obd_init_magic = 0;
1060         EXIT;
1061 }
1062 #endif