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