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