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/version.h>
37 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
38 # include <linux/ext3_xattr.h>
40 # include <asm/statfs.h>
42 #include <linux/kp30.h>
43 #include <linux/lustre_fsfilt.h>
44 #include <linux/obd.h>
45 #include <linux/module.h>
47 static kmem_cache_t *fcb_cache;
48 static atomic_t fcb_cache_count = ATOMIC_INIT(0);
50 struct fsfilt_cb_data {
51 struct journal_callback cb_jcb; /* data private to jbd */
52 fsfilt_cb_t cb_func; /* MDS/OBD completion function */
53 struct obd_device *cb_obd; /* MDS/OBD completion device */
54 __u64 cb_last_rcvd; /* MDS/OST last committed operation */
57 #define EXT3_XATTR_INDEX_LUSTRE 5
58 #define XATTR_LUSTRE_MDS_OBJID "system.lustre_mds_objid"
61 * We don't currently need any additional blocks for rmdir and
62 * unlink transactions because we are storing the OST oa_id inside
63 * the inode (which we will be changing anyways as part of this
66 static void *fsfilt_ext3_start(struct inode *inode, int op)
68 /* For updates to the last recieved file */
69 int nblocks = EXT3_DATA_TRANS_BLOCKS;
74 case FSFILT_OP_UNLINK:
75 nblocks += EXT3_DELETE_TRANS_BLOCKS;
77 case FSFILT_OP_RENAME:
78 /* We may be modifying two directories */
79 nblocks += EXT3_DATA_TRANS_BLOCKS;
80 case FSFILT_OP_SYMLINK:
81 /* Possible new block + block bitmap + GDT for long symlink */
83 case FSFILT_OP_CREATE:
86 /* New inode + block bitmap + GDT for new file */
89 /* Change parent directory */
90 nblocks += EXT3_INDEX_EXTRA_TRANS_BLOCKS+EXT3_DATA_TRANS_BLOCKS;
92 case FSFILT_OP_SETATTR:
93 /* Setattr on inode */
96 default: CERROR("unknown transaction start op %d\n", op);
101 handle = journal_start(EXT3_JOURNAL(inode), nblocks);
107 static int fsfilt_ext3_commit(struct inode *inode, void *handle)
112 rc = journal_stop((handle_t *)handle);
118 static int fsfilt_ext3_setattr(struct dentry *dentry, void *handle,
121 struct inode *inode = dentry->d_inode;
125 if (inode->i_op->setattr)
126 rc = inode->i_op->setattr(dentry, iattr);
128 rc = inode_setattr(inode, iattr);
135 static int fsfilt_ext3_set_md(struct inode *inode, void *handle,
136 void *lmm, int lmm_size)
142 rc = ext3_xattr_set(handle, inode, EXT3_XATTR_INDEX_LUSTRE,
143 XATTR_LUSTRE_MDS_OBJID, lmm, lmm_size, 0);
148 CERROR("error adding MD data to inode %lu: rc = %d\n",
150 if (rc != -ENOSPC) LBUG();
155 static int fsfilt_ext3_get_md(struct inode *inode, void *lmm, int size)
161 rc = ext3_xattr_get(inode, EXT3_XATTR_INDEX_LUSTRE,
162 XATTR_LUSTRE_MDS_OBJID, lmm, size);
166 /* This gives us the MD size */
168 return (rc == -ENODATA) ? 0 : rc;
171 CDEBUG(D_INFO, "error getting EA %s from inode %lu: "
172 "rc = %d\n", XATTR_LUSTRE_MDS_OBJID, inode->i_ino, rc);
173 memset(lmm, 0, size);
174 return (rc == -ENODATA) ? 0 : rc;
180 static ssize_t fsfilt_ext3_readpage(struct file *file, char *buf, size_t count,
183 struct inode *inode = file->f_dentry->d_inode;
186 if (S_ISREG(inode->i_mode))
187 rc = file->f_op->read(file, buf, count, offset);
189 struct buffer_head *bh;
191 /* FIXME: this assumes the blocksize == count, but the calling
192 * function will detect this as an error for now */
193 bh = ext3_bread(NULL, inode,
194 *offset >> inode->i_sb->s_blocksize_bits,
198 memcpy(buf, bh->b_data, inode->i_blksize);
200 rc = inode->i_blksize;
207 static void fsfilt_ext3_cb_func(struct journal_callback *jcb, int error)
209 struct fsfilt_cb_data *fcb = (struct fsfilt_cb_data *)jcb;
211 fcb->cb_func(fcb->cb_obd, fcb->cb_last_rcvd, error);
213 kmem_cache_free(fcb_cache, fcb);
214 atomic_dec(&fcb_cache_count);
217 static int fsfilt_ext3_set_last_rcvd(struct obd_device *obd, __u64 last_rcvd,
218 void *handle, fsfilt_cb_t cb_func)
220 #ifdef HAVE_JOURNAL_CALLBACK_STATUS
221 struct fsfilt_cb_data *fcb;
223 fcb = kmem_cache_alloc(fcb_cache, GFP_NOFS);
227 atomic_inc(&fcb_cache_count);
228 fcb->cb_func = cb_func;
230 fcb->cb_last_rcvd = last_rcvd;
232 CDEBUG(D_EXT2, "set callback for last_rcvd: "LPD64"\n", last_rcvd);
234 /* Note that an "incompatible pointer" warning here is OK for now */
235 journal_callback_set(handle, fsfilt_ext3_cb_func,
236 (struct journal_callback *)fcb);
239 #warning "no journal callback kernel patch, faking it..."
240 static long next = 0;
242 if (time_after(jiffies, next)) {
243 CERROR("no journal callback kernel patch, faking it...\n");
244 next = jiffies + 300 * HZ;
247 cb_func(obd, last_rcvd, 0);
253 static int fsfilt_ext3_journal_data(struct file *filp)
255 struct inode *inode = filp->f_dentry->d_inode;
257 EXT3_I(inode)->i_flags |= EXT3_JOURNAL_DATA_FL;
263 * We need to hack the return value for the free inode counts because
264 * the current EA code requires one filesystem block per inode with EAs,
265 * so it is possible to run out of blocks before we run out of inodes.
267 * This can be removed when the ext3 EA code is fixed.
269 static int fsfilt_ext3_statfs(struct super_block *sb, struct statfs *sfs)
271 int rc = vfs_statfs(sb, sfs);
273 if (!rc && sfs->f_bfree < sfs->f_ffree)
274 sfs->f_ffree = sfs->f_bfree;
279 static int fsfilt_ext3_sync(struct super_block *sb)
281 return ext3_force_commit(sb);
284 static struct fsfilt_operations fsfilt_ext3_ops = {
286 fs_owner: THIS_MODULE,
287 fs_start: fsfilt_ext3_start,
288 fs_commit: fsfilt_ext3_commit,
289 fs_setattr: fsfilt_ext3_setattr,
290 fs_set_md: fsfilt_ext3_set_md,
291 fs_get_md: fsfilt_ext3_get_md,
292 fs_readpage: fsfilt_ext3_readpage,
293 fs_journal_data: fsfilt_ext3_journal_data,
294 fs_set_last_rcvd: fsfilt_ext3_set_last_rcvd,
295 fs_statfs: fsfilt_ext3_statfs,
296 fs_sync: fsfilt_ext3_sync,
299 static int __init fsfilt_ext3_init(void)
303 //rc = ext3_xattr_register();
304 fcb_cache = kmem_cache_create("fsfilt_ext3_fcb",
305 sizeof(struct fsfilt_cb_data), 0,
308 CERROR("error allocating fsfilt journal callback cache\n");
309 GOTO(out, rc = -ENOMEM);
312 rc = fsfilt_register_ops(&fsfilt_ext3_ops);
315 kmem_cache_destroy(fcb_cache);
320 static void __exit fsfilt_ext3_exit(void)
324 fsfilt_unregister_ops(&fsfilt_ext3_ops);
325 rc = kmem_cache_destroy(fcb_cache);
327 if (rc || atomic_read(&fcb_cache_count)) {
328 CERROR("can't free fsfilt callback cache: count %d, rc = %d\n",
329 atomic_read(&fcb_cache_count), rc);
332 //rc = ext3_xattr_unregister();
335 MODULE_AUTHOR("Cluster File Systems, Inc. <info@clusterfs.com>");
336 MODULE_DESCRIPTION("Lustre ext3 Filesystem Helper v0.1");
337 MODULE_LICENSE("GPL");
339 module_init(fsfilt_ext3_init);
340 module_exit(fsfilt_ext3_exit);