1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
4 * lustre/mds/mds_extN.c
5 * Lustre Metadata Server (mds) journal 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_MDS
29 #include <linux/jbd.h>
30 #include <linux/extN_fs.h>
31 #include <linux/extN_jbd.h>
32 #include <linux/extN_xattr.h>
33 #include <linux/lustre_mds.h>
34 #include <linux/module.h>
35 #include <linux/obd_lov.h>
37 static struct mds_fs_operations mds_extN_fs_ops;
38 static kmem_cache_t *jcb_cache;
39 static int jcb_cache_count;
42 struct journal_callback cb_jcb;
43 struct mds_obd *cb_mds;
47 #define EXTN_XATTR_INDEX_LUSTRE 5
48 #define XATTR_LUSTRE_MDS_OBJID "system.lustre_mds_objid"
50 #define XATTR_MDS_MO_MAGIC 0xEA0BD047
53 * We don't currently need any additional blocks for rmdir and
54 * unlink transactions because we are storing the OST oa_id inside
55 * the inode (which we will be changing anyways as part of this
58 static void *mds_extN_start(struct inode *inode, int op)
60 /* For updates to the last recieved file */
61 int nblocks = EXTN_DATA_TRANS_BLOCKS;
66 nblocks += EXTN_DELETE_TRANS_BLOCKS;
69 /* We may be modifying two directories */
70 nblocks += EXTN_DATA_TRANS_BLOCKS;
71 case MDS_FSOP_SYMLINK:
72 /* Possible new block + block bitmap + GDT for long symlink */
77 /* New inode + block bitmap + GDT for new file */
80 /* Change parent directory */
81 nblocks += EXTN_INDEX_EXTRA_TRANS_BLOCKS+EXTN_DATA_TRANS_BLOCKS;
83 case MDS_FSOP_SETATTR:
84 /* Setattr on inode */
87 default: CERROR("unknown transaction start op %d\n", op);
91 return journal_start(EXTN_JOURNAL(inode), nblocks);
94 static int mds_extN_commit(struct inode *inode, void *handle)
96 return journal_stop((handle_t *)handle);
99 /* Assumes BKL is held */
100 static int mds_extN_setattr(struct dentry *dentry, void *handle,
103 struct inode *inode = dentry->d_inode;
105 if (inode->i_op->setattr)
106 return inode->i_op->setattr(dentry, iattr);
108 return inode_setattr(inode, iattr);
111 static int mds_extN_set_md(struct inode *inode, void *handle,
112 struct lov_mds_md *md)
119 rc = extN_xattr_set(handle, inode, EXTN_XATTR_INDEX_LUSTRE,
120 XATTR_LUSTRE_MDS_OBJID, NULL, 0, 0);
122 md->lmd_magic = cpu_to_le32(XATTR_MDS_MO_MAGIC);
123 rc = extN_xattr_set(handle, inode, EXTN_XATTR_INDEX_LUSTRE,
124 XATTR_LUSTRE_MDS_OBJID, md,
125 md->lmd_easize, XATTR_CREATE);
131 CERROR("error adding objectid %Ld to inode %ld: %d\n",
132 (unsigned long long)md->lmd_object_id, inode->i_ino, rc);
138 static int mds_extN_get_md(struct inode *inode, struct lov_mds_md *md)
141 int size = md->lmd_easize;
145 rc = extN_xattr_get(inode, EXTN_XATTR_INDEX_LUSTRE,
146 XATTR_LUSTRE_MDS_OBJID, md, size);
151 CDEBUG(D_INFO, "error getting EA %s from MDS inode %ld: "
152 "rc = %d\n", XATTR_LUSTRE_MDS_OBJID, inode->i_ino, rc);
155 } else if (md == NULL)
158 if (md->lmd_magic != cpu_to_le32(XATTR_MDS_MO_MAGIC)) {
159 CERROR("MDS striping md for ino %ld has bad magic\n",
163 /* This field is byteswapped because it appears in the
164 * catalogue. All others are opaque to the MDS */
165 md->lmd_object_id = le64_to_cpu(md->lmd_object_id);
171 static ssize_t mds_extN_readpage(struct file *file, char *buf, size_t count,
174 struct inode *inode = file->f_dentry->d_inode;
177 if (S_ISREG(inode->i_mode))
178 rc = file->f_op->read(file, buf, count, offset);
180 struct buffer_head *bh;
182 /* FIXME: this assumes the blocksize == count, but the calling
183 * function will detect this as an error for now */
184 bh = extN_bread(NULL, inode,
185 *offset >> inode->i_sb->s_blocksize_bits,
189 memcpy(buf, bh->b_data, inode->i_blksize);
191 rc = inode->i_blksize;
198 static void mds_extN_delete_inode(struct inode *inode)
200 if (S_ISREG(inode->i_mode)) {
201 void *handle = mds_extN_start(inode, MDS_FSOP_UNLINK);
203 if (IS_ERR(handle)) {
204 CERROR("unable to start transaction");
208 if (mds_extN_set_md(inode, handle, NULL))
209 CERROR("error clearing obdo on %ld\n", inode->i_ino);
211 if (mds_extN_fs_ops.cl_delete_inode)
212 mds_extN_fs_ops.cl_delete_inode(inode);
214 if (mds_extN_commit(inode, handle))
215 CERROR("error closing handle on %ld\n", inode->i_ino);
217 mds_extN_fs_ops.cl_delete_inode(inode);
220 static void mds_extN_callback_status(void *jcb, int error)
222 struct mds_cb_data *mcb = (struct mds_cb_data *)jcb;
224 CDEBUG(D_EXT2, "got callback for last_rcvd %Ld: rc = %d\n",
225 mcb->cb_last_rcvd, error);
226 if (!error && mcb->cb_last_rcvd > mcb->cb_mds->mds_last_committed)
227 mcb->cb_mds->mds_last_committed = mcb->cb_last_rcvd;
229 kmem_cache_free(jcb_cache, jcb);
233 static int mds_extN_set_last_rcvd(struct mds_obd *mds, void *handle)
235 struct mds_cb_data *mcb;
237 mcb = kmem_cache_alloc(jcb_cache, GFP_NOFS);
243 mcb->cb_last_rcvd = mds->mds_last_rcvd;
245 #ifdef HAVE_JOURNAL_CALLBACK_STATUS
246 CDEBUG(D_EXT2, "set callback for last_rcvd: %Ld\n",
247 (unsigned long long)mcb->cb_last_rcvd);
248 journal_callback_set(handle, mds_extN_callback_status,
251 #warning "no journal callback kernel patch, faking it..."
253 static long next = 0;
255 if (time_after(jiffies, next)) {
256 CERROR("no journal callback kernel patch, faking it...\n");
257 next = jiffies + 300 * HZ;
260 mds_extN_callback_status((struct journal_callback *)mcb, 0);
266 static int mds_extN_journal_data(struct file *filp)
268 struct inode *inode = filp->f_dentry->d_inode;
270 EXTN_I(inode)->i_flags |= EXTN_JOURNAL_DATA_FL;
276 * We need to hack the return value for the free inode counts because
277 * the current EA code requires one filesystem block per inode with EAs,
278 * so it is possible to run out of blocks before we run out of inodes.
280 * This can be removed when the extN EA code is fixed.
282 static int mds_extN_statfs(struct super_block *sb, struct statfs *sfs)
284 int rc = vfs_statfs(sb, sfs);
286 if (!rc && sfs->f_bfree < sfs->f_ffree)
287 sfs->f_ffree = sfs->f_bfree;
292 static struct mds_fs_operations mds_extN_fs_ops = {
293 fs_owner: THIS_MODULE,
294 fs_start: mds_extN_start,
295 fs_commit: mds_extN_commit,
296 fs_setattr: mds_extN_setattr,
297 fs_set_md: mds_extN_set_md,
298 fs_get_md: mds_extN_get_md,
299 fs_readpage: mds_extN_readpage,
300 fs_delete_inode: mds_extN_delete_inode,
301 cl_delete_inode: clear_inode,
302 fs_journal_data: mds_extN_journal_data,
303 fs_set_last_rcvd: mds_extN_set_last_rcvd,
304 fs_statfs: mds_extN_statfs,
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. <info@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);