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