Whamcloud - gitweb
Much cleaner separation of the class and simulated obd code.
[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 static int obd_class_open(struct inode * inode, struct file * file)
65 {
66         int dev;
67         ENTRY;
68
69         if (!inode)
70                 return -EINVAL;
71         dev = MINOR(inode->i_rdev);
72         if (dev >= MAX_OBD_DEVICES)
73                 return -ENODEV;
74         obd_dev[dev].refcnt++;
75         CDEBUG(D_PSDEV, "Refcount now %d\n", obd_dev[dev].refcnt++);
76
77         MOD_INC_USE_COUNT;
78         EXIT;
79         return 0;
80 }
81
82 static int obd_class_release(struct inode * inode, struct file * file)
83 {
84         int dev;
85         ENTRY;
86
87         if (!inode)
88                 return -EINVAL;
89         dev = MINOR(inode->i_rdev);
90         if (dev >= MAX_OBD_DEVICES)
91                 return -ENODEV;
92         fsync_dev(inode->i_rdev);
93         if (obd_dev[dev].refcnt <= 0)
94                 printk(KERN_ALERT "presto_psdev_release: refcount(%d) <= 0\n",
95                        obd_dev[dev].refcnt);
96         obd_dev[dev].refcnt--;
97
98         CDEBUG(D_PSDEV, "Refcount now %d\n", obd_dev[dev].refcnt++);
99
100         MOD_DEC_USE_COUNT;
101
102         EXIT;
103         return 0;
104 }
105
106 static struct obd_type *obd_nm_to_type(char *nm) 
107 {
108         struct list_head *tmp;
109         struct obd_type *type;
110         
111         tmp = &obd_types;
112         while ( (tmp = tmp->next) != &obd_types ) {
113                 type = list_entry(tmp, struct obd_type, typ_chain);
114                 if (strlen(type->typ_name) == strlen(nm) &&
115                     strcmp(type->typ_name, nm) == 0 ) {
116                         return type;
117                 }
118         }
119         return NULL;
120 }
121
122 static int obd_class_ioctl (struct inode * inode, struct file * filp, 
123                      unsigned int cmd, unsigned long arg)
124 {
125         int err, i_ino, dev;
126         struct obd_device *obddev;
127         struct oic_rw_s rw_s; /* read, write */
128         long int cli_id; /* connect, disconnect */
129
130         struct oic_prealloc_s prealloc; /* preallocate */
131         if (!inode)
132                 return -EINVAL;
133         dev = MINOR(inode->i_rdev);
134         if (dev > MAX_OBD_DEVICES)
135                 return -ENODEV;
136
137         obddev = &obd_dev[dev];
138
139         /* has this minor been registered? */
140         if (cmd != OBD_IOC_SETUP_SUPER && !obd_dev[dev].obd_type)
141                 return -ENODEV;
142
143         switch (cmd) {
144         case OBD_IOC_SETUP_SUPER: {
145                 struct obd_type *type;
146
147                 struct setup {
148                         int  setup_data;
149                         char setup_type[24];
150                 } input;
151
152                 if ( obddev->obd_type ) {
153                         CDEBUG(D_IOCTL, "Device %d already setup (type %s)\n",
154                                dev, obddev->obd_type->typ_name);
155                         return -1;
156                 }
157
158                 /* get data structures */
159                 if ( (err= copy_from_user(&input, (void *) arg, sizeof(struct setup))) )
160                         return err;
161
162                 type = obd_nm_to_type(input.setup_type);
163                 if ( !type ) {
164                         CDEBUG(D_IOCTL, "Trying to register non existent type %s\n",
165                                input.setup_type);
166                         return -1;
167                 }
168                 obddev->obd_type = type;
169
170                 CDEBUG(D_IOCTL, "Registering %d, type %s\n",
171                        dev, input.setup_type);
172                 if ( obddev->obd_type->typ_ops->o_setup(obddev, 
173                                                         &input.setup_data)){
174                         obddev->obd_type = NULL;
175                         return -1;
176                 } else {
177                         type->typ_refcount++;
178                         return 0;
179                 }
180
181
182         }
183         case OBD_IOC_CLEANUP_SUPER:
184
185                 /* cleanup has no argument */
186                 if ( obddev->obd_type->typ_refcount ) 
187                         obddev->obd_type->typ_refcount--;
188                 else 
189                         printk("OBD_CLEANUP: refcount wrap!\n");
190
191                 if ( obddev->obd_type->typ_ops->o_cleanup ) 
192                         return obddev->obd_type->typ_ops->o_cleanup(obddev);
193                 else 
194                         return 0;
195
196         case OBD_IOC_CONNECT:
197         {
198                 struct obd_conn_info conninfo;
199
200                 if (obddev->obd_type->typ_ops->o_connect(dev, &conninfo))
201                         return -EINVAL;
202
203                 return copy_to_user((int *)arg, &conninfo,
204                                     sizeof(struct obd_conn_info));
205         }
206         case OBD_IOC_DISCONNECT:
207                 /* frees data structures */
208                 get_user(cli_id, (int *) arg);
209
210                 obddev->obd_type->typ_ops->o_disconnect(cli_id);
211                 return 0;
212
213         case OBD_IOC_SYNC:
214                 /* sync doesn't need a connection ID, because it knows
215                  * what device it was called on, and can thus get the
216                  * superblock that it needs. */
217                 if (!obddev->sb || !obddev->sb->s_dev) {
218                         CDEBUG(D_IOCTL, "fatal: device not initialized.\n");
219                         err = -EINVAL;
220                 } else {
221                         if ((err = fsync_dev(obddev->sb->s_dev)))
222                                 CDEBUG(D_IOCTL, "sync: fsync_dev failure\n");
223                         else
224                                 CDEBUG(D_IOCTL, "sync: success\n");
225                 }
226
227                 return put_user(err, (int *) arg);
228         case OBD_IOC_CREATE:
229                 /* similarly, create doesn't need a connection ID for
230                  * the same reasons. */
231                 if (!obddev->sb) {
232                         CDEBUG(D_IOCTL, "fatal: device not initialized.\n");
233                         return put_user(-EINVAL, (int *) arg);
234                 }
235
236                 i_ino = obddev->obd_type->typ_ops->o_create(obddev, 0, &err);
237                 if (err) {
238                         CDEBUG(D_IOCTL, "create: obd_inode_new failure\n");
239                         /* 0 is the only error value */
240                         return put_user(0, (int *) arg);
241                 }
242
243                 return put_user(i_ino, (int *) arg);
244         case OBD_IOC_DESTROY:
245         {
246                 struct destroy_s {
247                         unsigned int conn_id;
248                         unsigned int ino;
249                 } destroy;
250                 copy_from_user(&destroy, (int *)arg, sizeof(struct destroy_s));
251                 if ( !obddev->obd_type ||
252                      !obddev->obd_type->typ_ops->o_destroy)
253                         return -EINVAL;
254
255                 return obddev->obd_type->typ_ops->o_destroy(destroy.conn_id, destroy.ino);
256         }
257         case OBD_IOC_SETATTR:
258         {
259                 int err;
260                 struct tmp {
261                         unsigned int conn_id;
262                         unsigned long ino;
263                         struct iattr iattr;
264                 } foo;
265
266                 err= copy_from_user(&foo, (int *)arg, sizeof(struct tmp));
267                 if (err)
268                         return err;
269
270                 if ( !obddev->obd_type ||
271                      !obddev->obd_type->typ_ops->o_setattr)
272                         return -EINVAL;
273
274                 return obddev->obd_type->typ_ops->o_setattr(foo.conn_id, foo.ino, &foo.iattr);
275         }
276
277         case OBD_IOC_GETATTR:
278         {
279                 int err;
280                 struct tmp {
281                         unsigned int conn_id;
282                         unsigned long ino;
283                 } foo;
284                 struct iattr iattr;
285                 copy_from_user(&foo, (int *)arg, sizeof(struct tmp));
286
287                 if ( !obddev->obd_type ||
288                      !obddev->obd_type->typ_ops->o_getattr)
289                         return -EINVAL;
290
291                 if (obddev->obd_type->typ_ops->o_getattr(foo.conn_id, 
292                                                          foo.ino, &iattr))
293                         return -EINVAL;
294
295                 err = copy_to_user((int *)arg, &iattr, sizeof(iattr));
296                 return err;
297         }
298
299         case OBD_IOC_READ:
300         {
301                 int err;
302
303                 err = copy_from_user(&rw_s, (int *)arg, sizeof(struct oic_rw_s));
304                 if ( err ) 
305                         return err;
306
307                 if ( !obddev->obd_type->typ_ops || 
308                      !obddev->obd_type->typ_ops->o_read ) 
309                         return -EINVAL;
310
311                 rw_s.count = obddev->obd_type->typ_ops->o_read(rw_s.conn_id, 
312                                                                rw_s.inode, 
313                                                                rw_s.buf,
314                                                                rw_s.count, 
315                                                                rw_s.offset, 
316                                                                &err);
317                 if ( err ) 
318                         return err;
319
320                 err = copy_to_user((int*)arg, &rw_s.count, 
321                                    sizeof(unsigned long));
322                 return err;
323         }
324
325         case OBD_IOC_WRITE:
326         {
327                 int err;
328
329                 copy_from_user(&rw_s, (int *)arg, sizeof(struct oic_rw_s));
330                 CDEBUG(D_IOCTL, "\n");
331                 if ( !obddev->obd_type->typ_ops->o_write ) 
332                         return -EINVAL;
333                 rw_s.count = 
334                         obddev->obd_type->typ_ops->o_write(rw_s.conn_id,
335                                                            rw_s.inode, 
336                                                            rw_s.buf,
337                                                            rw_s.count, 
338                                                            rw_s.offset, 
339                                                            &err);
340
341                 printk("Result rw_s.count %ld\n", rw_s.count);
342                 return (int)rw_s.count;
343                 copy_to_user((int *)arg, &rw_s.count, 
344                              sizeof(unsigned long));
345                 return err;
346         }
347         case OBD_IOC_PREALLOCATE:
348                 copy_from_user(&prealloc, (int *)arg,
349                                sizeof(struct oic_prealloc_s));
350
351                 if (!obddev->sb || !obddev->sb->s_dev) {
352                         CDEBUG(D_IOCTL, "fatal: device not initialized.\n");
353                         return -EINVAL;
354                 }
355
356                 if (!obddev->obd_type || 
357                     !obddev->obd_type->typ_ops->o_preallocate)
358                         return -EINVAL;
359
360                 prealloc.alloc =
361                         obddev->obd_type->typ_ops->o_preallocate(prealloc.cli_id, prealloc.alloc,
362                                                prealloc.inodes, &err);
363                 if ( err ) 
364                         return err;
365                 return copy_to_user((int *)arg, &prealloc,
366                                     sizeof(struct oic_prealloc_s));
367         case OBD_IOC_STATFS:
368         {
369                 struct statfs *tmp;
370                 unsigned int conn_id;
371                 
372                 tmp = (void *)arg + sizeof(unsigned int);
373                 get_user(conn_id, (int *) arg);
374                 if ( !obddev->obd_type ||
375                      !obddev->obd_type->typ_ops->o_statfs)
376                         return -EINVAL;
377
378                 return obddev->obd_type->typ_ops->o_statfs(conn_id, tmp);
379         }
380         default:
381                 printk("invalid ioctl: cmd = %u, arg = %lu\n", cmd, arg);
382                 return -ENOTTY;
383         }
384 }
385
386 /* Driver interface done, utility functions follow */
387
388 int obd_register_type(struct obd_ops *ops, char *nm)
389 {
390         struct obd_type *type;
391
392         if  ( obd_nm_to_type(nm) ) {
393                 CDEBUG(D_IOCTL, "Type %s already registered\n", nm);
394                 return -1;
395         }
396
397         OBD_ALLOC(type, struct obd_type * , sizeof(*type));
398         if ( !type ) 
399                 return -ENOMEM;
400         memset(type, 0, sizeof(*type));
401         INIT_LIST_HEAD(&type->typ_chain);
402
403         list_add(&type->typ_chain, obd_types.next);
404         type->typ_ops = ops;
405         type->typ_name = nm;
406         return 0;
407 }
408         
409 int obd_unregister_type(char *nm)
410 {
411         struct obd_type *type = obd_nm_to_type(nm);
412
413         if ( !type ) 
414                 return -1;
415
416         if ( type->typ_refcount ) 
417                 return -1;
418
419         list_del(&type->typ_chain);
420         OBD_FREE(type, sizeof(*type));
421         return 0;
422 }
423
424 /* declare character device */
425 static struct file_operations obd_psdev_fops = {
426         NULL,                  /* llseek */
427         NULL,                  /* read */
428         NULL,                  /* write */
429         NULL,                  /* presto_psdev_readdir */
430         NULL,                  /* poll */
431         obd_class_ioctl,       /* ioctl */
432         NULL,                  /* presto_psdev_mmap */
433         obd_class_open,        /* open */
434         NULL,
435         obd_class_release,     /* release */
436         NULL,                  /* fsync */
437         NULL,                  /* fasync */
438         NULL,                  /* check_media_change */
439         NULL,                  /* revalidate */
440         NULL                   /* lock */
441 };
442
443
444 /* modules setup */
445
446 int init_obd(void)
447 {
448         int i;
449
450         printk(KERN_INFO "OBD class driver  v0.002, braam@stelias.com\n");
451
452         INIT_LIST_HEAD(&obd_types);
453
454         if (register_chrdev(OBD_PSDEV_MAJOR,"obd_psdev", 
455                             &obd_psdev_fops)) {
456                 printk(KERN_ERR "obd_psdev: unable to get major %d\n", 
457                        OBD_PSDEV_MAJOR);
458                 return -EIO;
459         }
460
461         for (i = 0; i < MAX_OBD_DEVICES; i++) {
462                 obd_dev[i].obd_type = 0;
463                 obd_dev[i].refcnt = 0;
464                 obd_dev[i].sb = NULL;
465                 obd_dev[i].last_id = 0;
466                 INIT_LIST_HEAD(&obd_dev[i].clients);
467         }
468
469         obd_sysctl_init();
470
471         return 0;
472 }
473
474 EXPORT_SYMBOL(obd_register_type);
475 EXPORT_SYMBOL(obd_unregister_type);
476
477 EXPORT_SYMBOL(obd_print_entry);
478 EXPORT_SYMBOL(obd_debug_level);
479 EXPORT_SYMBOL(obd_dev);
480
481 #ifdef MODULE
482 int init_module(void)
483 {
484         return init_obd();
485 }
486
487 void cleanup_module(void)
488 {
489         int i;
490         ENTRY;
491
492         unregister_chrdev(OBD_PSDEV_MAJOR, "obd_psdev");
493         for (i = 0; i < MAX_OBD_DEVICES; i++) {
494                 struct obd_device *obddev = &obd_dev[i];
495                 if ( obddev->obd_type && 
496                      obddev->obd_type->typ_ops->o_cleanup_device )
497                         return obddev->obd_type->typ_ops->o_cleanup_device(i);
498         }
499
500         obd_sysctl_clean();
501 }
502 #endif