1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
4 * lustre/lib/fsfilt_ext3.c
5 * Lustre filesystem abstraction routines
7 * Copyright (C) 2002 Cluster File Systems, Inc.
8 * Author: Andreas Dilger <adilger@clusterfs.com>
10 * This file is part of Lustre, http://www.lustre.org.
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.
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.
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.
26 #error "FIXME: this needs to be updated to match fsfilt_extN.c"
28 #define DEBUG_SUBSYSTEM S_FILTER
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>
42 static kmem_cache_t *fcb_cache;
43 static int fcb_cache_count;
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 */
52 #define EXT3_XATTR_INDEX_LUSTRE 5
53 #define XATTR_LUSTRE_MDS_OBJID "system.lustre_mds_objid"
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
61 static void *fsfilt_ext3_start(struct inode *inode, int op)
63 /* For updates to the last recieved file */
64 int nblocks = EXT3_DATA_TRANS_BLOCKS;
69 case FSFILT_OP_UNLINK:
70 nblocks += EXT3_DELETE_TRANS_BLOCKS;
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 */
78 case FSFILT_OP_CREATE:
81 /* New inode + block bitmap + GDT for new file */
84 /* Change parent directory */
85 nblocks += EXT3_INDEX_EXTRA_TRANS_BLOCKS+EXT3_DATA_TRANS_BLOCKS;
87 case FSFILT_OP_SETATTR:
88 /* Setattr on inode */
91 default: CERROR("unknown transaction start op %d\n", op);
96 handle = journal_start(EXT3_JOURNAL(inode), nblocks);
102 static int fsfilt_ext3_commit(struct inode *inode, void *handle)
107 rc = journal_stop((handle_t *)handle);
113 static int fsfilt_ext3_setattr(struct dentry *dentry, void *handle,
116 struct inode *inode = dentry->d_inode;
120 if (inode->i_op->setattr)
121 rc = inode->i_op->setattr(dentry, iattr);
123 rc = inode_setattr(inode, iattr);
130 static int fsfilt_ext3_set_md(struct inode *inode, void *handle,
131 void *lmm, int lmm_size)
137 rc = ext3_xattr_set(handle, inode, EXT3_XATTR_INDEX_LUSTRE,
138 XATTR_LUSTRE_MDS_OBJID, lmm, lmm_size, 0);
143 CERROR("error adding MD data to inode %lu: rc = %d\n",
145 if (rc != -ENOSPC) LBUG();
150 static int fsfilt_ext3_get_md(struct inode *inode, void *lmm, int size)
156 rc = ext3_xattr_get(inode, EXT3_XATTR_INDEX_LUSTRE,
157 XATTR_LUSTRE_MDS_OBJID, lmm, size);
161 /* This gives us the MD size */
163 return (rc == -ENODATA) ? 0 : rc;
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;
175 static ssize_t fsfilt_ext3_readpage(struct file *file, char *buf, size_t count,
178 struct inode *inode = file->f_dentry->d_inode;
181 if (S_ISREG(inode->i_mode))
182 rc = file->f_op->read(file, buf, count, offset);
184 struct buffer_head *bh;
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,
193 memcpy(buf, bh->b_data, inode->i_blksize);
195 rc = inode->i_blksize;
202 static void fsfilt_ext3_cb_func(struct journal_callback *jcb, int error)
204 struct fsfilt_cb_data *fcb = (struct fsfilt_cb_data *)jcb;
206 fcb->cb_func(fcb->cb_obd, fcb->cb_last_rcvd, error);
208 kmem_cache_free(fcb_cache, fcb);
212 static int fsfilt_ext3_set_last_rcvd(struct obd_device *obd, __u64 last_rcvd,
213 void *handle, fsfilt_cb_t cb_func)
215 #ifdef HAVE_JOURNAL_CALLBACK_STATUS
216 struct fsfilt_cb_data *fcb;
218 fcb = kmem_cache_alloc(fcb_cache, GFP_NOFS);
223 fcb->cb_func = cb_func;
225 fcb->cb_last_rcvd = last_rcvd;
227 CDEBUG(D_EXT2, "set callback for last_rcvd: "LPD64"\n", last_rcvd);
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);
234 #warning "no journal callback kernel patch, faking it..."
235 static long next = 0;
237 if (time_after(jiffies, next)) {
238 CERROR("no journal callback kernel patch, faking it...\n");
239 next = jiffies + 300 * HZ;
242 cb_func(obd, last_rcvd, 0);
248 static int fsfilt_ext3_journal_data(struct file *filp)
250 struct inode *inode = filp->f_dentry->d_inode;
252 EXT3_I(inode)->i_flags |= EXT3_JOURNAL_DATA_FL;
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.
262 * This can be removed when the ext3 EA code is fixed.
264 static int fsfilt_ext3_statfs(struct super_block *sb, struct statfs *sfs)
266 int rc = vfs_statfs(sb, sfs);
268 if (!rc && sfs->f_bfree < sfs->f_ffree)
269 sfs->f_ffree = sfs->f_bfree;
274 static int fsfilt_ext3_sync(struct super_block *sb)
276 return ext3_force_commit(sb);
279 static struct fsfilt_operations fsfilt_ext3_ops = {
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,
294 static int __init fsfilt_ext3_init(void)
298 //rc = ext3_xattr_register();
299 fcb_cache = kmem_cache_create("fsfilt_ext3_fcb",
300 sizeof(struct fsfilt_cb_data), 0,
303 CERROR("error allocating fsfilt journal callback cache\n");
304 GOTO(out, rc = -ENOMEM);
307 rc = fsfilt_register_ops(&fsfilt_ext3_fs_ops);
310 kmem_cache_destroy(fcb_cache);
315 static void __exit fsfilt_ext3_exit(void)
319 fsfilt_unregister_ops(&fsfilt_ext3_fs_ops);
320 rc = kmem_cache_destroy(fcb_cache);
322 if (rc || fcb_cache_count) {
323 CERROR("can't free fsfilt callback cache: count %d, rc = %d\n",
324 fcb_cache_count, rc);
327 //rc = ext3_xattr_unregister();
330 MODULE_AUTHOR("Cluster File Systems, Inc. <info@clusterfs.com>");
331 MODULE_DESCRIPTION("Lustre ext3 Filesystem Helper v0.1");
332 MODULE_LICENSE("GPL");
334 module_init(fsfilt_ext3_init);
335 module_exit(fsfilt_ext3_exit);