Whamcloud - gitweb
- elimininate the system calls from filter obd
[fs/lustre-release.git] / lustre / obdfilter / filter.c
1 /*
2  *  linux/fs/ext2_obd/ext2_obd.c
3  *
4  * Copyright (C) 2001  Cluster File Systems, Inc.
5  *
6  * This code is issued under the GNU General Public License.
7  * See the file COPYING in this distribution
8  *
9  * by Peter Braam <braam@clusterfs.com>
10  */
11
12 #define EXPORT_SYMTAB
13
14 #include <linux/version.h>
15 #include <linux/module.h>
16 #include <linux/fs.h>
17 #include <linux/stat.h>
18 #include <linux/locks.h>
19 #include <linux/ext2_fs.h>
20 #include <linux/quotaops.h>
21 #include <asm/unistd.h>
22 #include <linux/obd_support.h>
23 #include <linux/obd_class.h>
24 #include <linux/obd_ext2.h>
25
26 extern struct obd_device obd_dev[MAX_OBD_DEVICES];
27 long filter_memory;
28
29 #define FILTER_ROOTINO 2
30
31 #define S_SHIFT 12
32
33 static char * obd_type_by_mode[S_IFMT >> S_SHIFT] = {
34         [0]                     "",
35         [S_IFREG >> S_SHIFT]    "R", 
36         [S_IFDIR >> S_SHIFT]    "D",
37         [S_IFCHR >> S_SHIFT]    "C",
38         [S_IFBLK >> S_SHIFT]    "B", 
39         [S_IFIFO >> S_SHIFT]    "F", 
40         [S_IFSOCK >> S_SHIFT]   "S",
41         [S_IFLNK >> S_SHIFT]    "L"
42 };
43
44 static void filter_id(char *buf, obd_id id, obd_mode mode)
45 {
46         sprintf(buf, "O/%s/%Ld", obd_type_by_mode[(mode & S_IFMT) >> S_SHIFT],
47                 id);
48 }
49
50 static struct file *filter_parent(obd_id id, obd_mode mode)
51 {
52         char path[64];
53         struct file *file;
54         sprintf(path, "O/%s", obd_type_by_mode[(mode & S_IFMT) >> S_SHIFT]);
55
56         file = filp_open(path, O_RDONLY, 0); 
57         return file;
58 }
59
60 void push_ctxt(struct run_ctxt *save, struct run_ctxt *new)
61
62         save->fs = get_fs();
63         save->pwd = dget(current->fs->pwd);
64         save->pwdmnt = mntget(current->fs->pwdmnt);
65
66         set_fs(new->fs);
67         set_fs_pwd(current->fs, new->pwdmnt, new->pwd);
68 }
69
70 void pop_ctxt(struct run_ctxt *saved)
71 {
72         set_fs(saved->fs);
73         set_fs_pwd(current->fs, saved->pwdmnt, saved->pwd);
74
75         dput(saved->pwd);
76         mntput(saved->pwdmnt);
77 }
78
79 static int simple_mkdir(struct dentry *dir, char *name, int mode)
80 {
81         struct dentry *dchild; 
82         int err;
83         ENTRY;
84         
85         dchild = lookup_one_len(name, dir, strlen(name));
86         if (IS_ERR(dchild)) { 
87                 EXIT;
88                 return PTR_ERR(dchild); 
89         }
90
91         if (dchild->d_inode) { 
92                 dput(dchild);
93                 EXIT;
94                 return -EEXIST;
95         }
96
97         err = vfs_mkdir(dir->d_inode, dchild, mode);
98         dput(dchild);
99         
100         EXIT;
101         return err;
102 }
103
104 static int simple_unlink(struct dentry *dir, char *name)
105 {
106         struct dentry *dchild; 
107         int err;
108         ENTRY;
109         
110         dchild = lookup_one_len(name, dir, strlen(name));
111         if (IS_ERR(dchild)) { 
112                 EXIT;
113                 return PTR_ERR(dchild); 
114         }
115
116         if (!dchild->d_inode) { 
117                 dput(dchild);
118                 EXIT;
119                 return -ENOENT;
120         }
121
122         err = vfs_unlink(dir->d_inode, dchild);
123         dput(dchild);
124         
125         EXIT;
126         return err;
127 }
128
129 static void filter_prep(struct obd_device *obddev)
130 {
131         struct run_ctxt saved;
132         struct file *file;
133         struct inode *inode;
134         loff_t off;
135         long rc;
136         char rootid[128];
137         __u64 lastino = 2;
138
139         push_ctxt(&saved, &obddev->u.filter.fo_ctxt);
140         rc = simple_mkdir(current->fs->pwd, "O", 0700);
141         rc = simple_mkdir(current->fs->pwd, "P", 0700);
142         rc = simple_mkdir(current->fs->pwd, "D", 0700);
143         file  = filp_open("O", O_RDONLY, 0); 
144         if (!file || IS_ERR(file)) { 
145                 printk(__FUNCTION__ ": cannot open O\n"); 
146                 goto out;
147         }
148         rc = simple_mkdir(file->f_dentry, "R", 0700);  /* regular */
149         rc = simple_mkdir(file->f_dentry, "D", 0700);  /* directory */
150         rc = simple_mkdir(file->f_dentry, "L", 0700);  /* symbolic links */
151         rc = simple_mkdir(file->f_dentry, "C", 0700);  /* character devices */
152         rc = simple_mkdir(file->f_dentry, "B", 0700);  /* block devices */
153         rc = simple_mkdir(file->f_dentry, "F", 0700);  /* fifo's */
154         rc = simple_mkdir(file->f_dentry, "S", 0700);  /* sockets */
155         filp_close(file, NULL); 
156
157         filter_id(rootid, FILTER_ROOTINO, S_IFDIR);
158         file = filp_open(rootid, O_RDWR | O_CREAT, 00755);
159         if (IS_ERR(file)) {
160                 printk("OBD filter: cannot make root directory"); 
161                 goto out;
162         }
163         filp_close(file, 0);
164         rc = simple_mkdir(current->fs->pwd, rootid, 0755);
165
166         file = filp_open("D/status", O_RDWR | O_CREAT, 0700);
167         if ( !file || IS_ERR(file) ) {
168                 printk("OBD filter: cannot open/create status file\n");
169                 goto out;
170         }
171
172         /* steal operations */
173         inode = file->f_dentry->d_inode;
174         obddev->u.filter.fo_fop = file->f_op;
175         obddev->u.filter.fo_iop = inode->i_op;
176         obddev->u.filter.fo_aops = inode->i_mapping->a_ops;
177
178         off = 0;
179         if (inode->i_size == 0) { 
180                 rc = file->f_op->write(file, (char *)&lastino, 
181                                        sizeof(lastino), &off);
182                 if (rc != sizeof(lastino)) { 
183                         printk("OBD filter: error writing lastino\n");
184                         goto out;
185                 }
186         } else { 
187                 rc = file->f_op->read(file, (char *)&lastino, sizeof(lastino), 
188                                       &off);
189                 if (rc != sizeof(lastino)) { 
190                         printk("OBD filter: error reading lastino\n");
191                         goto out;
192                 }
193         }
194         obddev->u.filter.fo_lastino = lastino;
195
196  out:
197         pop_ctxt(&saved);
198 }
199
200 static void filter_post(struct obd_device *obddev)
201 {
202         struct run_ctxt saved;
203         long rc;
204         struct file *file;
205         loff_t off = 0; 
206
207         push_ctxt(&saved, &obddev->u.filter.fo_ctxt);
208         file = filp_open("D/status", O_RDWR | O_CREAT, 0700);
209         if ( !file || IS_ERR(file)) { 
210                 printk("OBD filter: cannot create status file\n");
211                 goto out;
212         }
213         rc = file->f_op->write(file, (char *)&obddev->u.filter.fo_lastino, 
214                        sizeof(obddev->u.filter.fo_lastino), &off);
215         if (rc != sizeof(sizeof(obddev->u.filter.fo_lastino)) ) { 
216                 printk("OBD filter: error writing lastino\n");
217         }
218
219         rc = filp_close(file, NULL); 
220         if (rc) { 
221                 printk("OBD filter: cannot close status file\n");
222         }
223  out:
224         pop_ctxt(&saved);
225 }
226
227
228 /* release per client resources */
229 static int filter_disconnect(struct obd_conn *conn)
230 {
231         /* XXX cleanup preallocated inodes */
232         return gen_disconnect(conn);
233 } /* ext2obd_disconnect */
234
235 /* mount the file system (secretly) */
236 static int filter_setup(struct obd_device *obddev, obd_count len,
237                         void *buf)
238                         
239 {
240         struct obd_ioctl_data* data = buf;
241         struct vfsmount *mnt;
242         int err; 
243         ENTRY;
244         
245         
246         mnt = do_kern_mount(data->ioc_inlbuf2, 0, 
247                             data->ioc_inlbuf1, NULL); 
248         err = PTR_ERR(mnt);
249         if (IS_ERR(mnt)) { 
250                 EXIT;
251                 return err;
252         }
253
254         obddev->u.filter.fo_sb = mnt->mnt_root->d_inode->i_sb;
255         if (!obddev->u.filter.fo_sb) {
256                 EXIT;
257                 return -ENODEV;
258         }
259
260         obddev->u.filter.fo_vfsmnt = mnt;
261         obddev->u.filter.fo_fstype = strdup(data->ioc_inlbuf2);
262
263         obddev->u.filter.fo_ctxt.pwdmnt = mnt;
264         obddev->u.filter.fo_ctxt.pwd = mnt->mnt_root;
265         obddev->u.filter.fo_ctxt.fs = KERNEL_DS;
266
267         filter_prep(obddev);
268         spin_lock_init(&obddev->u.filter.fo_lock);
269
270         MOD_INC_USE_COUNT;
271         EXIT; 
272         return 0;
273
274
275 static __u64 filter_next_id(struct obd_device *obddev) 
276 {
277         __u64 id;
278         spin_lock(&obddev->u.filter.fo_lock);
279         obddev->u.filter.fo_lastino++;
280         id =    obddev->u.filter.fo_lastino;
281         spin_unlock(&obddev->u.filter.fo_lock);
282         return id;
283 }
284
285 static int filter_cleanup(struct obd_device * obddev)
286 {
287         struct super_block *sb;
288
289         ENTRY;
290
291         if ( !(obddev->obd_flags & OBD_SET_UP) ) {
292                 EXIT;
293                 return 0;
294         }
295
296         if ( !list_empty(&obddev->obd_gen_clients) ) {
297                 printk(KERN_WARNING __FUNCTION__ ": still has clients!\n");
298                 EXIT;
299                 return -EBUSY;
300         }
301
302         sb = obddev->u.filter.fo_sb;
303         if (!obddev->u.filter.fo_sb){
304                 EXIT;
305                 return 0;
306         }
307         filter_post(obddev);
308
309         unlock_kernel();
310         mntput(obddev->u.filter.fo_vfsmnt); 
311         obddev->u.filter.fo_sb = 0;
312         kfree(obddev->u.filter.fo_fstype);
313
314         lock_kernel();
315
316         MOD_DEC_USE_COUNT;
317         EXIT;
318         return 0;
319 }
320
321
322 static struct file *filter_obj_open(struct obd_device *obddev, 
323                                      struct obdo *oa)
324 {
325         struct file *file;
326         int error = 0;
327         char id[24];
328         struct run_ctxt saved;
329         struct super_block *sb;
330
331         sb = obddev->u.filter.fo_sb;
332         if (!sb || !sb->s_dev) {
333                 CDEBUG(D_SUPER, "fatal: device not initialized.\n");
334                 EXIT;
335                 return NULL;
336         }
337
338         if ( !oa->o_id ) {
339                 CDEBUG(D_INODE, "fatal: invalid obdo %lu\n", (long)oa->o_id);
340                 EXIT;
341                 return NULL;
342         }
343
344         if ( ! (oa->o_mode & S_IFMT) ) { 
345                 printk("OBD filter_obj_open, no type (%Ld), mode %o!\n", 
346                        oa->o_id, oa->o_mode);
347         }
348         filter_id(id, oa->o_id, oa->o_mode); 
349         push_ctxt(&saved, &obddev->u.filter.fo_ctxt);
350         file = filp_open(id , O_RDONLY | O_LARGEFILE, 0);
351         pop_ctxt(&saved);
352
353         if (IS_ERR(file)) { 
354                 error = PTR_ERR(file);
355                 file = NULL;
356         }
357         CDEBUG(D_INODE, "opening obdo %s\n", id);
358
359         return file;
360 }
361
362 static struct inode *filter_inode_from_obdo(struct obd_device *obddev, 
363                                      struct obdo *oa)
364 {
365         struct file *file;
366         struct inode *inode; 
367
368         file = filter_obj_open(obddev, oa);
369         if ( !file ) { 
370                 printk("filter_inode_from_obdo failed\n"); 
371                 return NULL;
372         }
373
374         inode = iget(file->f_dentry->d_inode->i_sb, file->f_dentry->d_inode->i_ino); 
375         filp_close(file, 0);
376         return inode;
377 }
378
379 static inline void filter_from_inode(struct obdo *oa, struct inode *inode)
380 {
381         int type = oa->o_mode & S_IFMT;
382         ENTRY;
383
384         CDEBUG(D_INFO, "src inode %ld, dst obdo %ld valid 0x%08x\n",
385                inode->i_ino, (long)oa->o_id, oa->o_valid);
386         obdo_from_inode(oa, inode);
387         oa->o_mode &= ~S_IFMT;
388         oa->o_mode |= type;
389
390         if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
391                 obd_rdev rdev = kdev_t_to_nr(inode->i_rdev);
392                 CDEBUG(D_INODE, "copying device %x from inode to obdo\n",
393                        rdev);
394                 *((obd_rdev *)oa->o_inline) = rdev;
395                 oa->o_obdflags |= OBD_FL_INLINEDATA;
396                 oa->o_valid |= OBD_MD_FLINLINE;
397         }
398
399 #if 0
400  else if (ext2obd_has_inline(inode)) {
401                 CDEBUG(D_INFO, "copying inline from inode to obdo\n");
402                 memcpy(oa->o_inline, inode->u.ext2_i.i_data,
403                        MIN(sizeof(inode->u.ext2_i.i_data),OBD_INLINESZ));
404                 oa->o_obdflags |= OBD_FL_INLINEDATA;
405                 oa->o_valid |= OBD_MD_FLINLINE;
406         }
407
408         if (ext2obd_has_obdmd(inode)) {
409                 /* XXX this will change when we don't store the obdmd in data */
410                 CDEBUG(D_INFO, "copying obdmd from inode to obdo\n");
411                 memcpy(oa->o_obdmd, inode->u.ext2_i.i_data,
412                        MIN(sizeof(inode->u.ext2_i.i_data),OBD_INLINESZ));
413                 oa->o_obdflags |= OBD_FL_OBDMDEXISTS;
414                 oa->o_valid |= OBD_MD_FLOBDMD;
415         }
416 #endif
417         EXIT;
418 }
419
420 static int filter_getattr(struct obd_conn *conn, struct obdo *oa)
421 {
422         struct inode *inode;
423
424         ENTRY;
425         if ( !gen_client(conn) ) {
426                 CDEBUG(D_IOCTL, "fatal: invalid client %u\n", conn->oc_id);
427                 EXIT;
428                 return -EINVAL;
429         }
430
431         if ( !(inode = filter_inode_from_obdo(conn->oc_dev, oa)) ) { 
432                 EXIT;
433                 return -ENOENT;
434         }
435
436         oa->o_valid &= ~OBD_MD_FLID;
437         filter_from_inode(oa, inode);
438         
439         iput(inode);
440         EXIT;
441         return 0;
442
443
444 static int filter_setattr(struct obd_conn *conn, struct obdo *oa)
445 {
446         struct inode *inode;
447         struct iattr iattr;
448         int rc;
449         struct dentry de;
450
451         if (!gen_client(conn)) {
452                 CDEBUG(D_IOCTL, "invalid client %u\n", conn->oc_id);
453                 return -EINVAL;
454         }
455
456         inode = filter_inode_from_obdo(conn->oc_dev, oa); 
457         if ( !inode ) { 
458                 EXIT;
459                 return -ENOENT;
460         }
461
462         iattr_from_obdo(&iattr, oa);
463         iattr.ia_mode &= ~S_IFMT;
464         iattr.ia_mode |= S_IFREG;
465         de.d_inode = inode;
466         if ( inode->i_op->setattr ) {
467                 rc = inode->i_op->setattr(&de, &iattr);
468         } else { 
469                 rc = inode_setattr(inode, &iattr);
470         }
471
472         iput(inode);
473         EXIT;
474         return rc;
475 }
476
477 static int filter_create (struct obd_conn* conn, struct obdo *oa)
478 {
479         char name[64];
480         struct run_ctxt saved;
481         struct file *file;
482         int mode;
483         struct obd_device *obddev = conn->oc_dev;
484         struct iattr;
485         ENTRY;
486
487         if (!gen_client(conn)) {
488                 CDEBUG(D_IOCTL, "invalid client %u\n", conn->oc_id);
489                 return -EINVAL;
490         }
491         CDEBUG(D_IOCTL, "\n");
492
493         oa->o_id = filter_next_id(conn->oc_dev);
494         if ( !(oa->o_mode && S_IFMT) ) { 
495                 printk("filter obd: no type!\n");
496                 return -ENOENT;
497         }
498
499         filter_id(name, oa->o_id, oa->o_mode);
500         push_ctxt(&saved, &obddev->u.filter.fo_ctxt);
501         mode = oa->o_mode;
502         mode &= ~S_IFMT;
503         mode |= S_IFREG; 
504         file = filp_open(name, O_RDONLY | O_CREAT, mode);
505         pop_ctxt(&saved);
506         if (IS_ERR(file)) { 
507                 printk("Error mknod obj %s, err %ld\n", name, PTR_ERR(file));
508                 return -ENOENT;
509         }
510         filp_close(file, 0);
511         CDEBUG(D_IOCTL, "\n");
512         
513         /* Set flags for fields we have set in ext2_new_inode */
514         oa->o_valid |= OBD_MD_FLID | OBD_MD_FLBLKSZ | OBD_MD_FLBLOCKS |
515                  OBD_MD_FLMTIME | OBD_MD_FLATIME | OBD_MD_FLCTIME |
516                  OBD_MD_FLUID | OBD_MD_FLGID;
517         return 0;
518 }
519
520 static int filter_destroy(struct obd_conn *conn, struct obdo *oa)
521 {
522         struct obd_device * obddev;
523         struct obd_client * cli;
524         struct inode * inode;
525         struct file *dir;
526         int rc;
527         struct run_ctxt saved;
528         char id[128];
529
530         if (!(cli = gen_client(conn))) {
531                 CDEBUG(D_IOCTL, "invalid client %u\n", conn->oc_id);
532                 EXIT;
533                 return -EINVAL;
534         }
535
536         obddev = conn->oc_dev;
537         inode = filter_inode_from_obdo(obddev, oa);
538
539         if (!inode) { 
540                 EXIT;
541                 return -ENOENT;
542         }
543
544         inode->i_nlink = 1;
545         inode->i_mode = 010000;
546         iput(inode);
547
548         filter_id(id, oa->o_id, oa->o_mode);
549         push_ctxt(&saved, &obddev->u.filter.fo_ctxt);
550         dir = filter_parent(oa->o_id, oa->o_mode); 
551         if (!dir || IS_ERR(dir)) { 
552                 goto out;
553         }
554
555         rc = simple_unlink(dir->f_dentry, id);
556         
557  out:
558         filp_close(dir, 0); 
559         pop_ctxt(&saved);
560         EXIT;
561         return rc;
562 }
563
564 static int filter_truncate(struct obd_conn *conn, struct obdo *oa, obd_size count,
565                          obd_off offset)
566 {
567         int error;
568
569         error = filter_setattr(conn, oa);
570         oa->o_valid = OBD_MD_FLBLOCKS | OBD_MD_FLCTIME | OBD_MD_FLMTIME;
571
572         EXIT;
573         return error;
574 }
575
576 /* buffer must lie in user memory here */
577 static int filter_read(struct obd_conn *conn, struct obdo *oa, char *buf,
578                         obd_size *count, obd_off offset)
579 {
580         struct file * file;
581         unsigned long retval;
582         int err;
583
584         if (!gen_client(conn)) {
585                 CDEBUG(D_IOCTL, "invalid client %u\n", conn->oc_id);
586                 EXIT;
587                 return -EINVAL;
588         }
589
590         file = filter_obj_open(conn->oc_dev, oa); 
591         if (!file || IS_ERR(file)) { 
592                 EXIT;
593                 return -PTR_ERR(file);
594         }
595
596         /* count doubles as retval */
597         retval = file->f_op->read(file, buf, *count, &offset);
598         filp_close(file, 0);
599
600         if ( retval >= 0 ) {
601                 err = 0;
602                 *count = retval;
603         } else {
604                 err = retval;
605                 *count = 0;
606         }
607
608         return err;
609 } /* ext2obd_read */
610
611
612 /* buffer must lie in user memory here */
613 static int filter_write(struct obd_conn *conn, struct obdo *oa, char *buf, 
614                          obd_size *count, obd_off offset)
615 {
616         int err;
617         struct file * file;
618         unsigned long retval;
619
620         ENTRY;
621         if (!gen_client(conn)) {
622                 CDEBUG(D_IOCTL, "invalid client %u\n", conn->oc_id);
623                 EXIT;
624                 return -EINVAL;
625         }
626
627         file = filter_obj_open(conn->oc_dev, oa); 
628         if (!file || IS_ERR(file)) { 
629                 EXIT;
630                 return -PTR_ERR(file);
631         }
632
633         /* count doubles as retval */
634         retval = file->f_op->write(file, buf, *count, &offset);
635         filp_close(file, 0);
636
637         if ( retval >= 0 ) {
638                 err = 0;
639                 *count = retval;
640                 EXIT;
641         } else {
642                 err = retval;
643                 *count = 0;
644                 EXIT;
645         }
646
647         return err;
648 } /* ext2obd_write */
649
650 static int filter_pgcache_brw(int rw, struct obd_conn *conn, 
651                                obd_count num_oa,
652                                struct obdo **oa, 
653                                obd_count *oa_bufs, 
654                                struct page **pages,
655                                obd_size *count, 
656                                obd_off *offset, 
657                                obd_flag *flags)
658 {
659         struct super_block      *sb;
660         mm_segment_t oldfs;
661         int                      onum;          /* index to oas */
662         int                      pnum;          /* index to pages (bufs) */
663         unsigned long            retval;
664         int                      error;
665         struct file *file;
666
667         ENTRY;
668
669         if (!gen_client(conn)) {
670                 CDEBUG(D_IOCTL, "invalid client %u\n", conn->oc_id);
671                 EXIT;
672                 return -EINVAL;
673         }
674
675         sb = conn->oc_dev->u.filter.fo_sb;
676         oldfs = get_fs();
677         set_fs(KERNEL_DS); 
678
679         pnum = 0; /* pnum indexes buf 0..num_pages */
680         for (onum = 0; onum < num_oa; onum++) {
681                 int              pg;
682
683                 file = filter_obj_open(conn->oc_dev, oa[onum]); 
684                 if (!file || IS_ERR(file)) { 
685                         EXIT;
686                         error = -ENOENT;
687                         goto ERROR;
688                 }
689
690                 /* count doubles as retval */
691                 for (pg = 0; pg < oa_bufs[onum]; pg++) {
692                         CDEBUG(D_INODE, "OP %d obdo no/pno: (%d,%d) (%ld,%ld) off count (%Ld,%Ld)\n", 
693                                rw, onum, pnum, file->f_dentry->d_inode->i_ino,
694                                (unsigned long)offset[pnum] >> PAGE_CACHE_SHIFT,
695                                offset[pnum], count[pnum]);
696                         if (rw == WRITE) { 
697                                 loff_t off; 
698                                 char *buffer;
699                                 off = offset[pnum]; 
700                                 buffer = kmap(pages[pnum]); 
701                                 retval = file->f_op->write(file, buffer, count[pnum], &off);
702                                 kunmap(pages[pnum]);
703                                 CDEBUG(D_INODE, "retval %ld\n", retval); 
704                         } else { 
705                                 loff_t off = offset[pnum]; 
706                                 char *buffer = kmap(pages[pnum]);
707
708                                 if (off >= file->f_dentry->d_inode->i_size) {
709                                         memset(buffer, 0, count[pnum]);
710                                         retval = count[pnum];
711                                 } else {
712                                         retval = file->f_op->read(file, buffer, count[pnum], &off);
713                                 } 
714                                 kunmap(pages[pnum]);
715
716                                 if ( retval != count[pnum] ) {
717                                         filp_close(file, 0);
718                                         retval = -EIO;
719                                         EXIT;
720                                         goto ERROR;
721                                 }
722                                 CDEBUG(D_INODE, "retval %ld\n", retval); 
723                         }
724                         pnum++;
725                 }
726                 /* sizes and blocks are set by generic_file_write */
727                 /* ctimes/mtimes will follow with a setattr call */ 
728                 filp_close(file, 0);
729         }
730         
731         EXIT;
732  ERROR:
733         set_fs(oldfs);
734         error = (retval >= 0) ? 0 : retval;
735         return error;
736 }
737
738 static int filter_statfs (struct obd_conn *conn, struct statfs * statfs)
739 {
740         struct super_block *sb;
741         int err;
742
743         ENTRY;
744
745         if (!gen_client(conn)) {
746                 CDEBUG(D_IOCTL, "invalid client %u\n", conn->oc_id);
747                 EXIT;
748                 return -EINVAL;
749         }
750
751         sb = conn->oc_dev->u.filter.fo_sb;
752
753         err = sb->s_op->statfs(sb, statfs);
754         EXIT;
755         return err;
756 } /* ext2obd_statfs */
757
758
759 static int  filter_get_info(struct obd_conn *conn, obd_count keylen,
760                              void *key, obd_count *vallen, void **val)
761 {
762         struct obd_device *obddev;
763         struct obd_client * cli;
764         ENTRY;
765
766         if (!(cli = gen_client(conn))) {
767                 CDEBUG(D_IOCTL, "invalid client %u\n", conn->oc_id);
768                 return -EINVAL;
769         }
770
771         obddev = conn->oc_dev;
772         
773         if ( keylen == strlen("blocksize") &&
774              memcmp(key, "blocksize", keylen) == 0 ) {
775                 *vallen = sizeof(int);
776                 *val = (void *)obddev->u.filter.fo_sb->s_blocksize;
777                 EXIT;
778                 return 0;
779         }
780
781         if ( keylen == strlen("blocksize_bits") &&
782              memcmp(key, "blocksize_bits", keylen) == 0 ){
783                 *vallen = sizeof(int);
784                 *val = (void *)(int)obddev->u.filter.fo_sb->s_blocksize_bits;
785                 EXIT;
786                 return 0;
787         }
788
789         if ( keylen == strlen("root_ino") &&
790              memcmp(key, "root_ino", keylen) == 0 ){
791                 *vallen = sizeof(int);
792                 *val = (void *)(int) FILTER_ROOTINO;
793                 EXIT;
794                 return 0;
795         }
796         
797         CDEBUG(D_IOCTL, "invalid key\n");
798         return -EINVAL;
799 }
800
801
802 struct obd_ops filter_obd_ops = {
803         o_iocontrol:   NULL,
804         o_get_info:    filter_get_info,
805         o_setup:       filter_setup,
806         o_cleanup:     filter_cleanup,
807         o_connect:     gen_connect,
808         o_disconnect:  filter_disconnect,
809         o_statfs:      filter_statfs,
810         o_getattr:     filter_getattr,
811         o_create:      filter_create,
812         o_setattr:     filter_setattr,
813         o_destroy:     filter_destroy,
814         o_read:        filter_read,
815         o_write:       filter_write,
816         o_brw:         filter_pgcache_brw,
817         o_punch:       filter_truncate,
818 #if 0
819         o_preallocate: ext2obd_preallocate_inodes,
820         o_migrate:     ext2obd_migrate,
821         o_copy:        gen_copy_data,
822         o_iterate:     ext2obd_iterate
823 #endif
824 };
825
826
827 static int __init obdfilter_init(void)
828 {
829         printk(KERN_INFO "Filtering OBD driver  v0.001, braam@clusterfs.com\n");
830         return obd_register_type(&filter_obd_ops, OBD_FILTER_DEVICENAME);
831 }
832
833 static void __exit obdfilter_exit(void)
834 {
835         obd_unregister_type(OBD_FILTER_DEVICENAME);
836 }
837
838 MODULE_AUTHOR("Peter J. Braam <braam@clusterfs.com>");
839 MODULE_DESCRIPTION("Lustre Filtering OBD driver v1.0");
840 MODULE_LICENSE("GPL"); 
841
842 module_init(obdfilter_init);
843 module_exit(obdfilter_exit);