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>
25 struct mds_fs_operations mds_extN_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;
42 #define EXTN_XATTR_INDEX_LUSTRE 5
43 #define XATTR_LUSTRE_MDS_OBJID "system.lustre_mds_objid"
45 #define XATTR_MDS_MO_MAGIC 0x4711
47 int mds_extN_init(struct mds_obd *mds)
52 * Replace the client filesystem delete_inode method with our own,
53 * so that we can clear the object ID before the inode is deleted.
54 * The fs_delete_inode method will call cl_delete_inode for us.
56 * We need to do this for the MDS superblock only, hence we install
57 * a modified copy of the original superblock method table.
59 * We still assume that there is only a single MDS client filesystem
60 * type, as we don't have access to the mds struct in delete_inode
61 * and store the client delete_inode method in a global table. This
62 * will only become a problem when multiple MDSs are running on a
63 * single host with different client filesystems.
65 OBD_ALLOC(mds->mds_sop, sizeof(*mds->mds_sop));
67 GOTO(out, rc = -ENOMEM);
69 memcpy(mds->mds_sop, mds->mds_sb->s_op, sizeof(*mds->mds_sop));
70 mds_extN_fs_ops.cl_delete_inode = mds->mds_sop->delete_inode;
71 mds->mds_sop->delete_inode = mds_extN_fs_ops.fs_delete_inode;
72 mds->mds_sb->s_op = mds->mds_sop;
74 //rc = extN_xattr_register();
75 jcb_cache = kmem_cache_create("mds_extN_jcb",
76 sizeof(struct mds_cb_data), 0,
77 SLAB_POISON, NULL, NULL);
79 CERROR("error allocating MDS journal callback cache\n");
80 GOTO(out_sop, rc = -ENOMEM);
86 OBD_FREE(mds->mds_sop, sizeof(*mds->mds_sop));
91 int mds_extN_exit(struct mds_obd *mds)
95 rc = kmem_cache_destroy(jcb_cache);
97 if (rc || jcb_cache_count) {
98 CERROR("can't free MDS callback cache: count %d, rc = %d\n",
102 //rc = extN_xattr_unregister();
103 OBD_FREE(mds->mds_sop, sizeof(*mds->mds_sop));
108 * We don't currently need any additional blocks for rmdir and
109 * unlink transactions because we are storing the OST oa_id inside
110 * the inode (which we will be changing anyways as part of this
113 static void *mds_extN_start(struct inode *inode, int op)
115 /* For updates to the last recieved file */
116 int nblocks = EXTN_DATA_TRANS_BLOCKS;
120 case MDS_FSOP_UNLINK:
121 nblocks += EXTN_DELETE_TRANS_BLOCKS;
123 case MDS_FSOP_RENAME:
124 /* We may be modifying two directories */
125 nblocks += EXTN_DATA_TRANS_BLOCKS;
126 case MDS_FSOP_SYMLINK:
127 /* Possible new block + block bitmap + GDT for long symlink */
129 case MDS_FSOP_CREATE:
132 /* New inode + block bitmap + GDT for new file */
135 /* Change parent directory */
136 nblocks += EXTN_INDEX_EXTRA_TRANS_BLOCKS+EXTN_DATA_TRANS_BLOCKS;
138 case MDS_FSOP_SETATTR:
139 /* Setattr on inode */
142 default: CERROR("unknown transaction start op %d\n", op);
146 return journal_start(EXTN_JOURNAL(inode), nblocks);
149 static int mds_extN_commit(struct inode *inode, void *handle)
151 return journal_stop((handle_t *)handle);
154 static int mds_extN_setattr(struct dentry *dentry, void *handle,
157 struct inode *inode = dentry->d_inode;
159 if (inode->i_op->setattr)
160 return inode->i_op->setattr(dentry, iattr);
162 return inode_setattr(inode, iattr);
165 static int mds_extN_set_objid(struct inode *inode, void *handle, obd_id id)
167 struct mds_objid data;
170 data.mo_magic = cpu_to_le16(XATTR_MDS_MO_MAGIC);
172 data.mo_ost = 0; /* FIXME: store OST index here */
173 data.mo_id = cpu_to_le64(id);
178 rc = extN_xattr_set(handle, inode, EXTN_XATTR_INDEX_LUSTRE,
179 XATTR_LUSTRE_MDS_OBJID, NULL, 0, 0);
181 rc = extN_xattr_set(handle, inode, EXTN_XATTR_INDEX_LUSTRE,
182 XATTR_LUSTRE_MDS_OBJID, &data,
183 sizeof(struct mds_objid), XATTR_CREATE);
189 CERROR("error adding objectid %Ld to inode %ld\n",
190 (unsigned long long)id, inode->i_ino);
194 static int mds_extN_get_objid(struct inode *inode, obd_id *id)
196 struct mds_objid data;
201 rc = extN_xattr_get(inode, EXTN_XATTR_INDEX_LUSTRE,
202 XATTR_LUSTRE_MDS_OBJID, &data,
203 sizeof(struct mds_objid));
208 CERROR("error getting EA %s from MDS inode %ld: rc = %d\n",
209 XATTR_LUSTRE_MDS_OBJID, inode->i_ino, rc);
211 } else if (data.mo_magic != cpu_to_le16(XATTR_MDS_MO_MAGIC)) {
212 CERROR("MDS object id %Ld has bad magic %x\n",
213 (unsigned long long)le64_to_cpu(data.mo_id),
214 le16_to_cpu(data.mo_magic));
217 *id = le64_to_cpu(data.mo_id);
218 /* FIXME: will actually use data.mo_ost at some point */
220 CERROR("MDS objid %Ld with ost index %d!\n",
227 static ssize_t mds_extN_readpage(struct file *file, char *buf, size_t count,
230 struct inode *inode = file->f_dentry->d_inode;
233 if (S_ISREG(inode->i_mode))
234 rc = file->f_op->read(file, buf, count, offset);
236 struct buffer_head *bh;
238 /* FIXME: this assumes the blocksize == count, but the calling
239 * function will detect this as an error for now */
240 bh = extN_bread(NULL, inode,
241 *offset >> inode->i_sb->s_blocksize_bits,
245 memcpy(buf, bh->b_data, inode->i_blksize);
247 rc = inode->i_blksize;
254 static void mds_extN_delete_inode(struct inode *inode)
256 if (S_ISREG(inode->i_mode)) {
257 void *handle = mds_extN_start(inode, MDS_FSOP_UNLINK);
259 if (IS_ERR(handle)) {
260 CERROR("unable to start transaction");
264 if (mds_extN_set_objid(inode, handle, 0))
265 CERROR("error clearing objid on %ld\n", inode->i_ino);
267 if (mds_extN_fs_ops.cl_delete_inode)
268 mds_extN_fs_ops.cl_delete_inode(inode);
270 if (mds_extN_commit(inode, handle))
271 CERROR("error closing handle on %ld\n", inode->i_ino);
273 mds_extN_fs_ops.cl_delete_inode(inode);
276 static void mds_extN_callback_status(struct journal_callback *jcb, int error)
278 struct mds_cb_data *mcb = (struct mds_cb_data *)jcb;
280 CDEBUG(D_EXT2, "got callback for last_rcvd %Ld: rc = %d\n",
281 mcb->cb_last_rcvd, error);
282 if (!error && mcb->cb_last_rcvd > mcb->cb_mds->mds_last_committed)
283 mcb->cb_mds->mds_last_committed = mcb->cb_last_rcvd;
285 kmem_cache_free(jcb_cache, jcb);
289 #ifdef HAVE_JOURNAL_CALLBACK
290 static void mds_extN_callback_func(void *cb_data)
292 mds_extN_callback_status(cb_data, 0);
296 static int mds_extN_set_last_rcvd(struct mds_obd *mds, void *handle)
298 struct mds_cb_data *mcb;
300 mcb = kmem_cache_alloc(jcb_cache, GFP_NOFS);
306 mcb->cb_last_rcvd = mds->mds_last_rcvd;
308 #ifdef HAVE_JOURNAL_CALLBACK_STATUS
309 CDEBUG(D_EXT2, "set callback for last_rcvd: %Ld\n",
310 (unsigned long long)mcb->cb_last_rcvd);
311 journal_callback_set(handle, mds_extN_callback_status,
312 (struct journal_callback *)mcb);
313 #elif HAVE_JOURNAL_CALLBACK /* XXX original patch version - remove soon */
314 #warning "using old journal callback kernel patch, please update"
315 CDEBUG(D_EXT2, "set callback for last_rcvd: %Ld\n",
316 (unsigned long long)mcb->cb_last_rcvd);
317 journal_callback_set(handle, mds_extN_callback_func, mcb);
319 #warning "no journal callback kernel patch, faking it..."
321 static long next = 0;
323 if (time_after(jiffies, next)) {
324 CERROR("no journal callback kernel patch, faking it...\n");
325 next = jiffies + 300 * HZ;
328 mds_extN_callback_status((struct journal_callback *)mcb, 0);
334 static int mds_extN_journal_data(struct file *filp)
336 struct inode *inode = filp->f_dentry->d_inode;
338 EXTN_I(inode)->i_flags |= EXTN_JOURNAL_DATA_FL;
343 struct mds_fs_operations mds_extN_fs_ops = {
344 fs_init: mds_extN_init,
345 fs_exit: mds_extN_exit,
346 fs_start: mds_extN_start,
347 fs_commit: mds_extN_commit,
348 fs_setattr: mds_extN_setattr,
349 fs_set_objid: mds_extN_set_objid,
350 fs_get_objid: mds_extN_get_objid,
351 fs_readpage: mds_extN_readpage,
352 fs_delete_inode:mds_extN_delete_inode,
353 cl_delete_inode:clear_inode,
354 fs_journal_data:mds_extN_journal_data,
355 fs_set_last_rcvd:mds_extN_set_last_rcvd,