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