Whamcloud - gitweb
Merge b_md into HEAD
[fs/lustre-release.git] / lustre / obdclass / fsfilt_ext3.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  lustre/lib/fsfilt_ext3.c
5  *  Lustre filesystem abstraction routines
6  *
7  *  Copyright (C) 2002 Cluster File Systems, Inc.
8  *   Author: Andreas Dilger <adilger@clusterfs.com>
9  *
10  *   This file is part of Lustre, http://www.lustre.org.
11  *
12  *   Lustre is free software; you can redistribute it and/or
13  *   modify it under the terms of version 2 of the GNU General Public
14  *   License as published by the Free Software Foundation.
15  *
16  *   Lustre is distributed in the hope that it will be useful,
17  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *   GNU General Public License for more details.
20  *
21  *   You should have received a copy of the GNU General Public License
22  *   along with Lustre; if not, write to the Free Software
23  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24  */
25
26 #error "FIXME: this needs to be updated to match fsfilt_extN.c"
27
28 #define DEBUG_SUBSYSTEM S_FILTER
29
30 #include <linux/fs.h>
31 #include <linux/jbd.h>
32 #include <linux/slab.h>
33 #include <linux/init.h>
34 #include <linux/ext3_fs.h>
35 #include <linux/ext3_jbd.h>
36 #include <linux/ext3_xattr.h>
37 #include <linux/kp30.h>
38 #include <linux/lustre_fsfilt.h>
39 #include <linux/obd.h>
40 #include <linux/module.h>
41
42 static kmem_cache_t *fcb_cache;
43 static int fcb_cache_count;
44
45 struct fsfilt_cb_data {
46         struct journal_callback cb_jcb; /* data private to jbd */
47         fsfilt_cb_t cb_func;            /* MDS/OBD completion function */
48         struct obd_device *cb_obd;      /* MDS/OBD completion device */
49         __u64 cb_last_rcvd;             /* MDS/OST last committed operation */
50 };
51
52 #define EXT3_XATTR_INDEX_LUSTRE         5
53 #define XATTR_LUSTRE_MDS_OBJID          "system.lustre_mds_objid"
54
55 /*
56  * We don't currently need any additional blocks for rmdir and
57  * unlink transactions because we are storing the OST oa_id inside
58  * the inode (which we will be changing anyways as part of this
59  * transaction).
60  */
61 static void *fsfilt_ext3_start(struct inode *inode, int op)
62 {
63         /* For updates to the last recieved file */
64         int nblocks = EXT3_DATA_TRANS_BLOCKS;
65         void *handle;
66
67         switch(op) {
68         case FSFILT_OP_RMDIR:
69         case FSFILT_OP_UNLINK:
70                 nblocks += EXT3_DELETE_TRANS_BLOCKS;
71                 break;
72         case FSFILT_OP_RENAME:
73                 /* We may be modifying two directories */
74                 nblocks += EXT3_DATA_TRANS_BLOCKS;
75         case FSFILT_OP_SYMLINK:
76                 /* Possible new block + block bitmap + GDT for long symlink */
77                 nblocks += 3;
78         case FSFILT_OP_CREATE:
79         case FSFILT_OP_MKDIR:
80         case FSFILT_OP_MKNOD:
81                 /* New inode + block bitmap + GDT for new file */
82                 nblocks += 3;
83         case FSFILT_OP_LINK:
84                 /* Change parent directory */
85                 nblocks += EXT3_INDEX_EXTRA_TRANS_BLOCKS+EXT3_DATA_TRANS_BLOCKS;
86                 break;
87         case FSFILT_OP_SETATTR:
88                 /* Setattr on inode */
89                 nblocks += 1;
90                 break;
91         default: CERROR("unknown transaction start op %d\n", op);
92                  LBUG();
93         }
94
95         lock_kernel();
96         handle = journal_start(EXT3_JOURNAL(inode), nblocks);
97         unlock_kernel();
98
99         return handle;
100 }
101
102 static int fsfilt_ext3_commit(struct inode *inode, void *handle)
103 {
104         int rc;
105
106         lock_kernel();
107         rc = journal_stop((handle_t *)handle);
108         unlock_kernel();
109
110         return rc;
111 }
112
113 static int fsfilt_ext3_setattr(struct dentry *dentry, void *handle,
114                                struct iattr *iattr)
115 {
116         struct inode *inode = dentry->d_inode;
117         int rc;
118
119         lock_kernel();
120         if (inode->i_op->setattr)
121                 rc = inode->i_op->setattr(dentry, iattr);
122         else
123                 rc = inode_setattr(inode, iattr);
124
125         unlock_kernel();
126
127         return rc;
128 }
129
130 static int fsfilt_ext3_set_md(struct inode *inode, void *handle,
131                               void *lmm, int lmm_size)
132 {
133         int rc;
134
135         down(&inode->i_sem);
136         lock_kernel();
137         rc = ext3_xattr_set(handle, inode, EXT3_XATTR_INDEX_LUSTRE,
138                             XATTR_LUSTRE_MDS_OBJID, lmm, lmm_size, 0);
139         unlock_kernel();
140         up(&inode->i_sem);
141
142         if (rc) {
143                 CERROR("error adding MD data to inode %lu: rc = %d\n",
144                        inode->i_ino, rc);
145                 if (rc != -ENOSPC) LBUG();
146         }
147         return rc;
148 }
149
150 static int fsfilt_ext3_get_md(struct inode *inode, void *lmm, int size)
151 {
152         int rc;
153
154         down(&inode->i_sem);
155         lock_kernel();
156         rc = ext3_xattr_get(inode, EXT3_XATTR_INDEX_LUSTRE,
157                             XATTR_LUSTRE_MDS_OBJID, lmm, size);
158         unlock_kernel();
159         up(&inode->i_sem);
160
161         /* This gives us the MD size */
162         if (lmm == NULL)
163                 return (rc == -ENODATA) ? 0 : rc;
164
165         if (rc < 0) {
166                 CDEBUG(D_INFO, "error getting EA %s from inode %lu: "
167                        "rc = %d\n", XATTR_LUSTRE_MDS_OBJID, inode->i_ino, rc);
168                 memset(lmm, 0, size);
169                 return (rc == -ENODATA) ? 0 : rc;
170         }
171
172         return rc;
173 }
174
175 static ssize_t fsfilt_ext3_readpage(struct file *file, char *buf, size_t count,
176                                     loff_t *offset)
177 {
178         struct inode *inode = file->f_dentry->d_inode;
179         int rc = 0;
180
181         if (S_ISREG(inode->i_mode))
182                 rc = file->f_op->read(file, buf, count, offset);
183         else {
184                 struct buffer_head *bh;
185
186                 /* FIXME: this assumes the blocksize == count, but the calling
187                  *        function will detect this as an error for now */
188                 bh = ext3_bread(NULL, inode,
189                                 *offset >> inode->i_sb->s_blocksize_bits,
190                                 0, &rc);
191
192                 if (bh) {
193                         memcpy(buf, bh->b_data, inode->i_blksize);
194                         brelse(bh);
195                         rc = inode->i_blksize;
196                 }
197         }
198
199         return rc;
200 }
201
202 static void fsfilt_ext3_cb_func(struct journal_callback *jcb, int error)
203 {
204         struct fsfilt_cb_data *fcb = (struct fsfilt_cb_data *)jcb;
205
206         fcb->cb_func(fcb->cb_obd, fcb->cb_last_rcvd, error);
207
208         kmem_cache_free(fcb_cache, fcb);
209         --fcb_cache_count;
210 }
211
212 static int fsfilt_ext3_set_last_rcvd(struct obd_device *obd, __u64 last_rcvd,
213                                      void *handle, fsfilt_cb_t cb_func)
214 {
215 #ifdef HAVE_JOURNAL_CALLBACK_STATUS
216         struct fsfilt_cb_data *fcb;
217
218         fcb = kmem_cache_alloc(fcb_cache, GFP_NOFS);
219         if (!fcb)
220                 RETURN(-ENOMEM);
221
222         ++fcb_cache_count;
223         fcb->cb_func = cb_func;
224         fcb->cb_obd = obd;
225         fcb->cb_last_rcvd = last_rcvd;
226
227         CDEBUG(D_EXT2, "set callback for last_rcvd: "LPD64"\n", last_rcvd);
228         lock_kernel();
229         /* Note that an "incompatible pointer" warning here is OK for now */
230         journal_callback_set(handle, fsfilt_ext3_cb_func,
231                              (struct journal_callback *)fcb);
232         unlock_kernel();
233 #else
234 #warning "no journal callback kernel patch, faking it..."
235         static long next = 0;
236
237         if (time_after(jiffies, next)) {
238                 CERROR("no journal callback kernel patch, faking it...\n");
239                 next = jiffies + 300 * HZ;
240         }
241
242         cb_func(obd, last_rcvd, 0);
243 #endif
244
245         return 0;
246 }
247
248 static int fsfilt_ext3_journal_data(struct file *filp)
249 {
250         struct inode *inode = filp->f_dentry->d_inode;
251
252         EXT3_I(inode)->i_flags |= EXT3_JOURNAL_DATA_FL;
253
254         return 0;
255 }
256
257 /*
258  * We need to hack the return value for the free inode counts because
259  * the current EA code requires one filesystem block per inode with EAs,
260  * so it is possible to run out of blocks before we run out of inodes.
261  *
262  * This can be removed when the ext3 EA code is fixed.
263  */
264 static int fsfilt_ext3_statfs(struct super_block *sb, struct statfs *sfs)
265 {
266         int rc = vfs_statfs(sb, sfs);
267
268         if (!rc && sfs->f_bfree < sfs->f_ffree)
269                 sfs->f_ffree = sfs->f_bfree;
270
271         return rc;
272 }
273
274 static int fsfilt_ext3_sync(struct super_block *sb)
275 {
276         return ext3_force_commit(sb);
277 }
278
279 static struct fsfilt_operations fsfilt_ext3_ops = {
280         fs_type:                "ext3",
281         fs_owner:               THIS_MODULE,
282         fs_start:               fsfilt_ext3_start,
283         fs_commit:              fsfilt_ext3_commit,
284         fs_setattr:             fsfilt_ext3_setattr,
285         fs_set_md:              fsfilt_ext3_set_md,
286         fs_get_md:              fsfilt_ext3_get_md,
287         fs_readpage:            fsfilt_ext3_readpage,
288         fs_journal_data:        fsfilt_ext3_journal_data,
289         fs_set_last_rcvd:       fsfilt_ext3_set_last_rcvd,
290         fs_statfs:              fsfilt_ext3_statfs,
291         fs_sync:                fsfilt_ext3_sync,
292 };
293
294 static int __init fsfilt_ext3_init(void)
295 {
296         int rc;
297
298         //rc = ext3_xattr_register();
299         fcb_cache = kmem_cache_create("fsfilt_ext3_fcb",
300                                       sizeof(struct fsfilt_cb_data), 0,
301                                       0, NULL, NULL);
302         if (!fcb_cache) {
303                 CERROR("error allocating fsfilt journal callback cache\n");
304                 GOTO(out, rc = -ENOMEM);
305         }
306
307         rc = fsfilt_register_ops(&fsfilt_ext3_fs_ops);
308
309         if (rc)
310                 kmem_cache_destroy(fcb_cache);
311 out:
312         return rc;
313 }
314
315 static void __exit fsfilt_ext3_exit(void)
316 {
317         int rc;
318
319         fsfilt_unregister_ops(&fsfilt_ext3_fs_ops);
320         rc = kmem_cache_destroy(fcb_cache);
321
322         if (rc || fcb_cache_count) {
323                 CERROR("can't free fsfilt callback cache: count %d, rc = %d\n",
324                        fcb_cache_count, rc);
325         }
326
327         //rc = ext3_xattr_unregister();
328 }
329
330 MODULE_AUTHOR("Cluster File Systems, Inc. <info@clusterfs.com>");
331 MODULE_DESCRIPTION("Lustre ext3 Filesystem Helper v0.1");
332 MODULE_LICENSE("GPL");
333
334 module_init(fsfilt_ext3_init);
335 module_exit(fsfilt_ext3_exit);