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