Whamcloud - gitweb
Remove the extra magic from mds_extN.c for now (we will get it back soon).
[fs/lustre-release.git] / lustre / mds / mds_extN.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  lustre/mds/mds_extN.c
5  *  Lustre Metadata Server (mds) journal abstraction routines
6  *
7  *  Copyright (c) 2002 Cluster File Systems, Inc.
8  *   Author: Andreas Dilger <adilger@clusterfs.com>
9  *
10  *   This file is part of Lustre, http://www.lustre.org.
11  *
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.
15  *
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.
20  *
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.
24  */
25
26 #define DEBUG_SUBSYSTEM S_MDS
27
28 #include <linux/fs.h>
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>
39
40 static struct mds_fs_operations mds_extN_fs_ops;
41 static kmem_cache_t *jcb_cache;
42 static int jcb_cache_count;
43
44 struct mds_cb_data {
45         struct journal_callback cb_jcb;
46         struct mds_obd *cb_mds;
47         __u64 cb_last_rcvd;
48 };
49
50 #define EXTN_XATTR_INDEX_LUSTRE         5
51 #define XATTR_LUSTRE_MDS_OBJID          "system.lustre_mds_objid"
52
53 #define XATTR_MDS_MO_MAGIC              0xEA0BD047
54
55 /*
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
59  * transaction).
60  */
61 static void *mds_extN_start(struct inode *inode, int op)
62 {
63         /* For updates to the last recieved file */
64         int nblocks = EXTN_DATA_TRANS_BLOCKS;
65
66         switch(op) {
67         case MDS_FSOP_RMDIR:
68         case MDS_FSOP_UNLINK:
69                 nblocks += EXTN_DELETE_TRANS_BLOCKS;
70                 break;
71         case MDS_FSOP_RENAME:
72                 /* We may be modifying two directories */
73                 nblocks += EXTN_DATA_TRANS_BLOCKS;
74         case MDS_FSOP_SYMLINK:
75                 /* Possible new block + block bitmap + GDT for long symlink */
76                 nblocks += 3;
77         case MDS_FSOP_CREATE:
78         case MDS_FSOP_MKDIR:
79         case MDS_FSOP_MKNOD:
80                 /* New inode + block bitmap + GDT for new file */
81                 nblocks += 3;
82         case MDS_FSOP_LINK:
83                 /* Change parent directory */
84                 nblocks += EXTN_INDEX_EXTRA_TRANS_BLOCKS+EXTN_DATA_TRANS_BLOCKS;
85                 break;
86         case MDS_FSOP_SETATTR:
87                 /* Setattr on inode */
88                 nblocks += 1;
89                 break;
90         default: CERROR("unknown transaction start op %d\n", op);
91                  LBUG();
92         }
93
94         return journal_start(EXTN_JOURNAL(inode), nblocks);
95 }
96
97 static int mds_extN_commit(struct inode *inode, void *handle)
98 {
99         return journal_stop((handle_t *)handle);
100 }
101
102 /* Assumes BKL is held */
103 static int mds_extN_setattr(struct dentry *dentry, void *handle,
104                             struct iattr *iattr)
105 {
106         struct inode *inode = dentry->d_inode;
107
108         if (inode->i_op->setattr)
109                 return inode->i_op->setattr(dentry, iattr);
110         else
111                 return inode_setattr(inode, iattr);
112 }
113
114 static int mds_extN_set_md(struct inode *inode, void *handle,
115                            struct lov_mds_md *lmm)
116 {
117         int rc;
118
119         down(&inode->i_sem);
120         lock_kernel();
121         if (lmm == NULL)
122                 rc = extN_xattr_set(handle, inode, EXTN_XATTR_INDEX_LUSTRE,
123                                     XATTR_LUSTRE_MDS_OBJID, NULL, 0, 0);
124         else {
125                 rc = extN_xattr_set(handle, inode, EXTN_XATTR_INDEX_LUSTRE,
126                                     XATTR_LUSTRE_MDS_OBJID, lmm,
127                                     lmm->lmm_easize, XATTR_CREATE);
128                 if (rc == -EEXIST)
129                         rc = extN_xattr_set(handle, inode,
130                                             EXTN_XATTR_INDEX_LUSTRE,
131                                             XATTR_LUSTRE_MDS_OBJID, lmm,
132                                             lmm->lmm_easize, 0);
133         }
134         unlock_kernel();
135         up(&inode->i_sem);
136
137         if (rc) {
138                 CERROR("error adding objectid "LPX64" to inode %ld: %d\n",
139                        lmm->lmm_object_id, inode->i_ino, rc);
140                 LBUG();
141         }
142         return rc;
143 }
144
145 static int mds_extN_get_md(struct inode *inode, struct lov_mds_md *lmm)
146 {
147         int rc;
148         int size = lmm->lmm_easize;
149
150         down(&inode->i_sem);
151         lock_kernel();
152         rc = extN_xattr_get(inode, EXTN_XATTR_INDEX_LUSTRE,
153                             XATTR_LUSTRE_MDS_OBJID, lmm, size);
154         unlock_kernel();
155         up(&inode->i_sem);
156
157         /* This gives us the MD size */
158         if (lmm == NULL)
159                 return rc;
160
161         if (rc < 0) {
162                 CDEBUG(D_INFO, "error getting EA %s from MDS inode %ld: "
163                        "rc = %d\n", XATTR_LUSTRE_MDS_OBJID, inode->i_ino, rc);
164                 memset(lmm, 0, size);
165                 return rc;
166         }
167
168         /* This field is byteswapped because it appears in the
169          * catalogue.  All others are opaque to the MDS */
170         lmm->lmm_object_id = le64_to_cpu(lmm->lmm_object_id);
171
172         return rc;
173 }
174
175 static ssize_t mds_extN_readpage(struct file *file, char *buf, size_t count,
176                                  loff_t *offset)
177 {
178         struct inode *inode = file->f_dentry->d_inode;
179         int rc = 0;
180
181         if (S_ISREG(inode->i_mode))
182                 rc = file->f_op->read(file, buf, count, offset);
183         else {
184                 struct buffer_head *bh;
185
186                 /* FIXME: this assumes the blocksize == count, but the calling
187                  *        function will detect this as an error for now */
188                 bh = extN_bread(NULL, inode,
189                                 *offset >> inode->i_sb->s_blocksize_bits,
190                                 0, &rc);
191
192                 if (bh) {
193                         memcpy(buf, bh->b_data, inode->i_blksize);
194                         brelse(bh);
195                         rc = inode->i_blksize;
196                 }
197         }
198
199         return rc;
200 }
201
202 static void mds_extN_delete_inode(struct inode *inode)
203 {
204         if (S_ISREG(inode->i_mode)) {
205                 void *handle = mds_extN_start(inode, MDS_FSOP_UNLINK);
206
207                 if (IS_ERR(handle)) {
208                         CERROR("unable to start transaction");
209                         EXIT;
210                         return;
211                 }
212                 if (mds_extN_set_md(inode, handle, NULL))
213                         CERROR("error clearing obdo on %ld\n", inode->i_ino);
214
215                 if (mds_extN_fs_ops.cl_delete_inode)
216                         mds_extN_fs_ops.cl_delete_inode(inode);
217
218                 if (mds_extN_commit(inode, handle))
219                         CERROR("error closing handle on %ld\n", inode->i_ino);
220         } else
221                 mds_extN_fs_ops.cl_delete_inode(inode);
222 }
223
224 static void mds_extN_callback_status(void *jcb, int error)
225 {
226         struct mds_cb_data *mcb = (struct mds_cb_data *)jcb;
227
228         CDEBUG(D_EXT2, "got callback for last_rcvd "LPD64": rc = %d\n",
229                mcb->cb_last_rcvd, error);
230         if (!error && mcb->cb_last_rcvd > mcb->cb_mds->mds_last_committed)
231                 mcb->cb_mds->mds_last_committed = mcb->cb_last_rcvd;
232
233         kmem_cache_free(jcb_cache, jcb);
234         --jcb_cache_count;
235 }
236
237 static int mds_extN_set_last_rcvd(struct mds_obd *mds, void *handle)
238 {
239         struct mds_cb_data *mcb;
240
241         mcb = kmem_cache_alloc(jcb_cache, GFP_NOFS);
242         if (!mcb)
243                 RETURN(-ENOMEM);
244
245         ++jcb_cache_count;
246         mcb->cb_mds = mds;
247         mcb->cb_last_rcvd = mds->mds_last_rcvd;
248
249 #ifdef HAVE_JOURNAL_CALLBACK_STATUS
250         CDEBUG(D_EXT2, "set callback for last_rcvd: %Ld\n",
251                (unsigned long long)mcb->cb_last_rcvd);
252         journal_callback_set(handle, mds_extN_callback_status,
253                              (void *)mcb);
254 #else
255 #warning "no journal callback kernel patch, faking it..."
256         {
257         static long next = 0;
258
259         if (time_after(jiffies, next)) {
260                 CERROR("no journal callback kernel patch, faking it...\n");
261                 next = jiffies + 300 * HZ;
262         }
263         }
264         mds_extN_callback_status((struct journal_callback *)mcb, 0);
265 #endif
266
267         return 0;
268 }
269
270 static int mds_extN_journal_data(struct file *filp)
271 {
272         struct inode *inode = filp->f_dentry->d_inode;
273
274         EXTN_I(inode)->i_flags |= EXTN_JOURNAL_DATA_FL;
275
276         return 0;
277 }
278
279 /*
280  * We need to hack the return value for the free inode counts because
281  * the current EA code requires one filesystem block per inode with EAs,
282  * so it is possible to run out of blocks before we run out of inodes.
283  *
284  * This can be removed when the extN EA code is fixed.
285  */
286 static int mds_extN_statfs(struct super_block *sb, struct statfs *sfs)
287 {
288         int rc = vfs_statfs(sb, sfs);
289
290         if (!rc && sfs->f_bfree < sfs->f_ffree)
291                 sfs->f_ffree = sfs->f_bfree;
292
293         return rc;
294 }
295
296 static struct mds_fs_operations mds_extN_fs_ops = {
297         fs_owner:               THIS_MODULE,
298         fs_start:               mds_extN_start,
299         fs_commit:              mds_extN_commit,
300         fs_setattr:             mds_extN_setattr,
301         fs_set_md:              mds_extN_set_md,
302         fs_get_md:              mds_extN_get_md,
303         fs_readpage:            mds_extN_readpage,
304         fs_delete_inode:        mds_extN_delete_inode,
305         cl_delete_inode:        clear_inode,
306         fs_journal_data:        mds_extN_journal_data,
307         fs_set_last_rcvd:       mds_extN_set_last_rcvd,
308         fs_statfs:              mds_extN_statfs,
309 };
310
311 static int __init mds_extN_init(void)
312 {
313         int rc;
314
315         //rc = extN_xattr_register();
316         jcb_cache = kmem_cache_create("mds_extN_jcb",
317                                       sizeof(struct mds_cb_data), 0,
318                                       0, NULL, NULL);
319         if (!jcb_cache) {
320                 CERROR("error allocating MDS journal callback cache\n");
321                 GOTO(out, rc = -ENOMEM);
322         }
323         rc = mds_register_fs_type(&mds_extN_fs_ops, "extN");
324
325         if (rc)
326                 kmem_cache_destroy(jcb_cache);
327 out:
328         return rc;
329 }
330
331 static void __exit mds_extN_exit(void)
332 {
333         int rc;
334
335         mds_unregister_fs_type("extN");
336         rc = kmem_cache_destroy(jcb_cache);
337
338         if (rc || jcb_cache_count) {
339                 CERROR("can't free MDS callback cache: count %d, rc = %d\n",
340                        jcb_cache_count, rc);
341         }
342
343         //rc = extN_xattr_unregister();
344 }
345
346 MODULE_AUTHOR("Cluster File Systems, Inc. <info@clusterfs.com>");
347 MODULE_DESCRIPTION("Lustre MDS extN Filesystem Helper v0.1");
348 MODULE_LICENSE("GPL");
349
350 module_init(mds_extN_init);
351 module_exit(mds_extN_exit);