Whamcloud - gitweb
WARNING: This commit breaks everything. It will be back in shape within 12
[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 struct mds_objid {
38         __u64 mo_magic;
39         struct lov_md mo_lov_md;
40 };
41
42 #define EXTN_XATTR_INDEX_LUSTRE         5
43 #define XATTR_LUSTRE_MDS_OBJID          "system.lustre_mds_objid"
44
45 #define XATTR_MDS_MO_MAGIC              0x4711
46
47 /*
48  * We don't currently need any additional blocks for rmdir and
49  * unlink transactions because we are storing the OST oa_id inside
50  * the inode (which we will be changing anyways as part of this
51  * transaction).
52  */
53 static void *mds_extN_start(struct inode *inode, int op)
54 {
55         /* For updates to the last recieved file */
56         int nblocks = EXTN_DATA_TRANS_BLOCKS;
57
58         switch(op) {
59         case MDS_FSOP_RMDIR:
60         case MDS_FSOP_UNLINK:
61                 nblocks += EXTN_DELETE_TRANS_BLOCKS;
62                 break;
63         case MDS_FSOP_RENAME:
64                 /* We may be modifying two directories */
65                 nblocks += EXTN_DATA_TRANS_BLOCKS;
66         case MDS_FSOP_SYMLINK:
67                 /* Possible new block + block bitmap + GDT for long symlink */
68                 nblocks += 3;
69         case MDS_FSOP_CREATE:
70         case MDS_FSOP_MKDIR:
71         case MDS_FSOP_MKNOD:
72                 /* New inode + block bitmap + GDT for new file */
73                 nblocks += 3;
74         case MDS_FSOP_LINK:
75                 /* Change parent directory */
76                 nblocks += EXTN_INDEX_EXTRA_TRANS_BLOCKS+EXTN_DATA_TRANS_BLOCKS;
77                 break;
78         case MDS_FSOP_SETATTR:
79                 /* Setattr on inode */
80                 nblocks += 1;
81                 break;
82         default: CERROR("unknown transaction start op %d\n", op);
83                  LBUG();
84         }
85
86         return journal_start(EXTN_JOURNAL(inode), nblocks);
87 }
88
89 static int mds_extN_commit(struct inode *inode, void *handle)
90 {
91         return journal_stop((handle_t *)handle);
92 }
93
94 static int mds_extN_setattr(struct dentry *dentry, void *handle,
95                             struct iattr *iattr)
96 {
97         struct inode *inode = dentry->d_inode;
98
99         if (inode->i_op->setattr)
100                 return inode->i_op->setattr(dentry, iattr);
101         else
102                 return inode_setattr(inode, iattr);
103 }
104
105 static int mds_extN_set_obdo(struct inode *inode, void *handle,
106                              struct obdo *obdo)
107 {
108         struct mds_objid *data = (struct mds_objid *)obdo->o_inline;
109         int rc;
110
111         data->mo_magic = cpu_to_le64(XATTR_MDS_MO_MAGIC);
112
113         lock_kernel();
114         down(&inode->i_sem);
115         if (obdo == NULL)
116                 rc = extN_xattr_set(handle, inode, EXTN_XATTR_INDEX_LUSTRE,
117                                     XATTR_LUSTRE_MDS_OBJID, NULL, 0, 0);
118         else
119                 rc = extN_xattr_set(handle, inode, EXTN_XATTR_INDEX_LUSTRE,
120                                     XATTR_LUSTRE_MDS_OBJID, obdo->o_inline,
121                                     OBD_INLINESZ, XATTR_CREATE);
122         up(&inode->i_sem);
123         unlock_kernel();
124
125         if (rc)
126                 CERROR("error adding objectid %Ld to inode %ld\n",
127                        (unsigned long long)obdo->o_id, inode->i_ino);
128         return rc;
129 }
130
131 static int mds_extN_get_obdo(struct inode *inode, struct obdo *obdo)
132 {
133         char *buf;
134         struct mds_objid data;
135         struct lov_object_id *lov_ids;
136         int rc, size;
137
138         lock_kernel();
139         down(&inode->i_sem);
140         rc = extN_xattr_get(inode, EXTN_XATTR_INDEX_LUSTRE,
141                             XATTR_LUSTRE_MDS_OBJID, &data,
142                             sizeof(struct mds_objid));
143         size = sizeof(struct mds_objid) + data.mo_lov_md.lmd_stripe_count *
144                 sizeof(*lov_ids);
145         OBD_ALLOC(buf, size);
146         if (buf == NULL)
147                 LBUG();
148         rc = extN_xattr_get(inode, EXTN_XATTR_INDEX_LUSTRE,
149                             XATTR_LUSTRE_MDS_OBJID, buf, size);
150         up(&inode->i_sem);
151         unlock_kernel();
152
153         if (size > OBD_INLINESZ)
154                 LBUG();
155
156         if (rc < 0) {
157                 CERROR("error getting EA %s from MDS inode %ld: rc = %d\n",
158                        XATTR_LUSTRE_MDS_OBJID, inode->i_ino, rc);
159                 obdo->o_id = 0;
160         } else if (data.mo_magic != cpu_to_le64(XATTR_MDS_MO_MAGIC)) {
161                 CERROR("MDS object id %Ld has bad magic %Lx\n",
162                        (unsigned long long)obdo->o_id,
163                        (unsigned long long)le64_to_cpu(data.mo_magic));
164                 rc = -EINVAL;
165         } else {
166                 /* This field is byteswapped because it appears in the
167                  * catalogue.  All others are opaque to the MDS */
168                 obdo->o_id = le64_to_cpu(data.mo_lov_md.lmd_object_id);
169                 memcpy(obdo->o_inline, buf + sizeof(data), size);
170         }
171
172 #warning FIXME: pass this buffer to caller for transmission when size exceeds OBD_INLINESZ
173         OBD_FREE(buf, size);
174         return rc;
175 }
176
177 static ssize_t mds_extN_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 = extN_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_extN_delete_inode(struct inode *inode)
205 {
206         if (S_ISREG(inode->i_mode)) {
207                 void *handle = mds_extN_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_extN_set_obdo(inode, handle, NULL))
215                         CERROR("error clearing obdo on %ld\n", inode->i_ino);
216
217                 if (mds_extN_fs_ops.cl_delete_inode)
218                         mds_extN_fs_ops.cl_delete_inode(inode);
219
220                 if (mds_extN_commit(inode, handle))
221                         CERROR("error closing handle on %ld\n", inode->i_ino);
222         } else
223                 mds_extN_fs_ops.cl_delete_inode(inode);
224 }
225
226 static void mds_extN_callback_status(void *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 %Ld: 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(jcb_cache, jcb);
236         --jcb_cache_count;
237 }
238
239 #ifdef HAVE_JOURNAL_CALLBACK
240 static void mds_extN_callback_func(void *cb_data)
241 {
242         mds_extN_callback_status(cb_data, 0);
243 }
244 #endif
245
246 static int mds_extN_set_last_rcvd(struct mds_obd *mds, void *handle)
247 {
248         struct mds_cb_data *mcb;
249
250         mcb = kmem_cache_alloc(jcb_cache, GFP_NOFS);
251         if (!mcb)
252                 RETURN(-ENOMEM);
253
254         ++jcb_cache_count;
255         mcb->cb_mds = mds;
256         mcb->cb_last_rcvd = mds->mds_last_rcvd;
257
258 #ifdef HAVE_JOURNAL_CALLBACK_STATUS
259         CDEBUG(D_EXT2, "set callback for last_rcvd: %Ld\n",
260                (unsigned long long)mcb->cb_last_rcvd);
261         journal_callback_set(handle, mds_extN_callback_status,
262                              (void *)mcb);
263 #elif defined(HAVE_JOURNAL_CALLBACK)
264         /* XXX original patch version - remove soon */
265 #warning "using old journal callback kernel patch, please update"
266         CDEBUG(D_EXT2, "set callback for last_rcvd: %Ld\n",
267                (unsigned long long)mcb->cb_last_rcvd);
268         journal_callback_set(handle, mds_extN_callback_func, mcb);
269 #else
270 #warning "no journal callback kernel patch, faking it..."
271         {
272         static long next = 0;
273
274         if (time_after(jiffies, next)) {
275                 CERROR("no journal callback kernel patch, faking it...\n");
276                 next = jiffies + 300 * HZ;
277         }
278         }
279         mds_extN_callback_status((struct journal_callback *)mcb, 0);
280 #endif
281
282         return 0;
283 }
284
285 static int mds_extN_journal_data(struct file *filp)
286 {
287         struct inode *inode = filp->f_dentry->d_inode;
288
289         EXTN_I(inode)->i_flags |= EXTN_JOURNAL_DATA_FL;
290
291         return 0;
292 }
293
294 static struct mds_fs_operations mds_extN_fs_ops = {
295         fs_start:               mds_extN_start,
296         fs_commit:              mds_extN_commit,
297         fs_setattr:             mds_extN_setattr,
298         fs_set_obdo:            mds_extN_set_obdo,
299         fs_get_obdo:            mds_extN_get_obdo,
300         fs_readpage:            mds_extN_readpage,
301         fs_delete_inode:        mds_extN_delete_inode,
302         cl_delete_inode:        clear_inode,
303         fs_journal_data:        mds_extN_journal_data,
304         fs_set_last_rcvd:       mds_extN_set_last_rcvd,
305 };
306
307 static int __init mds_extN_init(void)
308 {
309         int rc;
310
311         //rc = extN_xattr_register();
312         jcb_cache = kmem_cache_create("mds_extN_jcb",
313                                       sizeof(struct mds_cb_data), 0,
314                                       0, NULL, NULL);
315         if (!jcb_cache) {
316                 CERROR("error allocating MDS journal callback cache\n");
317                 GOTO(out, rc = -ENOMEM);
318         }
319         rc = mds_register_fs_type(&mds_extN_fs_ops, "extN");
320
321         if (rc)
322                 kmem_cache_destroy(jcb_cache);
323 out:
324         return rc;
325 }
326
327 static void __exit mds_extN_exit(void)
328 {
329         int rc;
330
331         mds_unregister_fs_type("extN");
332         rc = kmem_cache_destroy(jcb_cache);
333
334         if (rc || jcb_cache_count) {
335                 CERROR("can't free MDS callback cache: count %d, rc = %d\n",
336                        jcb_cache_count, rc);
337         }
338
339         //rc = extN_xattr_unregister();
340 }
341
342 MODULE_AUTHOR("Cluster File Systems, Inc. <adilger@clusterfs.com>");
343 MODULE_DESCRIPTION("Lustre MDS extN Filesystem Helper v0.1");
344 MODULE_LICENSE("GPL");
345
346 module_init(mds_extN_init);
347 module_exit(mds_extN_exit);