Whamcloud - gitweb
land b_md onto HEAD. the highlights:
[fs/lustre-release.git] / lustre / obdclass / fsfilt_extN.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  lustre/lib/fsfilt_extN.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/pagemap.h>
32 #include <linux/quotaops.h>
33 #include <linux/extN_fs.h>
34 #include <linux/extN_jbd.h>
35 #include <linux/extN_xattr.h>
36 #include <linux/kp30.h>
37 #include <linux/lustre_fsfilt.h>
38 #include <linux/obd.h>
39 #include <linux/module.h>
40
41 static kmem_cache_t *fcb_cache;
42 static int fcb_cache_count;
43
44 struct fsfilt_cb_data {
45         struct journal_callback cb_jcb; /* data private to jbd */
46         fsfilt_cb_t cb_func;            /* MDS/OBD completion function */
47         struct obd_device *cb_obd;      /* MDS/OBD completion device */
48         __u64 cb_last_rcvd;             /* MDS/OST last committed operation */
49 };
50
51 #define EXTN_XATTR_INDEX_LUSTRE         5
52 #define XATTR_LUSTRE_MDS_OBJID          "system.lustre_mds_objid"
53
54 /*
55  * We don't currently need any additional blocks for rmdir and
56  * unlink transactions because we are storing the OST oa_id inside
57  * the inode (which we will be changing anyways as part of this
58  * transaction).
59  */
60 static void *fsfilt_extN_start(struct inode *inode, int op)
61 {
62         /* For updates to the last recieved file */
63         int nblocks = EXTN_DATA_TRANS_BLOCKS;
64         void *handle;
65
66         switch(op) {
67         case FSFILT_OP_RMDIR:
68         case FSFILT_OP_UNLINK:
69                 nblocks += EXTN_DELETE_TRANS_BLOCKS;
70                 break;
71         case FSFILT_OP_RENAME:
72                 /* modify additional directory */
73                 nblocks += EXTN_DATA_TRANS_BLOCKS;
74                 /* no break */
75         case FSFILT_OP_SYMLINK:
76                 /* additional block + block bitmap + GDT for long symlink */
77                 nblocks += 3;
78                 /* no break */
79         case FSFILT_OP_CREATE:
80         case FSFILT_OP_MKDIR:
81         case FSFILT_OP_MKNOD:
82                 /* modify one inode + block bitmap + GDT */
83                 nblocks += 3;
84                 /* no break */
85         case FSFILT_OP_LINK:
86                 /* modify parent directory */
87                 nblocks += EXTN_INDEX_EXTRA_TRANS_BLOCKS+EXTN_DATA_TRANS_BLOCKS;
88                 break;
89         case FSFILT_OP_SETATTR:
90                 /* Setattr on inode */
91                 nblocks += 1;
92                 break;
93         default: CERROR("unknown transaction start op %d\n", op);
94                  LBUG();
95         }
96
97         LASSERT(!current->journal_info);
98         lock_kernel();
99         handle = journal_start(EXTN_JOURNAL(inode), nblocks);
100         unlock_kernel();
101
102         return handle;
103 }
104
105 /*
106  * Calculate the number of buffer credits needed to write multiple pages in
107  * a single extN transaction.  No, this shouldn't be here, but as yet extN
108  * doesn't have a nice API for calculating this sort of thing in advance.
109  *
110  * See comment above extN_writepage_trans_blocks for details.  We assume
111  * no data journaling is being done, but it does allow for all of the pages
112  * being non-contiguous.  If we are guaranteed contiguous pages we could
113  * reduce the number of (d)indirect blocks a lot.
114  *
115  * With N blocks per page and P pages, for each inode we have at most:
116  * N*P indirect
117  * min(N*P, blocksize/4 + 1) dindirect blocks
118  * niocount tindirect
119  *
120  * For the entire filesystem, we have at most:
121  * min(sum(nindir + P), ngroups) bitmap blocks (from the above)
122  * min(sum(nindir + P), gdblocks) group descriptor blocks (from the above)
123  * objcount inode blocks
124  * 1 superblock
125  * 2 * EXTN_SINGLEDATA_TRANS_BLOCKS for the quota files
126  */
127 static int fsfilt_extN_credits_needed(int objcount, struct fsfilt_objinfo *fso)
128 {
129         struct super_block *sb = fso->fso_dentry->d_inode->i_sb;
130         int blockpp = 1 << (PAGE_CACHE_SHIFT - sb->s_blocksize_bits);
131         int addrpp = EXTN_ADDR_PER_BLOCK(sb) * blockpp;
132         int nbitmaps = 0;
133         int ngdblocks = 0;
134         int needed = objcount + 1;
135         int i;
136
137         for (i = 0; i < objcount; i++, fso++) {
138                 int nblocks = fso->fso_bufcnt * blockpp;
139                 int ndindirect = min(nblocks, addrpp + 1);
140                 int nindir = nblocks + ndindirect + 1;
141
142                 nbitmaps += nindir + nblocks;
143                 ngdblocks += nindir + nblocks;
144
145                 needed += nindir;
146         }
147
148         /* Assumes extN and extN have same sb_info layout at the start. */
149         if (nbitmaps > EXTN_SB(sb)->s_groups_count)
150                 nbitmaps = EXTN_SB(sb)->s_groups_count;
151         if (ngdblocks > EXTN_SB(sb)->s_gdb_count)
152                 ngdblocks = EXTN_SB(sb)->s_gdb_count;
153
154         needed += nbitmaps + ngdblocks;
155
156 #ifdef CONFIG_QUOTA
157         /* We assume that there will be 1 bit set in s_dquot.flags for each
158          * quota file that is active.  This is at least true for now.
159          */
160         needed += hweight32(sb_any_quota_enabled(sb)) *
161                 EXTN_SINGLEDATA_TRANS_BLOCKS;
162 #endif
163
164         return needed;
165 }
166
167 /* We have to start a huge journal transaction here to hold all of the
168  * metadata for the pages being written here.  This is necessitated by
169  * the fact that we do lots of prepare_write operations before we do
170  * any of the matching commit_write operations, so even if we split
171  * up to use "smaller" transactions none of them could complete until
172  * all of them were opened.  By having a single journal transaction,
173  * we eliminate duplicate reservations for common blocks like the
174  * superblock and group descriptors or bitmaps.
175  *
176  * We will start the transaction here, but each prepare_write will
177  * add a refcount to the transaction, and each commit_write will
178  * remove a refcount.  The transaction will be closed when all of
179  * the pages have been written.
180  */
181 static void *fsfilt_extN_brw_start(int objcount, struct fsfilt_objinfo *fso,
182                                    int niocount, struct niobuf_remote *nb)
183 {
184         journal_t *journal;
185         handle_t *handle;
186         int needed;
187         ENTRY;
188
189         LASSERT(!current->journal_info);
190         journal = EXTN_SB(fso->fso_dentry->d_inode->i_sb)->s_journal;
191         needed = fsfilt_extN_credits_needed(objcount, fso);
192
193         /* The number of blocks we could _possibly_ dirty can very large.
194          * We reduce our request if it is absurd (and we couldn't get that
195          * many credits for a single handle anyways).
196          *
197          * At some point we have to limit the size of I/Os sent at one time,
198          * increase the size of the journal, or we have to calculate the
199          * actual journal requirements more carefully by checking all of
200          * the blocks instead of being maximally pessimistic.  It remains to
201          * be seen if this is a real problem or not.
202          */
203         if (needed > journal->j_max_transaction_buffers) {
204                 CERROR("want too many journal credits (%d) using %d instead\n",
205                        needed, journal->j_max_transaction_buffers);
206                 needed = journal->j_max_transaction_buffers;
207         }
208
209         lock_kernel();
210         handle = journal_start(journal, needed);
211         unlock_kernel();
212         if (IS_ERR(handle))
213                 CERROR("can't get handle for %d credits: rc = %ld\n", needed,
214                        PTR_ERR(handle));
215
216         RETURN(handle);
217 }
218
219 static int fsfilt_extN_commit(struct inode *inode, void *handle)
220 {
221         int rc;
222
223         lock_kernel();
224         rc = journal_stop((handle_t *)handle);
225         unlock_kernel();
226
227         return rc;
228 }
229
230 static int fsfilt_extN_setattr(struct dentry *dentry, void *handle,
231                                struct iattr *iattr)
232 {
233         struct inode *inode = dentry->d_inode;
234         int rc;
235
236         lock_kernel();
237         if (inode->i_op->setattr)
238                 rc = inode->i_op->setattr(dentry, iattr);
239         else
240                 rc = inode_setattr(inode, iattr);
241
242         unlock_kernel();
243
244         return rc;
245 }
246
247 static int fsfilt_extN_set_md(struct inode *inode, void *handle,
248                               void *lmm, int lmm_size)
249 {
250         int rc;
251
252         down(&inode->i_sem);
253         lock_kernel();
254         rc = extN_xattr_set(handle, inode, EXTN_XATTR_INDEX_LUSTRE,
255                             XATTR_LUSTRE_MDS_OBJID, lmm, lmm_size, 0);
256         unlock_kernel();
257         up(&inode->i_sem);
258
259         if (rc) {
260                 CERROR("error adding MD data to inode %lu: rc = %d\n",
261                        inode->i_ino, rc);
262                 if (rc != -ENOSPC) LBUG();
263         }
264         return rc;
265 }
266
267 static int fsfilt_extN_get_md(struct inode *inode, void *lmm, int size)
268 {
269         int rc;
270
271         down(&inode->i_sem);
272         lock_kernel();
273         rc = extN_xattr_get(inode, EXTN_XATTR_INDEX_LUSTRE,
274                             XATTR_LUSTRE_MDS_OBJID, lmm, size);
275         unlock_kernel();
276         up(&inode->i_sem);
277
278         /* This gives us the MD size */
279         if (lmm == NULL)
280                 return (rc == -ENODATA) ? 0 : rc;
281
282         if (rc < 0) {
283                 CDEBUG(D_INFO, "error getting EA %s from inode %lu: "
284                        "rc = %d\n", XATTR_LUSTRE_MDS_OBJID, inode->i_ino, rc);
285                 memset(lmm, 0, size);
286                 return (rc == -ENODATA) ? 0 : rc;
287         }
288
289         return rc;
290 }
291
292 static ssize_t fsfilt_extN_readpage(struct file *file, char *buf, size_t count,
293                                     loff_t *offset)
294 {
295         struct inode *inode = file->f_dentry->d_inode;
296         int rc = 0;
297
298         if (S_ISREG(inode->i_mode))
299                 rc = file->f_op->read(file, buf, count, offset);
300         else {
301                 struct buffer_head *bh;
302
303                 /* FIXME: this assumes the blocksize == count, but the calling
304                  *        function will detect this as an error for now */
305                 bh = extN_bread(NULL, inode,
306                                 *offset >> inode->i_sb->s_blocksize_bits,
307                                 0, &rc);
308
309                 if (bh) {
310                         memcpy(buf, bh->b_data, inode->i_blksize);
311                         brelse(bh);
312                         rc = inode->i_blksize;
313                 }
314         }
315
316         return rc;
317 }
318
319 static void fsfilt_extN_cb_func(struct journal_callback *jcb, int error)
320 {
321         struct fsfilt_cb_data *fcb = (struct fsfilt_cb_data *)jcb;
322
323         fcb->cb_func(fcb->cb_obd, fcb->cb_last_rcvd, error);
324
325         kmem_cache_free(fcb_cache, fcb);
326         --fcb_cache_count;
327 }
328
329 static int fsfilt_extN_set_last_rcvd(struct obd_device *obd, __u64 last_rcvd,
330                                      void *handle, fsfilt_cb_t cb_func)
331 {
332 #ifdef HAVE_JOURNAL_CALLBACK_STATUS
333         struct fsfilt_cb_data *fcb;
334
335         fcb = kmem_cache_alloc(fcb_cache, GFP_NOFS);
336         if (!fcb)
337                 RETURN(-ENOMEM);
338
339         ++fcb_cache_count;
340         fcb->cb_func = cb_func;
341         fcb->cb_obd = obd;
342         fcb->cb_last_rcvd = last_rcvd;
343
344         CDEBUG(D_EXT2, "set callback for last_rcvd: "LPD64"\n", last_rcvd);
345         lock_kernel();
346         /* Note that an "incompatible pointer" warning here is OK for now */
347         journal_callback_set(handle, fsfilt_extN_cb_func,
348                              (struct journal_callback *)fcb);
349         unlock_kernel();
350 #else
351 #warning "no journal callback kernel patch, faking it..."
352         static long next = 0;
353
354         if (time_after(jiffies, next)) {
355                 CERROR("no journal callback kernel patch, faking it...\n");
356                 next = jiffies + 300 * HZ;
357         }
358
359         cb_func(obd, last_rcvd, 0);
360 #endif
361
362         return 0;
363 }
364
365 static int fsfilt_extN_journal_data(struct file *filp)
366 {
367         struct inode *inode = filp->f_dentry->d_inode;
368
369         EXTN_I(inode)->i_flags |= EXTN_JOURNAL_DATA_FL;
370
371         return 0;
372 }
373
374 /*
375  * We need to hack the return value for the free inode counts because
376  * the current EA code requires one filesystem block per inode with EAs,
377  * so it is possible to run out of blocks before we run out of inodes.
378  *
379  * This can be removed when the extN EA code is fixed.
380  */
381 static int fsfilt_extN_statfs(struct super_block *sb, struct obd_statfs *osfs)
382 {
383         struct statfs sfs;
384         int rc = vfs_statfs(sb, &sfs);
385
386         if (!rc && sfs.f_bfree < sfs.f_ffree)
387                 sfs.f_ffree = sfs.f_bfree;
388
389         statfs_pack(osfs, &sfs);
390         return rc;
391 }
392
393 static struct fsfilt_operations fsfilt_extN_ops = {
394         fs_type:                "extN",
395         fs_owner:               THIS_MODULE,
396         fs_start:               fsfilt_extN_start,
397         fs_brw_start:           fsfilt_extN_brw_start,
398         fs_commit:              fsfilt_extN_commit,
399         fs_setattr:             fsfilt_extN_setattr,
400         fs_set_md:              fsfilt_extN_set_md,
401         fs_get_md:              fsfilt_extN_get_md,
402         fs_readpage:            fsfilt_extN_readpage,
403         fs_journal_data:        fsfilt_extN_journal_data,
404         fs_set_last_rcvd:       fsfilt_extN_set_last_rcvd,
405         fs_statfs:              fsfilt_extN_statfs,
406 };
407
408 static int __init fsfilt_extN_init(void)
409 {
410         int rc;
411
412         //rc = extN_xattr_register();
413         fcb_cache = kmem_cache_create("fsfilt_extN_fcb",
414                                       sizeof(struct fsfilt_cb_data), 0,
415                                       0, NULL, NULL);
416         if (!fcb_cache) {
417                 CERROR("error allocating fsfilt journal callback cache\n");
418                 GOTO(out, rc = -ENOMEM);
419         }
420
421         rc = fsfilt_register_ops(&fsfilt_extN_ops);
422
423         if (rc)
424                 kmem_cache_destroy(fcb_cache);
425 out:
426         return rc;
427 }
428
429 static void __exit fsfilt_extN_exit(void)
430 {
431         int rc;
432
433         fsfilt_unregister_ops(&fsfilt_extN_ops);
434         rc = kmem_cache_destroy(fcb_cache);
435
436         if (rc || fcb_cache_count) {
437                 CERROR("can't free fsfilt callback cache: count %d, rc = %d\n",
438                        fcb_cache_count, rc);
439         }
440
441         //rc = extN_xattr_unregister();
442 }
443
444 MODULE_AUTHOR("Cluster File Systems, Inc. <info@clusterfs.com>");
445 MODULE_DESCRIPTION("Lustre extN Filesystem Helper v0.1");
446 MODULE_LICENSE("GPL");
447
448 module_init(fsfilt_extN_init);
449 module_exit(fsfilt_extN_exit);