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 #define DEBUG_SUBSYSTEM S_FILTER
29 #include <linux/jbd.h>
30 #include <linux/slab.h>
31 #include <linux/init.h>
32 #include <linux/ext3_fs.h>
33 #include <linux/ext3_jbd.h>
34 #include <linux/ext3_xattr.h>
35 #include <linux/kp30.h>
36 #include <linux/lustre_fsfilt.h>
37 #include <linux/obd.h>
38 #include <linux/module.h>
40 static kmem_cache_t *fcb_cache;
41 static int fcb_cache_count;
43 struct fsfilt_cb_data {
44 struct journal_callback cb_jcb; /* data private to jbd */
45 fsfilt_cb_t cb_func; /* MDS/OBD completion function */
46 struct obd_device *cb_obd; /* MDS/OBD completion device */
47 __u64 cb_last_rcvd; /* MDS/OST last committed operation */
50 #define EXT3_XATTR_INDEX_LUSTRE 5
51 #define XATTR_LUSTRE_MDS_OBJID "system.lustre_mds_objid"
54 * We don't currently need any additional blocks for rmdir and
55 * unlink transactions because we are storing the OST oa_id inside
56 * the inode (which we will be changing anyways as part of this
59 static void *fsfilt_ext3_start(struct inode *inode, int op)
61 /* For updates to the last recieved file */
62 int nblocks = EXT3_DATA_TRANS_BLOCKS;
67 case FSFILT_OP_UNLINK:
68 nblocks += EXT3_DELETE_TRANS_BLOCKS;
70 case FSFILT_OP_RENAME:
71 /* We may be modifying two directories */
72 nblocks += EXT3_DATA_TRANS_BLOCKS;
73 case FSFILT_OP_SYMLINK:
74 /* Possible new block + block bitmap + GDT for long symlink */
76 case FSFILT_OP_CREATE:
79 /* New inode + block bitmap + GDT for new file */
82 /* Change parent directory */
83 nblocks += EXT3_INDEX_EXTRA_TRANS_BLOCKS+EXT3_DATA_TRANS_BLOCKS;
85 case FSFILT_OP_SETATTR:
86 /* Setattr on inode */
89 default: CERROR("unknown transaction start op %d\n", op);
94 handle = journal_start(EXT3_JOURNAL(inode), nblocks);
100 static int fsfilt_ext3_commit(struct inode *inode, void *handle)
105 rc = journal_stop((handle_t *)handle);
111 static int fsfilt_ext3_setattr(struct dentry *dentry, void *handle,
114 struct inode *inode = dentry->d_inode;
118 if (inode->i_op->setattr)
119 rc = inode->i_op->setattr(dentry, iattr);
121 rc = inode_setattr(inode, iattr);
128 static int fsfilt_ext3_set_md(struct inode *inode, void *handle,
129 void *lmm, int lmm_size)
135 rc = ext3_xattr_set(handle, inode, EXT3_XATTR_INDEX_LUSTRE,
136 XATTR_LUSTRE_MDS_OBJID, lmm, lmm_size, 0);
141 CERROR("error adding MD data to inode %lu: rc = %d\n",
143 if (rc != -ENOSPC) LBUG();
148 static int fsfilt_ext3_get_md(struct inode *inode, void *lmm, int size)
154 rc = ext3_xattr_get(inode, EXT3_XATTR_INDEX_LUSTRE,
155 XATTR_LUSTRE_MDS_OBJID, lmm, size);
159 /* This gives us the MD size */
161 return (rc == -ENODATA) ? 0 : rc;
164 CDEBUG(D_INFO, "error getting EA %s from inode %lu: "
165 "rc = %d\n", XATTR_LUSTRE_MDS_OBJID, inode->i_ino, rc);
166 memset(lmm, 0, size);
167 return (rc == -ENODATA) ? 0 : rc;
173 static ssize_t fsfilt_ext3_readpage(struct file *file, char *buf, size_t count,
176 struct inode *inode = file->f_dentry->d_inode;
179 if (S_ISREG(inode->i_mode))
180 rc = file->f_op->read(file, buf, count, offset);
182 struct buffer_head *bh;
184 /* FIXME: this assumes the blocksize == count, but the calling
185 * function will detect this as an error for now */
186 bh = ext3_bread(NULL, inode,
187 *offset >> inode->i_sb->s_blocksize_bits,
191 memcpy(buf, bh->b_data, inode->i_blksize);
193 rc = inode->i_blksize;
200 static void fsfilt_ext3_cb_func(struct journal_callback *jcb, int error)
202 struct fsfilt_cb_data *fcb = (struct fsfilt_cb_data *)jcb;
204 fcb->cb_func(fcb->cb_obd, fcb->cb_last_rcvd, error);
206 kmem_cache_free(fcb_cache, fcb);
210 static int fsfilt_ext3_set_last_rcvd(struct obd_device *obd, __u64 last_rcvd,
211 void *handle, fsfilt_cb_t cb_func)
213 #ifdef HAVE_JOURNAL_CALLBACK_STATUS
214 struct fsfilt_cb_data *fcb;
216 fcb = kmem_cache_alloc(fcb_cache, GFP_NOFS);
221 fcb->cb_func = cb_func;
223 fcb->cb_last_rcvd = last_rcvd;
225 CDEBUG(D_EXT2, "set callback for last_rcvd: "LPD64"\n", last_rcvd);
227 /* Note that an "incompatible pointer" warning here is OK for now */
228 journal_callback_set(handle, fsfilt_ext3_cb_func,
229 (struct journal_callback *)fcb);
232 #warning "no journal callback kernel patch, faking it..."
233 static long next = 0;
235 if (time_after(jiffies, next)) {
236 CERROR("no journal callback kernel patch, faking it...\n");
237 next = jiffies + 300 * HZ;
240 cb_func(obd, last_rcvd, 0);
246 static int fsfilt_ext3_journal_data(struct file *filp)
248 struct inode *inode = filp->f_dentry->d_inode;
250 EXT3_I(inode)->i_flags |= EXT3_JOURNAL_DATA_FL;
256 * We need to hack the return value for the free inode counts because
257 * the current EA code requires one filesystem block per inode with EAs,
258 * so it is possible to run out of blocks before we run out of inodes.
260 * This can be removed when the ext3 EA code is fixed.
262 static int fsfilt_ext3_statfs(struct super_block *sb, struct statfs *sfs)
264 int rc = vfs_statfs(sb, sfs);
266 if (!rc && sfs->f_bfree < sfs->f_ffree)
267 sfs->f_ffree = sfs->f_bfree;
272 static struct fsfilt_operations fsfilt_ext3_ops = {
274 fs_owner: THIS_MODULE,
275 fs_start: fsfilt_ext3_start,
276 fs_commit: fsfilt_ext3_commit,
277 fs_setattr: fsfilt_ext3_setattr,
278 fs_set_md: fsfilt_ext3_set_md,
279 fs_get_md: fsfilt_ext3_get_md,
280 fs_readpage: fsfilt_ext3_readpage,
281 fs_journal_data: fsfilt_ext3_journal_data,
282 fs_set_last_rcvd: fsfilt_ext3_set_last_rcvd,
283 fs_statfs: fsfilt_ext3_statfs,
286 static int __init fsfilt_ext3_init(void)
290 //rc = ext3_xattr_register();
291 fcb_cache = kmem_cache_create("fsfilt_ext3_fcb",
292 sizeof(struct fsfilt_cb_data), 0,
295 CERROR("error allocating fsfilt journal callback cache\n");
296 GOTO(out, rc = -ENOMEM);
299 rc = fsfilt_register_ops(&fsfilt_ext3_fs_ops);
302 kmem_cache_destroy(fcb_cache);
307 static void __exit fsfilt_ext3_exit(void)
311 fsfilt_unregister_ops(&fsfilt_ext3_fs_ops);
312 rc = kmem_cache_destroy(fcb_cache);
314 if (rc || fcb_cache_count) {
315 CERROR("can't free fsfilt callback cache: count %d, rc = %d\n",
316 fcb_cache_count, rc);
319 //rc = ext3_xattr_unregister();
322 MODULE_AUTHOR("Cluster File Systems, Inc. <info@clusterfs.com>");
323 MODULE_DESCRIPTION("Lustre ext3 Filesystem Helper v0.1");
324 MODULE_LICENSE("GPL");
326 module_init(fsfilt_ext3_init);
327 module_exit(fsfilt_ext3_exit);