1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
6 * Lustre Metadata Server (mds) journal abstraction routines
8 * Copyright (C) 2002 Cluster File Systems, Inc.
9 * author: Andreas Dilger <adilger@clusterfs.com>
11 * This code is issued under the GNU General Public License.
12 * See the file COPYING in this distribution
16 #define DEBUG_SUBSYSTEM S_MDS
19 #include <linux/jbd.h>
20 #include <linux/ext3_fs.h>
21 #include <linux/ext3_jbd.h>
22 #include <linux/lustre_mds.h>
23 #include <linux/module.h>
25 static struct mds_fs_operations mds_ext3_fs_ops;
26 static kmem_cache_t *jcb_cache;
27 static int jcb_cache_count;
30 struct journal_callback cb_jcb;
31 struct mds_obd *cb_mds;
36 * We don't currently need any additional blocks for rmdir and
37 * unlink transactions because we are storing the OST oa_id inside
38 * the inode (which we will be changing anyways as part of this
41 static void *mds_ext3_start(struct inode *inode, int op)
43 /* For updates to the last recieved file */
44 int nblocks = EXT3_DATA_TRANS_BLOCKS;
49 nblocks += EXT3_DELETE_TRANS_BLOCKS;
52 /* We may be modifying two directories */
53 nblocks += EXT3_DATA_TRANS_BLOCKS;
54 case MDS_FSOP_SYMLINK:
55 /* Possible new block + block bitmap + GDT for long symlink */
60 /* New inode + block bitmap + GDT for new file */
63 /* Change parent directory */
64 nblocks += EXT3_DATA_TRANS_BLOCKS;
66 case MDS_FSOP_SETATTR:
67 /* Setattr on inode */
70 default: CERROR("unknown transaction start op %d\n", op);
74 return journal_start(EXT3_JOURNAL(inode), nblocks);
77 static int mds_ext3_commit(struct inode *inode, void *handle)
79 return journal_stop((handle_t *)handle);
82 static int mds_ext3_setattr(struct dentry *dentry, void *handle,
85 struct inode *inode = dentry->d_inode;
87 /* a _really_ horrible hack to avoid removing the data stored
88 in the block pointers; this data is the object id
89 this will go into an extended attribute at some point.
91 if (iattr->ia_valid & ATTR_SIZE) {
92 /* ATTR_SIZE would invoke truncate: clear it */
93 iattr->ia_valid &= ~ATTR_SIZE;
94 inode->i_size = iattr->ia_size;
96 /* an _even_more_ horrible hack to make this hack work with
97 * ext3. This is because ext3 keeps a separate inode size
98 * until the inode is committed to ensure consistency. This
99 * will also go away with the move to EAs.
101 EXT3_I(inode)->i_disksize = inode->i_size;
103 /* make sure _something_ gets set - so new inode
104 goes to disk (probably won't work over XFS */
105 if (!iattr->ia_valid & ATTR_MODE) {
106 iattr->ia_valid |= ATTR_MODE;
107 iattr->ia_mode = inode->i_mode;
111 if (inode->i_op->setattr)
112 return inode->i_op->setattr(dentry, iattr);
114 return inode_setattr(inode, iattr);
118 * FIXME: nasty hack - store the object id in the first two
119 * direct block spots. This should be done with EAs...
120 * Note also that this does not currently mark the inode
121 * dirty (it currently is used with other operations that
122 * subsequently also mark the inode dirty).
124 static int mds_ext3_set_objid(struct inode *inode, void *handle, obd_id id)
126 (__u64)EXT3_I(inode)->i_data[0] = cpu_to_le64(id);
130 static int mds_ext3_get_objid(struct inode *inode, obd_id *id)
132 *id = le64_to_cpu(EXT3_I(inode)->i_data[0]);
137 static ssize_t mds_ext3_readpage(struct file *file, char *buf, size_t count,
140 struct inode *inode = file->f_dentry->d_inode;
143 if (S_ISREG(inode->i_mode))
144 rc = file->f_op->read(file, buf, count, offset);
146 struct buffer_head *bh;
148 /* FIXME: this assumes the blocksize == count, but the calling
149 * function will detect this as an error for now */
150 bh = ext3_bread(NULL, inode,
151 *offset >> inode->i_sb->s_blocksize_bits,
155 memcpy(buf, bh->b_data, inode->i_blksize);
157 rc = inode->i_blksize;
164 static void mds_ext3_delete_inode(struct inode *inode)
166 if (S_ISREG(inode->i_mode)) {
167 void *handle = mds_ext3_start(inode, MDS_FSOP_UNLINK);
169 if (IS_ERR(handle)) {
170 CERROR("unable to start transaction");
174 if (mds_ext3_set_objid(inode, handle, 0))
175 CERROR("error clearing objid on %ld\n", inode->i_ino);
177 if (mds_ext3_fs_ops.cl_delete_inode)
178 mds_ext3_fs_ops.cl_delete_inode(inode);
180 if (mds_ext3_commit(inode, handle))
181 CERROR("error closing handle on %ld\n", inode->i_ino);
183 mds_ext3_fs_ops.cl_delete_inode(inode);
186 static void mds_ext3_callback_status(void *jcb, int error)
188 struct mds_cb_data *mcb = (struct mds_cb_data *)jcb;
190 CDEBUG(D_EXT2, "got callback for last_rcvd %Ld: rc = %d\n",
191 mcb->cb_last_rcvd, error);
192 if (!error && mcb->cb_last_rcvd > mcb->cb_mds->mds_last_committed)
193 mcb->cb_mds->mds_last_committed = mcb->cb_last_rcvd;
195 kmem_cache_free(jcb_cache, mcb);
196 //OBD_FREE(mcb, sizeof(*mcb));
200 #ifdef HAVE_JOURNAL_CALLBACK
201 static void mds_ext3_callback_func(void *cb_data)
203 mds_ext3_callback_status(cb_data, 0);
207 static int mds_ext3_set_last_rcvd(struct mds_obd *mds, void *handle)
209 struct mds_cb_data *mcb;
211 //OBD_ALLOC(mcb, sizeof(*mcb));
212 mcb = kmem_cache_alloc(jcb_cache, GFP_NOFS);
218 mcb->cb_last_rcvd = mds->mds_last_rcvd;
220 #ifdef HAVE_JOURNAL_CALLBACK_STATUS
221 CDEBUG(D_EXT2, "set callback for last_rcvd: %Ld\n",
222 (unsigned long long)mcb->cb_last_rcvd);
223 journal_callback_set(handle, mds_ext3_callback_status,
225 #elif defined(HAVE_JOURNAL_CALLBACK)
226 /* XXX original patch version - remove soon */
227 #warning "using old journal callback kernel patch, please update"
228 CDEBUG(D_EXT2, "set callback for last_rcvd: %Ld\n",
229 (unsigned long long)mcb->cb_last_rcvd);
230 journal_callback_set(handle, mds_ext3_callback_func, mcb);
232 #warning "no journal callback kernel patch, faking it..."
234 static long next = 0;
236 if (time_after(jiffies, next)) {
237 CERROR("no journal callback kernel patch, faking it...\n");
238 next = jiffies + 300 * HZ;
241 mds_ext3_callback_status((struct journal_callback *)mcb, 0);
247 static int mds_ext3_journal_data(struct file *filp)
249 struct inode *inode = filp->f_dentry->d_inode;
251 EXT3_I(inode)->i_flags |= EXT3_JOURNAL_DATA_FL;
256 static struct mds_fs_operations mds_ext3_fs_ops = {
257 fs_start: mds_ext3_start,
258 fs_commit: mds_ext3_commit,
259 fs_setattr: mds_ext3_setattr,
260 fs_set_objid: mds_ext3_set_objid,
261 fs_get_objid: mds_ext3_get_objid,
262 fs_readpage: mds_ext3_readpage,
263 fs_delete_inode:mds_ext3_delete_inode,
264 cl_delete_inode:clear_inode,
265 fs_journal_data:mds_ext3_journal_data,
266 fs_set_last_rcvd:mds_ext3_set_last_rcvd,
269 static int __init mds_ext3_init(void)
273 jcb_cache = kmem_cache_create("mds_ext3_jcb",
274 sizeof(struct mds_cb_data), 0,
277 CERROR("error allocating MDS journal callback cache\n");
278 GOTO(out, rc = -ENOMEM);
281 rc = mds_register_fs_type(&mds_ext3_fs_ops, "ext3");
284 kmem_cache_destroy(jcb_cache);
289 static void __exit mds_ext3_exit(void)
293 mds_unregister_fs_type("ext3");
294 rc = kmem_cache_destroy(jcb_cache);
296 if (rc || jcb_cache_count) {
297 CERROR("can't free MDS callback cache: count %d, rc = %d\n",
298 jcb_cache_count, rc);
302 MODULE_AUTHOR("Cluster File Systems, Inc. <adilger@clusterfs.com>");
303 MODULE_DESCRIPTION("Lustre MDS ext3 Filesystem Helper v0.1");
304 MODULE_LICENSE("GPL");
306 module_init(mds_ext3_init);
307 module_exit(mds_ext3_exit);