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