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