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