1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
4 * lustre/lib/fsfilt_extN.c
5 * Lustre filesystem abstraction routines
7 * Copyright (C) 2002 Cluster File Systems, Inc.
8 * Author: Andreas Dilger <adilger@clusterfs.com>
10 * This file is part of Lustre, http://www.lustre.org.
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.
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.
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.
26 #define DEBUG_SUBSYSTEM S_FILTER
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>
41 static kmem_cache_t *fcb_cache;
42 static int fcb_cache_count;
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 */
51 #define EXTN_XATTR_INDEX_LUSTRE 5
52 #define XATTR_LUSTRE_MDS_OBJID "system.lustre_mds_objid"
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
60 static void *fsfilt_extN_start(struct inode *inode, int op)
62 /* For updates to the last recieved file */
63 int nblocks = EXTN_DATA_TRANS_BLOCKS;
68 case FSFILT_OP_UNLINK:
69 nblocks += EXTN_DELETE_TRANS_BLOCKS;
71 case FSFILT_OP_RENAME:
72 /* modify additional directory */
73 nblocks += EXTN_DATA_TRANS_BLOCKS;
75 case FSFILT_OP_SYMLINK:
76 /* additional block + block bitmap + GDT for long symlink */
79 case FSFILT_OP_CREATE:
82 /* modify one inode + block bitmap + GDT */
86 /* modify parent directory */
87 nblocks += EXTN_INDEX_EXTRA_TRANS_BLOCKS+EXTN_DATA_TRANS_BLOCKS;
89 case FSFILT_OP_SETATTR:
90 /* Setattr on inode */
93 default: CERROR("unknown transaction start op %d\n", op);
97 LASSERT(!current->journal_info);
99 handle = journal_start(EXTN_JOURNAL(inode), nblocks);
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.
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.
115 * With N blocks per page and P pages, for each inode we have at most:
117 * min(N*P, blocksize/4 + 1) dindirect blocks
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
125 * 2 * EXTN_SINGLEDATA_TRANS_BLOCKS for the quota files
127 static int fsfilt_extN_credits_needed(int objcount, struct fsfilt_objinfo *fso)
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;
134 int needed = objcount + 1;
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;
142 nbitmaps += nindir + nblocks;
143 ngdblocks += nindir + nblocks;
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;
154 needed += nbitmaps + ngdblocks;
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.
160 needed += hweight32(sb_any_quota_enabled(sb)) *
161 EXTN_SINGLEDATA_TRANS_BLOCKS;
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.
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.
181 static void *fsfilt_extN_brw_start(int objcount, struct fsfilt_objinfo *fso,
182 int niocount, struct niobuf_remote *nb)
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);
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).
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.
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;
210 handle = journal_start(journal, needed);
213 CERROR("can't get handle for %d credits: rc = %ld\n", needed,
219 static int fsfilt_extN_commit(struct inode *inode, void *handle)
224 rc = journal_stop((handle_t *)handle);
230 static int fsfilt_extN_setattr(struct dentry *dentry, void *handle,
233 struct inode *inode = dentry->d_inode;
237 if (inode->i_op->setattr)
238 rc = inode->i_op->setattr(dentry, iattr);
240 rc = inode_setattr(inode, iattr);
247 static int fsfilt_extN_set_md(struct inode *inode, void *handle,
248 void *lmm, int lmm_size)
254 rc = extN_xattr_set(handle, inode, EXTN_XATTR_INDEX_LUSTRE,
255 XATTR_LUSTRE_MDS_OBJID, lmm, lmm_size, 0);
260 CERROR("error adding MD data to inode %lu: rc = %d\n",
262 if (rc != -ENOSPC) LBUG();
267 static int fsfilt_extN_get_md(struct inode *inode, void *lmm, int size)
273 rc = extN_xattr_get(inode, EXTN_XATTR_INDEX_LUSTRE,
274 XATTR_LUSTRE_MDS_OBJID, lmm, size);
278 /* This gives us the MD size */
280 return (rc == -ENODATA) ? 0 : rc;
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;
292 static ssize_t fsfilt_extN_readpage(struct file *file, char *buf, size_t count,
295 struct inode *inode = file->f_dentry->d_inode;
298 if (S_ISREG(inode->i_mode))
299 rc = file->f_op->read(file, buf, count, offset);
301 struct buffer_head *bh;
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,
310 memcpy(buf, bh->b_data, inode->i_blksize);
312 rc = inode->i_blksize;
319 static void fsfilt_extN_cb_func(struct journal_callback *jcb, int error)
321 struct fsfilt_cb_data *fcb = (struct fsfilt_cb_data *)jcb;
323 fcb->cb_func(fcb->cb_obd, fcb->cb_last_rcvd, error);
325 kmem_cache_free(fcb_cache, fcb);
329 static int fsfilt_extN_set_last_rcvd(struct obd_device *obd, __u64 last_rcvd,
330 void *handle, fsfilt_cb_t cb_func)
332 #ifdef HAVE_JOURNAL_CALLBACK_STATUS
333 struct fsfilt_cb_data *fcb;
335 fcb = kmem_cache_alloc(fcb_cache, GFP_NOFS);
340 fcb->cb_func = cb_func;
342 fcb->cb_last_rcvd = last_rcvd;
344 CDEBUG(D_EXT2, "set callback for last_rcvd: "LPD64"\n", last_rcvd);
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);
351 #warning "no journal callback kernel patch, faking it..."
352 static long next = 0;
354 if (time_after(jiffies, next)) {
355 CERROR("no journal callback kernel patch, faking it...\n");
356 next = jiffies + 300 * HZ;
359 cb_func(obd, last_rcvd, 0);
365 static int fsfilt_extN_journal_data(struct file *filp)
367 struct inode *inode = filp->f_dentry->d_inode;
369 EXTN_I(inode)->i_flags |= EXTN_JOURNAL_DATA_FL;
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.
379 * This can be removed when the extN EA code is fixed.
381 static int fsfilt_extN_statfs(struct super_block *sb, struct obd_statfs *osfs)
384 int rc = vfs_statfs(sb, &sfs);
386 if (!rc && sfs.f_bfree < sfs.f_ffree)
387 sfs.f_ffree = sfs.f_bfree;
389 statfs_pack(osfs, &sfs);
393 static struct fsfilt_operations fsfilt_extN_ops = {
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,
408 static int __init fsfilt_extN_init(void)
412 //rc = extN_xattr_register();
413 fcb_cache = kmem_cache_create("fsfilt_extN_fcb",
414 sizeof(struct fsfilt_cb_data), 0,
417 CERROR("error allocating fsfilt journal callback cache\n");
418 GOTO(out, rc = -ENOMEM);
421 rc = fsfilt_register_ops(&fsfilt_extN_ops);
424 kmem_cache_destroy(fcb_cache);
429 static void __exit fsfilt_extN_exit(void)
433 fsfilt_unregister_ops(&fsfilt_extN_ops);
434 rc = kmem_cache_destroy(fcb_cache);
436 if (rc || fcb_cache_count) {
437 CERROR("can't free fsfilt callback cache: count %d, rc = %d\n",
438 fcb_cache_count, rc);
441 //rc = extN_xattr_unregister();
444 MODULE_AUTHOR("Cluster File Systems, Inc. <info@clusterfs.com>");
445 MODULE_DESCRIPTION("Lustre extN Filesystem Helper v0.1");
446 MODULE_LICENSE("GPL");
448 module_init(fsfilt_extN_init);
449 module_exit(fsfilt_extN_exit);