Whamcloud - gitweb
land b_md onto HEAD. the highlights:
[fs/lustre-release.git] / lustre / obdclass / fsfilt_ext3.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  lustre/lib/fsfilt_ext3.c
5  *  Lustre filesystem 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_FILTER
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 <linux/ext3_xattr.h>
35 #include <linux/kp30.h>
36 #include <linux/lustre_fsfilt.h>
37 #include <linux/obd.h>
38 #include <linux/module.h>
39
40 static kmem_cache_t *fcb_cache;
41 static int fcb_cache_count;
42
43 struct fsfilt_cb_data {
44         struct journal_callback cb_jcb; /* data private to jbd */
45         fsfilt_cb_t cb_func;            /* MDS/OBD completion function */
46         struct obd_device *cb_obd;      /* MDS/OBD completion device */
47         __u64 cb_last_rcvd;             /* MDS/OST last committed operation */
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 *fsfilt_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 FSFILT_OP_RMDIR:
67         case FSFILT_OP_UNLINK:
68                 nblocks += EXT3_DELETE_TRANS_BLOCKS;
69                 break;
70         case FSFILT_OP_RENAME:
71                 /* We may be modifying two directories */
72                 nblocks += EXT3_DATA_TRANS_BLOCKS;
73         case FSFILT_OP_SYMLINK:
74                 /* Possible new block + block bitmap + GDT for long symlink */
75                 nblocks += 3;
76         case FSFILT_OP_CREATE:
77         case FSFILT_OP_MKDIR:
78         case FSFILT_OP_MKNOD:
79                 /* New inode + block bitmap + GDT for new file */
80                 nblocks += 3;
81         case FSFILT_OP_LINK:
82                 /* Change parent directory */
83                 nblocks += EXT3_INDEX_EXTRA_TRANS_BLOCKS+EXT3_DATA_TRANS_BLOCKS;
84                 break;
85         case FSFILT_OP_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 fsfilt_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 fsfilt_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 fsfilt_ext3_set_md(struct inode *inode, void *handle,
129                               void *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 MD data to inode %lu: rc = %d\n",
142                        inode->i_ino, rc);
143                 if (rc != -ENOSPC) LBUG();
144         }
145         return rc;
146 }
147
148 static int fsfilt_ext3_get_md(struct inode *inode, void *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 inode %lu: "
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         return rc;
171 }
172
173 static ssize_t fsfilt_ext3_readpage(struct file *file, char *buf, size_t count,
174                                     loff_t *offset)
175 {
176         struct inode *inode = file->f_dentry->d_inode;
177         int rc = 0;
178
179         if (S_ISREG(inode->i_mode))
180                 rc = file->f_op->read(file, buf, count, offset);
181         else {
182                 struct buffer_head *bh;
183
184                 /* FIXME: this assumes the blocksize == count, but the calling
185                  *        function will detect this as an error for now */
186                 bh = ext3_bread(NULL, inode,
187                                 *offset >> inode->i_sb->s_blocksize_bits,
188                                 0, &rc);
189
190                 if (bh) {
191                         memcpy(buf, bh->b_data, inode->i_blksize);
192                         brelse(bh);
193                         rc = inode->i_blksize;
194                 }
195         }
196
197         return rc;
198 }
199
200 static void fsfilt_ext3_cb_func(struct journal_callback *jcb, int error)
201 {
202         struct fsfilt_cb_data *fcb = (struct fsfilt_cb_data *)jcb;
203
204         fcb->cb_func(fcb->cb_obd, fcb->cb_last_rcvd, error);
205
206         kmem_cache_free(fcb_cache, fcb);
207         --fcb_cache_count;
208 }
209
210 static int fsfilt_ext3_set_last_rcvd(struct obd_device *obd, __u64 last_rcvd,
211                                      void *handle, fsfilt_cb_t cb_func)
212 {
213 #ifdef HAVE_JOURNAL_CALLBACK_STATUS
214         struct fsfilt_cb_data *fcb;
215
216         fcb = kmem_cache_alloc(fcb_cache, GFP_NOFS);
217         if (!fcb)
218                 RETURN(-ENOMEM);
219
220         ++fcb_cache_count;
221         fcb->cb_func = cb_func;
222         fcb->cb_obd = obd;
223         fcb->cb_last_rcvd = last_rcvd;
224
225         CDEBUG(D_EXT2, "set callback for last_rcvd: "LPD64"\n", last_rcvd);
226         lock_kernel();
227         /* Note that an "incompatible pointer" warning here is OK for now */
228         journal_callback_set(handle, fsfilt_ext3_cb_func,
229                              (struct journal_callback *)fcb);
230         unlock_kernel();
231 #else
232 #warning "no journal callback kernel patch, faking it..."
233         static long next = 0;
234
235         if (time_after(jiffies, next)) {
236                 CERROR("no journal callback kernel patch, faking it...\n");
237                 next = jiffies + 300 * HZ;
238         }
239
240         cb_func(obd, last_rcvd, 0);
241 #endif
242
243         return 0;
244 }
245
246 static int fsfilt_ext3_journal_data(struct file *filp)
247 {
248         struct inode *inode = filp->f_dentry->d_inode;
249
250         EXT3_I(inode)->i_flags |= EXT3_JOURNAL_DATA_FL;
251
252         return 0;
253 }
254
255 /*
256  * We need to hack the return value for the free inode counts because
257  * the current EA code requires one filesystem block per inode with EAs,
258  * so it is possible to run out of blocks before we run out of inodes.
259  *
260  * This can be removed when the ext3 EA code is fixed.
261  */
262 static int fsfilt_ext3_statfs(struct super_block *sb, struct statfs *sfs)
263 {
264         int rc = vfs_statfs(sb, sfs);
265
266         if (!rc && sfs->f_bfree < sfs->f_ffree)
267                 sfs->f_ffree = sfs->f_bfree;
268
269         return rc;
270 }
271
272 static struct fsfilt_operations fsfilt_ext3_ops = {
273         fs_type:                "ext3",
274         fs_owner:               THIS_MODULE,
275         fs_start:               fsfilt_ext3_start,
276         fs_commit:              fsfilt_ext3_commit,
277         fs_setattr:             fsfilt_ext3_setattr,
278         fs_set_md:              fsfilt_ext3_set_md,
279         fs_get_md:              fsfilt_ext3_get_md,
280         fs_readpage:            fsfilt_ext3_readpage,
281         fs_journal_data:        fsfilt_ext3_journal_data,
282         fs_set_last_rcvd:       fsfilt_ext3_set_last_rcvd,
283         fs_statfs:              fsfilt_ext3_statfs,
284 };
285
286 static int __init fsfilt_ext3_init(void)
287 {
288         int rc;
289
290         //rc = ext3_xattr_register();
291         fcb_cache = kmem_cache_create("fsfilt_ext3_fcb",
292                                       sizeof(struct fsfilt_cb_data), 0,
293                                       0, NULL, NULL);
294         if (!fcb_cache) {
295                 CERROR("error allocating fsfilt journal callback cache\n");
296                 GOTO(out, rc = -ENOMEM);
297         }
298
299         rc = fsfilt_register_ops(&fsfilt_ext3_fs_ops);
300
301         if (rc)
302                 kmem_cache_destroy(fcb_cache);
303 out:
304         return rc;
305 }
306
307 static void __exit fsfilt_ext3_exit(void)
308 {
309         int rc;
310
311         fsfilt_unregister_ops(&fsfilt_ext3_fs_ops);
312         rc = kmem_cache_destroy(fcb_cache);
313
314         if (rc || fcb_cache_count) {
315                 CERROR("can't free fsfilt callback cache: count %d, rc = %d\n",
316                        fcb_cache_count, rc);
317         }
318
319         //rc = ext3_xattr_unregister();
320 }
321
322 MODULE_AUTHOR("Cluster File Systems, Inc. <info@clusterfs.com>");
323 MODULE_DESCRIPTION("Lustre ext3 Filesystem Helper v0.1");
324 MODULE_LICENSE("GPL");
325
326 module_init(fsfilt_ext3_init);
327 module_exit(fsfilt_ext3_exit);