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/extN_fs.h>
21 #include <linux/extN_jbd.h>
22 #include <linux/extN_xattr.h>
23 #include <linux/lustre_mds.h>
24 #include <linux/module.h>
25 #include <linux/obd_lov.h>
27 static struct mds_fs_operations mds_extN_fs_ops;
28 static kmem_cache_t *jcb_cache;
29 static int jcb_cache_count;
32 struct journal_callback cb_jcb;
33 struct mds_obd *cb_mds;
39 struct lov_md mo_lov_md;
42 #define EXTN_XATTR_INDEX_LUSTRE 5
43 #define XATTR_LUSTRE_MDS_OBJID "system.lustre_mds_objid"
45 #define XATTR_MDS_MO_MAGIC 0x4711
48 * We don't currently need any additional blocks for rmdir and
49 * unlink transactions because we are storing the OST oa_id inside
50 * the inode (which we will be changing anyways as part of this
53 static void *mds_extN_start(struct inode *inode, int op)
55 /* For updates to the last recieved file */
56 int nblocks = EXTN_DATA_TRANS_BLOCKS;
61 nblocks += EXTN_DELETE_TRANS_BLOCKS;
64 /* We may be modifying two directories */
65 nblocks += EXTN_DATA_TRANS_BLOCKS;
66 case MDS_FSOP_SYMLINK:
67 /* Possible new block + block bitmap + GDT for long symlink */
72 /* New inode + block bitmap + GDT for new file */
75 /* Change parent directory */
76 nblocks += EXTN_INDEX_EXTRA_TRANS_BLOCKS+EXTN_DATA_TRANS_BLOCKS;
78 case MDS_FSOP_SETATTR:
79 /* Setattr on inode */
82 default: CERROR("unknown transaction start op %d\n", op);
86 return journal_start(EXTN_JOURNAL(inode), nblocks);
89 static int mds_extN_commit(struct inode *inode, void *handle)
91 return journal_stop((handle_t *)handle);
94 static int mds_extN_setattr(struct dentry *dentry, void *handle,
97 struct inode *inode = dentry->d_inode;
99 if (inode->i_op->setattr)
100 return inode->i_op->setattr(dentry, iattr);
102 return inode_setattr(inode, iattr);
105 static int mds_extN_set_obdo(struct inode *inode, void *handle,
108 struct mds_objid *data = (struct mds_objid *)obdo->o_inline;
111 data->mo_magic = cpu_to_le64(XATTR_MDS_MO_MAGIC);
116 rc = extN_xattr_set(handle, inode, EXTN_XATTR_INDEX_LUSTRE,
117 XATTR_LUSTRE_MDS_OBJID, NULL, 0, 0);
119 rc = extN_xattr_set(handle, inode, EXTN_XATTR_INDEX_LUSTRE,
120 XATTR_LUSTRE_MDS_OBJID, obdo->o_inline,
121 OBD_INLINESZ, XATTR_CREATE);
126 CERROR("error adding objectid %Ld to inode %ld\n",
127 (unsigned long long)obdo->o_id, inode->i_ino);
131 static int mds_extN_get_obdo(struct inode *inode, struct obdo *obdo)
134 struct mds_objid data;
135 struct lov_object_id *lov_ids;
140 rc = extN_xattr_get(inode, EXTN_XATTR_INDEX_LUSTRE,
141 XATTR_LUSTRE_MDS_OBJID, &data,
142 sizeof(struct mds_objid));
143 size = sizeof(struct mds_objid) + data.mo_lov_md.lmd_stripe_count *
145 OBD_ALLOC(buf, size);
148 rc = extN_xattr_get(inode, EXTN_XATTR_INDEX_LUSTRE,
149 XATTR_LUSTRE_MDS_OBJID, buf, size);
153 if (size > OBD_INLINESZ)
157 CERROR("error getting EA %s from MDS inode %ld: rc = %d\n",
158 XATTR_LUSTRE_MDS_OBJID, inode->i_ino, rc);
160 } else if (data.mo_magic != cpu_to_le64(XATTR_MDS_MO_MAGIC)) {
161 CERROR("MDS object id %Ld has bad magic %Lx\n",
162 (unsigned long long)obdo->o_id,
163 (unsigned long long)le64_to_cpu(data.mo_magic));
166 /* This field is byteswapped because it appears in the
167 * catalogue. All others are opaque to the MDS */
168 obdo->o_id = le64_to_cpu(data.mo_lov_md.lmd_object_id);
169 memcpy(obdo->o_inline, buf + sizeof(data), size);
172 #warning FIXME: pass this buffer to caller for transmission when size exceeds OBD_INLINESZ
177 static ssize_t mds_extN_readpage(struct file *file, char *buf, size_t count,
180 struct inode *inode = file->f_dentry->d_inode;
183 if (S_ISREG(inode->i_mode))
184 rc = file->f_op->read(file, buf, count, offset);
186 struct buffer_head *bh;
188 /* FIXME: this assumes the blocksize == count, but the calling
189 * function will detect this as an error for now */
190 bh = extN_bread(NULL, inode,
191 *offset >> inode->i_sb->s_blocksize_bits,
195 memcpy(buf, bh->b_data, inode->i_blksize);
197 rc = inode->i_blksize;
204 static void mds_extN_delete_inode(struct inode *inode)
206 if (S_ISREG(inode->i_mode)) {
207 void *handle = mds_extN_start(inode, MDS_FSOP_UNLINK);
209 if (IS_ERR(handle)) {
210 CERROR("unable to start transaction");
214 if (mds_extN_set_obdo(inode, handle, NULL))
215 CERROR("error clearing obdo on %ld\n", inode->i_ino);
217 if (mds_extN_fs_ops.cl_delete_inode)
218 mds_extN_fs_ops.cl_delete_inode(inode);
220 if (mds_extN_commit(inode, handle))
221 CERROR("error closing handle on %ld\n", inode->i_ino);
223 mds_extN_fs_ops.cl_delete_inode(inode);
226 static void mds_extN_callback_status(void *jcb, int error)
228 struct mds_cb_data *mcb = (struct mds_cb_data *)jcb;
230 CDEBUG(D_EXT2, "got callback for last_rcvd %Ld: rc = %d\n",
231 mcb->cb_last_rcvd, error);
232 if (!error && mcb->cb_last_rcvd > mcb->cb_mds->mds_last_committed)
233 mcb->cb_mds->mds_last_committed = mcb->cb_last_rcvd;
235 kmem_cache_free(jcb_cache, jcb);
239 #ifdef HAVE_JOURNAL_CALLBACK
240 static void mds_extN_callback_func(void *cb_data)
242 mds_extN_callback_status(cb_data, 0);
246 static int mds_extN_set_last_rcvd(struct mds_obd *mds, void *handle)
248 struct mds_cb_data *mcb;
250 mcb = kmem_cache_alloc(jcb_cache, GFP_NOFS);
256 mcb->cb_last_rcvd = mds->mds_last_rcvd;
258 #ifdef HAVE_JOURNAL_CALLBACK_STATUS
259 CDEBUG(D_EXT2, "set callback for last_rcvd: %Ld\n",
260 (unsigned long long)mcb->cb_last_rcvd);
261 journal_callback_set(handle, mds_extN_callback_status,
263 #elif defined(HAVE_JOURNAL_CALLBACK)
264 /* XXX original patch version - remove soon */
265 #warning "using old journal callback kernel patch, please update"
266 CDEBUG(D_EXT2, "set callback for last_rcvd: %Ld\n",
267 (unsigned long long)mcb->cb_last_rcvd);
268 journal_callback_set(handle, mds_extN_callback_func, mcb);
270 #warning "no journal callback kernel patch, faking it..."
272 static long next = 0;
274 if (time_after(jiffies, next)) {
275 CERROR("no journal callback kernel patch, faking it...\n");
276 next = jiffies + 300 * HZ;
279 mds_extN_callback_status((struct journal_callback *)mcb, 0);
285 static int mds_extN_journal_data(struct file *filp)
287 struct inode *inode = filp->f_dentry->d_inode;
289 EXTN_I(inode)->i_flags |= EXTN_JOURNAL_DATA_FL;
294 static struct mds_fs_operations mds_extN_fs_ops = {
295 fs_start: mds_extN_start,
296 fs_commit: mds_extN_commit,
297 fs_setattr: mds_extN_setattr,
298 fs_set_obdo: mds_extN_set_obdo,
299 fs_get_obdo: mds_extN_get_obdo,
300 fs_readpage: mds_extN_readpage,
301 fs_delete_inode: mds_extN_delete_inode,
302 cl_delete_inode: clear_inode,
303 fs_journal_data: mds_extN_journal_data,
304 fs_set_last_rcvd: mds_extN_set_last_rcvd,
307 static int __init mds_extN_init(void)
311 //rc = extN_xattr_register();
312 jcb_cache = kmem_cache_create("mds_extN_jcb",
313 sizeof(struct mds_cb_data), 0,
316 CERROR("error allocating MDS journal callback cache\n");
317 GOTO(out, rc = -ENOMEM);
319 rc = mds_register_fs_type(&mds_extN_fs_ops, "extN");
322 kmem_cache_destroy(jcb_cache);
327 static void __exit mds_extN_exit(void)
331 mds_unregister_fs_type("extN");
332 rc = kmem_cache_destroy(jcb_cache);
334 if (rc || jcb_cache_count) {
335 CERROR("can't free MDS callback cache: count %d, rc = %d\n",
336 jcb_cache_count, rc);
339 //rc = extN_xattr_unregister();
342 MODULE_AUTHOR("Cluster File Systems, Inc. <adilger@clusterfs.com>");
343 MODULE_DESCRIPTION("Lustre MDS extN Filesystem Helper v0.1");
344 MODULE_LICENSE("GPL");
346 module_init(mds_extN_init);
347 module_exit(mds_extN_exit);