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/slab.h>
31 #include <linux/extN_fs.h>
32 #include <linux/extN_jbd.h>
33 #include <linux/extN_xattr.h>
34 #include <linux/kp30.h>
35 #include <linux/lustre_mds.h>
36 #include <linux/obd.h>
37 #include <linux/module.h>
38 #include <linux/obd_lov.h>
40 static struct mds_fs_operations mds_extN_fs_ops;
41 static kmem_cache_t *mcb_cache;
42 static int mcb_cache_count;
45 struct journal_callback cb_jcb;
46 struct mds_obd *cb_mds;
50 #define EXTN_XATTR_INDEX_LUSTRE 5
51 #define XATTR_LUSTRE_MDS_OBJID "system.lustre_mds_objid"
53 #define XATTR_MDS_MO_MAGIC 0xEA0BD047
56 * We don't currently need any additional blocks for rmdir and
57 * unlink transactions because we are storing the OST oa_id inside
58 * the inode (which we will be changing anyways as part of this
61 static void *mds_extN_start(struct inode *inode, int op)
63 /* For updates to the last recieved file */
64 int nblocks = EXTN_DATA_TRANS_BLOCKS;
70 nblocks += EXTN_DELETE_TRANS_BLOCKS;
73 /* We may be modifying two directories */
74 nblocks += EXTN_DATA_TRANS_BLOCKS;
75 case MDS_FSOP_SYMLINK:
76 /* Possible new block + block bitmap + GDT for long symlink */
81 /* New inode + block bitmap + GDT for new file */
84 /* Change parent directory */
85 nblocks += EXTN_INDEX_EXTRA_TRANS_BLOCKS+EXTN_DATA_TRANS_BLOCKS;
87 case MDS_FSOP_SETATTR:
88 /* Setattr on inode */
91 default: CERROR("unknown transaction start op %d\n", op);
96 handle = journal_start(EXTN_JOURNAL(inode), nblocks);
102 static int mds_extN_commit(struct inode *inode, void *handle)
107 rc = journal_stop((handle_t *)handle);
113 static int mds_extN_setattr(struct dentry *dentry, void *handle,
116 struct inode *inode = dentry->d_inode;
120 if (inode->i_op->setattr)
121 rc = inode->i_op->setattr(dentry, iattr);
123 rc = inode_setattr(inode, iattr);
130 static int mds_extN_set_md(struct inode *inode, void *handle,
131 struct lov_mds_md *lmm)
137 rc = extN_xattr_set(handle, inode, EXTN_XATTR_INDEX_LUSTRE,
138 XATTR_LUSTRE_MDS_OBJID, lmm,
139 lmm ? lmm->lmm_easize : 0, 0);
144 CERROR("error adding objectid "LPX64" to inode %ld: %d\n",
145 lmm->lmm_object_id, inode->i_ino, rc);
146 if (rc != -ENOSPC) LBUG();
151 static int mds_extN_get_md(struct inode *inode, struct lov_mds_md *lmm)
154 int size = lmm->lmm_easize;
158 rc = extN_xattr_get(inode, EXTN_XATTR_INDEX_LUSTRE,
159 XATTR_LUSTRE_MDS_OBJID, lmm, size);
163 /* This gives us the MD size */
168 CDEBUG(D_INFO, "error getting EA %s from MDS inode %ld: "
169 "rc = %d\n", XATTR_LUSTRE_MDS_OBJID, inode->i_ino, rc);
170 memset(lmm, 0, size);
174 /* This field is byteswapped because it appears in the
175 * catalogue. All others are opaque to the MDS */
176 lmm->lmm_object_id = le64_to_cpu(lmm->lmm_object_id);
181 static ssize_t mds_extN_readpage(struct file *file, char *buf, size_t count,
184 struct inode *inode = file->f_dentry->d_inode;
187 if (S_ISREG(inode->i_mode))
188 rc = file->f_op->read(file, buf, count, offset);
190 struct buffer_head *bh;
192 /* FIXME: this assumes the blocksize == count, but the calling
193 * function will detect this as an error for now */
194 bh = extN_bread(NULL, inode,
195 *offset >> inode->i_sb->s_blocksize_bits,
199 memcpy(buf, bh->b_data, inode->i_blksize);
201 rc = inode->i_blksize;
208 static void mds_extN_delete_inode(struct inode *inode)
210 if (S_ISREG(inode->i_mode)) {
211 void *handle = mds_extN_start(inode, MDS_FSOP_UNLINK);
213 if (IS_ERR(handle)) {
214 CERROR("unable to start transaction");
218 if (mds_extN_set_md(inode, handle, NULL))
219 CERROR("error clearing objid on %ld\n", inode->i_ino);
221 if (mds_extN_fs_ops.cl_delete_inode)
222 mds_extN_fs_ops.cl_delete_inode(inode);
224 if (mds_extN_commit(inode, handle))
225 CERROR("error closing handle on %ld\n", inode->i_ino);
227 mds_extN_fs_ops.cl_delete_inode(inode);
230 static void mds_extN_callback_status(struct journal_callback *jcb, int error)
232 struct mds_cb_data *mcb = (struct mds_cb_data *)jcb;
234 CDEBUG(D_EXT2, "got callback for last_rcvd "LPD64": rc = %d\n",
235 mcb->cb_last_rcvd, error);
236 if (!error && mcb->cb_last_rcvd > mcb->cb_mds->mds_last_committed)
237 mcb->cb_mds->mds_last_committed = mcb->cb_last_rcvd;
239 kmem_cache_free(mcb_cache, mcb);
243 static int mds_extN_set_last_rcvd(struct mds_obd *mds, void *handle)
245 struct mds_cb_data *mcb;
247 mcb = kmem_cache_alloc(mcb_cache, GFP_NOFS);
253 mcb->cb_last_rcvd = mds->mds_last_rcvd;
255 #ifdef HAVE_JOURNAL_CALLBACK_STATUS
256 CDEBUG(D_EXT2, "set callback for last_rcvd: "LPD64"\n",
259 /* Note that an "incompatible pointer warning here is OK for now */
260 journal_callback_set(handle, mds_extN_callback_status,
261 (struct journal_callback *)mcb);
264 #warning "no journal callback kernel patch, faking it..."
266 static long next = 0;
268 if (time_after(jiffies, next)) {
269 CERROR("no journal callback kernel patch, faking it...\n");
270 next = jiffies + 300 * HZ;
273 mds_extN_callback_status((struct journal_callback *)mcb, 0);
279 static int mds_extN_journal_data(struct file *filp)
281 struct inode *inode = filp->f_dentry->d_inode;
283 EXTN_I(inode)->i_flags |= EXTN_JOURNAL_DATA_FL;
289 * We need to hack the return value for the free inode counts because
290 * the current EA code requires one filesystem block per inode with EAs,
291 * so it is possible to run out of blocks before we run out of inodes.
293 * This can be removed when the extN EA code is fixed.
295 static int mds_extN_statfs(struct super_block *sb, struct statfs *sfs)
297 int rc = vfs_statfs(sb, sfs);
299 if (!rc && sfs->f_bfree < sfs->f_ffree)
300 sfs->f_ffree = sfs->f_bfree;
305 static struct mds_fs_operations mds_extN_fs_ops = {
306 fs_owner: THIS_MODULE,
307 fs_start: mds_extN_start,
308 fs_commit: mds_extN_commit,
309 fs_setattr: mds_extN_setattr,
310 fs_set_md: mds_extN_set_md,
311 fs_get_md: mds_extN_get_md,
312 fs_readpage: mds_extN_readpage,
313 fs_delete_inode: mds_extN_delete_inode,
314 cl_delete_inode: clear_inode,
315 fs_journal_data: mds_extN_journal_data,
316 fs_set_last_rcvd: mds_extN_set_last_rcvd,
317 fs_statfs: mds_extN_statfs,
320 static int __init mds_extN_init(void)
324 //rc = extN_xattr_register();
325 mcb_cache = kmem_cache_create("mds_extN_mcb",
326 sizeof(struct mds_cb_data), 0,
329 CERROR("error allocating MDS journal callback cache\n");
330 GOTO(out, rc = -ENOMEM);
333 rc = mds_register_fs_type(&mds_extN_fs_ops, "extN");
336 kmem_cache_destroy(mcb_cache);
341 static void __exit mds_extN_exit(void)
345 mds_unregister_fs_type("extN");
346 rc = kmem_cache_destroy(mcb_cache);
348 if (rc || mcb_cache_count) {
349 CERROR("can't free MDS callback cache: count %d, rc = %d\n",
350 mcb_cache_count, rc);
353 //rc = extN_xattr_unregister();
356 MODULE_AUTHOR("Cluster File Systems, Inc. <info@clusterfs.com>");
357 MODULE_DESCRIPTION("Lustre MDS extN Filesystem Helper v0.1");
358 MODULE_LICENSE("GPL");
360 module_init(mds_extN_init);
361 module_exit(mds_extN_exit);