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