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