Whamcloud - gitweb
Merge of b_md to HEAD:
[fs/lustre-release.git] / lustre / mds / mds_ext3.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  lustre/mds/mds_ext3.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/init.h>
32 #include <linux/ext3_fs.h>
33 #include <linux/ext3_jbd.h>
34 #include <../fs/ext3/xattr.h>
35 #include <linux/kp30.h>
36 #include <linux/lustre_mds.h>
37 #include <linux/obd.h>
38 #include <linux/module.h>
39
40 static struct mds_fs_operations mds_ext3_fs_ops;
41 static kmem_cache_t *mcb_cache;
42 static int mcb_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 EXT3_XATTR_INDEX_LUSTRE         5
51 #define XATTR_LUSTRE_MDS_OBJID          "system.lustre_mds_objid"
52
53 /*
54  * We don't currently need any additional blocks for rmdir and
55  * unlink transactions because we are storing the OST oa_id inside
56  * the inode (which we will be changing anyways as part of this
57  * transaction).
58  */
59 static void *mds_ext3_start(struct inode *inode, int op)
60 {
61         /* For updates to the last recieved file */
62         int nblocks = EXT3_DATA_TRANS_BLOCKS;
63         void *handle;
64
65         switch(op) {
66         case MDS_FSOP_RMDIR:
67         case MDS_FSOP_UNLINK:
68                 nblocks += EXT3_DELETE_TRANS_BLOCKS;
69                 break;
70         case MDS_FSOP_RENAME:
71                 /* We may be modifying two directories */
72                 nblocks += EXT3_DATA_TRANS_BLOCKS;
73         case MDS_FSOP_SYMLINK:
74                 /* Possible new block + block bitmap + GDT for long symlink */
75                 nblocks += 3;
76         case MDS_FSOP_CREATE:
77         case MDS_FSOP_MKDIR:
78         case MDS_FSOP_MKNOD:
79                 /* New inode + block bitmap + GDT for new file */
80                 nblocks += 3;
81         case MDS_FSOP_LINK:
82                 /* Change parent directory */
83                 nblocks += EXT3_INDEX_EXTRA_TRANS_BLOCKS+EXT3_DATA_TRANS_BLOCKS;
84                 break;
85         case MDS_FSOP_SETATTR:
86                 /* Setattr on inode */
87                 nblocks += 1;
88                 break;
89         default: CERROR("unknown transaction start op %d\n", op);
90                  LBUG();
91         }
92
93         lock_kernel();
94         handle = journal_start(EXT3_JOURNAL(inode), nblocks);
95         unlock_kernel();
96
97         return handle;
98 }
99
100 static int mds_ext3_commit(struct inode *inode, void *handle)
101 {
102         int rc;
103
104         lock_kernel();
105         rc = journal_stop((handle_t *)handle);
106         unlock_kernel();
107
108         return rc;
109 }
110
111 static int mds_ext3_setattr(struct dentry *dentry, void *handle,
112                             struct iattr *iattr)
113 {
114         struct inode *inode = dentry->d_inode;
115         int rc;
116
117         lock_kernel();
118         if (inode->i_op->setattr)
119                 rc = inode->i_op->setattr(dentry, iattr);
120         else
121                 rc = inode_setattr(inode, iattr);
122
123         unlock_kernel();
124
125         return rc;
126 }
127
128 static int mds_ext3_set_md(struct inode *inode, void *handle,
129                            struct lov_mds_md *lmm, int lmm_size)
130 {
131         int rc;
132
133         down(&inode->i_sem);
134         lock_kernel();
135         rc = ext3_xattr_set(handle, inode, EXT3_XATTR_INDEX_LUSTRE,
136                             XATTR_LUSTRE_MDS_OBJID, lmm, lmm_size, 0);
137         unlock_kernel();
138         up(&inode->i_sem);
139
140         if (rc) {
141                 CERROR("error adding objectid "LPX64" to inode %ld: %d\n",
142                        lmm->lmm_object_id, inode->i_ino, rc);
143                 if (rc != -ENOSPC) LBUG();
144         }
145         return rc;
146 }
147
148 static int mds_ext3_get_md(struct inode *inode, struct lov_mds_md *lmm,int size)
149 {
150         int rc;
151
152         down(&inode->i_sem);
153         lock_kernel();
154         rc = ext3_xattr_get(inode, EXT3_XATTR_INDEX_LUSTRE,
155                             XATTR_LUSTRE_MDS_OBJID, lmm, size);
156         unlock_kernel();
157         up(&inode->i_sem);
158
159         /* This gives us the MD size */
160         if (lmm == NULL)
161                 return (rc == -ENODATA) ? 0 : rc;
162
163         if (rc < 0) {
164                 CDEBUG(D_INFO, "error getting EA %s from MDS inode %ld: "
165                        "rc = %d\n", XATTR_LUSTRE_MDS_OBJID, inode->i_ino, rc);
166                 memset(lmm, 0, size);
167                 return (rc == -ENODATA) ? 0 : rc;
168         }
169
170         /* This field is byteswapped because it appears in the
171          * catalogue.  All others are opaque to the MDS */
172         lmm->lmm_object_id = le64_to_cpu(lmm->lmm_object_id);
173
174         return rc;
175 }
176
177 static ssize_t mds_ext3_readpage(struct file *file, char *buf, size_t count,
178                                  loff_t *offset)
179 {
180         struct inode *inode = file->f_dentry->d_inode;
181         int rc = 0;
182
183         if (S_ISREG(inode->i_mode))
184                 rc = file->f_op->read(file, buf, count, offset);
185         else {
186                 struct buffer_head *bh;
187
188                 /* FIXME: this assumes the blocksize == count, but the calling
189                  *        function will detect this as an error for now */
190                 bh = ext3_bread(NULL, inode,
191                                 *offset >> inode->i_sb->s_blocksize_bits,
192                                 0, &rc);
193
194                 if (bh) {
195                         memcpy(buf, bh->b_data, inode->i_blksize);
196                         brelse(bh);
197                         rc = inode->i_blksize;
198                 }
199         }
200
201         return rc;
202 }
203
204 static void mds_ext3_delete_inode(struct inode *inode)
205 {
206         if (S_ISREG(inode->i_mode)) {
207                 void *handle = mds_ext3_start(inode, MDS_FSOP_UNLINK);
208
209                 if (IS_ERR(handle)) {
210                         CERROR("unable to start transaction");
211                         EXIT;
212                         return;
213                 }
214                 if (mds_ext3_set_md(inode, handle, NULL, 0))
215                         CERROR("error clearing objid on %ld\n", inode->i_ino);
216
217                 if (mds_ext3_fs_ops.cl_delete_inode)
218                         mds_ext3_fs_ops.cl_delete_inode(inode);
219
220                 if (mds_ext3_commit(inode, handle))
221                         CERROR("error closing handle on %ld\n", inode->i_ino);
222         } else
223                 mds_ext3_fs_ops.cl_delete_inode(inode);
224 }
225
226 static void mds_ext3_callback_status(struct journal_callback *jcb, int error)
227 {
228         struct mds_cb_data *mcb = (struct mds_cb_data *)jcb;
229
230         CDEBUG(D_EXT2, "got callback for last_rcvd "LPD64": 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;
234
235         kmem_cache_free(mcb_cache, mcb);
236         --mcb_cache_count;
237 }
238
239 static int mds_ext3_set_last_rcvd(struct mds_obd *mds, void *handle)
240 {
241         struct mds_cb_data *mcb;
242
243         mcb = kmem_cache_alloc(mcb_cache, GFP_NOFS);
244         if (!mcb)
245                 RETURN(-ENOMEM);
246
247         ++mcb_cache_count;
248         mcb->cb_mds = mds;
249         mcb->cb_last_rcvd = mds->mds_last_rcvd;
250
251 #ifdef HAVE_JOURNAL_CALLBACK_STATUS
252         CDEBUG(D_EXT2, "set callback for last_rcvd: "LPD64"\n",
253                mcb->cb_last_rcvd);
254         lock_kernel();
255         /* Note that an "incompatible pointer" warning here is OK for now */
256         journal_callback_set(handle, mds_ext3_callback_status,
257                              (struct journal_callback *)mcb);
258         unlock_kernel();
259 #else
260 #warning "no journal callback kernel patch, faking it..."
261         {
262         static long next = 0;
263
264         if (time_after(jiffies, next)) {
265                 CERROR("no journal callback kernel patch, faking it...\n");
266                 next = jiffies + 300 * HZ;
267         }
268
269         mds_ext3_callback_status((struct journal_callback *)mcb, 0);
270 #endif
271
272         return 0;
273 }
274
275 static int mds_ext3_journal_data(struct file *filp)
276 {
277         struct inode *inode = filp->f_dentry->d_inode;
278
279         EXT3_I(inode)->i_flags |= EXT3_JOURNAL_DATA_FL;
280
281         return 0;
282 }
283
284 /*
285  * We need to hack the return value for the free inode counts because
286  * the current EA code requires one filesystem block per inode with EAs,
287  * so it is possible to run out of blocks before we run out of inodes.
288  *
289  * This can be removed when the ext3 EA code is fixed.
290  */
291 static int mds_ext3_statfs(struct super_block *sb, struct statfs *sfs)
292 {
293         int rc = vfs_statfs(sb, sfs);
294
295         if (!rc && sfs->f_bfree < sfs->f_ffree)
296                 sfs->f_ffree = sfs->f_bfree;
297
298         return rc;
299 }
300
301 static struct mds_fs_operations mds_ext3_fs_ops = {
302         fs_owner:               THIS_MODULE,
303         fs_start:               mds_ext3_start,
304         fs_commit:              mds_ext3_commit,
305         fs_setattr:             mds_ext3_setattr,
306         fs_set_md:              mds_ext3_set_md,
307         fs_get_md:              mds_ext3_get_md,
308         fs_readpage:            mds_ext3_readpage,
309         fs_delete_inode:        mds_ext3_delete_inode,
310         cl_delete_inode:        clear_inode,
311         fs_journal_data:        mds_ext3_journal_data,
312         fs_set_last_rcvd:       mds_ext3_set_last_rcvd,
313         fs_statfs:              mds_ext3_statfs,
314 };
315
316 static int __init mds_ext3_init(void)
317 {
318         int rc;
319
320         //rc = ext3_xattr_register();
321         mcb_cache = kmem_cache_create("mds_ext3_mcb",
322                                       sizeof(struct mds_cb_data), 0,
323                                       0, NULL, NULL);
324         if (!mcb_cache) {
325                 CERROR("error allocating MDS journal callback cache\n");
326                 GOTO(out, rc = -ENOMEM);
327         }
328
329         rc = mds_register_fs_type(&mds_ext3_fs_ops, "ext3");
330
331         if (rc)
332                 kmem_cache_destroy(mcb_cache);
333 out:
334         return rc;
335 }
336
337 static void __exit mds_ext3_exit(void)
338 {
339         int rc;
340
341         mds_unregister_fs_type("ext3");
342         rc = kmem_cache_destroy(mcb_cache);
343
344         if (rc || mcb_cache_count) {
345                 CERROR("can't free MDS callback cache: count %d, rc = %d\n",
346                        mcb_cache_count, rc);
347         }
348
349         //rc = ext3_xattr_unregister();
350 }
351
352 MODULE_AUTHOR("Cluster File Systems, Inc. <info@clusterfs.com>");
353 MODULE_DESCRIPTION("Lustre MDS ext3 Filesystem Helper v0.1");
354 MODULE_LICENSE("GPL");
355
356 module_init(mds_ext3_init);
357 module_exit(mds_ext3_exit);