aboutsummaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorSteve French <sfrench@us.ibm.com>2008-03-01 18:29:55 +0000
committerSteve French <sfrench@us.ibm.com>2008-03-01 18:29:55 +0000
commit0dbd888936a23514716b8d944775bc56f731363a (patch)
treea2c60cdc45bdcbed47680731fa8188bffe58c098 /fs
parent0b442d2c28479332610c46e1a74e5638ab63a97d (diff)
parentd395991c117d43bfca97101a931a41d062a93852 (diff)
Merge branch 'master' of /pub/scm/linux/kernel/git/torvalds/linux-2.6
Diffstat (limited to 'fs')
-rw-r--r--fs/bio.c2
-rw-r--r--fs/block_dev.c201
-rw-r--r--fs/dlm/rcom.c2
-rw-r--r--fs/efs/dir.c2
-rw-r--r--fs/efs/efs.h140
-rw-r--r--fs/efs/file.c2
-rw-r--r--fs/efs/inode.c4
-rw-r--r--fs/efs/namei.c2
-rw-r--r--fs/efs/super.c7
-rw-r--r--fs/efs/symlink.c2
-rw-r--r--fs/ext4/dir.c2
-rw-r--r--fs/ext4/extents.c59
-rw-r--r--fs/ext4/ialloc.c22
-rw-r--r--fs/ext4/inode.c56
-rw-r--r--fs/ext4/mballoc.c80
-rw-r--r--fs/ext4/migrate.c5
-rw-r--r--fs/ext4/namei.c18
-rw-r--r--fs/ext4/resize.c1
-rw-r--r--fs/fuse/dir.c2
-rw-r--r--fs/lockd/svc.c2
-rw-r--r--fs/nfs/callback.c3
-rw-r--r--fs/nfs/callback_xdr.c6
-rw-r--r--fs/nfs/delegation.c2
-rw-r--r--fs/nfs/idmap.c2
-rw-r--r--fs/nfs/nfs4state.c2
-rw-r--r--fs/nfsd/nfsfh.c2
-rw-r--r--fs/proc/base.c28
-rw-r--r--fs/proc/task_mmu.c2
-rw-r--r--fs/ufs/util.h2
-rw-r--r--fs/xfs/Kbuild6
-rw-r--r--fs/xfs/Makefile118
-rw-r--r--fs/xfs/Makefile-linux-2.6117
-rw-r--r--fs/xfs/linux-2.6/xfs_super.c14
-rw-r--r--fs/xfs/xfs_bit.c103
-rw-r--r--fs/xfs/xfs_bit.h27
-rw-r--r--fs/xfs/xfs_clnt.h2
-rw-r--r--fs/xfs/xfs_ialloc.c2
-rw-r--r--fs/xfs/xfs_mount.h2
-rw-r--r--fs/xfs/xfs_rtalloc.c19
-rw-r--r--fs/xfs/xfs_vfsops.c4
40 files changed, 606 insertions, 468 deletions
diff --git a/fs/bio.c b/fs/bio.c
index 242e409dab4..3312fcc3c09 100644
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -903,7 +903,7 @@ void bio_set_pages_dirty(struct bio *bio)
}
}
-void bio_release_pages(struct bio *bio)
+static void bio_release_pages(struct bio *bio)
{
struct bio_vec *bvec = bio->bi_io_vec;
int i;
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 67fe72ce6ac..7d822fae776 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -31,6 +31,8 @@ struct bdev_inode {
struct inode vfs_inode;
};
+static const struct address_space_operations def_blk_aops;
+
static inline struct bdev_inode *BDEV_I(struct inode *inode)
{
return container_of(inode, struct bdev_inode, vfs_inode);
@@ -171,203 +173,6 @@ blkdev_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
iov, offset, nr_segs, blkdev_get_blocks, NULL);
}
-#if 0
-static void blk_end_aio(struct bio *bio, int error)
-{
- struct kiocb *iocb = bio->bi_private;
- atomic_t *bio_count = &iocb->ki_bio_count;
-
- if (bio_data_dir(bio) == READ)
- bio_check_pages_dirty(bio);
- else {
- bio_release_pages(bio);
- bio_put(bio);
- }
-
- /* iocb->ki_nbytes stores error code from LLDD */
- if (error)
- iocb->ki_nbytes = -EIO;
-
- if (atomic_dec_and_test(bio_count)) {
- if ((long)iocb->ki_nbytes < 0)
- aio_complete(iocb, iocb->ki_nbytes, 0);
- else
- aio_complete(iocb, iocb->ki_left, 0);
- }
-
- return 0;
-}
-
-#define VEC_SIZE 16
-struct pvec {
- unsigned short nr;
- unsigned short idx;
- struct page *page[VEC_SIZE];
-};
-
-#define PAGES_SPANNED(addr, len) \
- (DIV_ROUND_UP((addr) + (len), PAGE_SIZE) - (addr) / PAGE_SIZE);
-
-/*
- * get page pointer for user addr, we internally cache struct page array for
- * (addr, count) range in pvec to avoid frequent call to get_user_pages. If
- * internal page list is exhausted, a batch count of up to VEC_SIZE is used
- * to get next set of page struct.
- */
-static struct page *blk_get_page(unsigned long addr, size_t count, int rw,
- struct pvec *pvec)
-{
- int ret, nr_pages;
- if (pvec->idx == pvec->nr) {
- nr_pages = PAGES_SPANNED(addr, count);
- nr_pages = min(nr_pages, VEC_SIZE);
- down_read(&current->mm->mmap_sem);
- ret = get_user_pages(current, current->mm, addr, nr_pages,
- rw == READ, 0, pvec->page, NULL);
- up_read(&current->mm->mmap_sem);
- if (ret < 0)
- return ERR_PTR(ret);
- pvec->nr = ret;
- pvec->idx = 0;
- }
- return pvec->page[pvec->idx++];
-}
-
-/* return a page back to pvec array */
-static void blk_unget_page(struct page *page, struct pvec *pvec)
-{
- pvec->page[--pvec->idx] = page;
-}
-
-static ssize_t
-blkdev_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
- loff_t pos, unsigned long nr_segs)
-{
- struct inode *inode = iocb->ki_filp->f_mapping->host;
- unsigned blkbits = blksize_bits(bdev_hardsect_size(I_BDEV(inode)));
- unsigned blocksize_mask = (1 << blkbits) - 1;
- unsigned long seg = 0; /* iov segment iterator */
- unsigned long nvec; /* number of bio vec needed */
- unsigned long cur_off; /* offset into current page */
- unsigned long cur_len; /* I/O len of current page, up to PAGE_SIZE */
-
- unsigned long addr; /* user iovec address */
- size_t count; /* user iovec len */
- size_t nbytes = iocb->ki_nbytes = iocb->ki_left; /* total xfer size */
- loff_t size; /* size of block device */
- struct bio *bio;
- atomic_t *bio_count = &iocb->ki_bio_count;
- struct page *page;
- struct pvec pvec;
-
- pvec.nr = 0;
- pvec.idx = 0;
-
- if (pos & blocksize_mask)
- return -EINVAL;
-
- size = i_size_read(inode);
- if (pos + nbytes > size) {
- nbytes = size - pos;
- iocb->ki_left = nbytes;
- }
-
- /*
- * check first non-zero iov alignment, the remaining
- * iov alignment is checked inside bio loop below.
- */
- do {
- addr = (unsigned long) iov[seg].iov_base;
- count = min(iov[seg].iov_len, nbytes);
- if (addr & blocksize_mask || count & blocksize_mask)
- return -EINVAL;
- } while (!count && ++seg < nr_segs);
- atomic_set(bio_count, 1);
-
- while (nbytes) {
- /* roughly estimate number of bio vec needed */
- nvec = (nbytes + PAGE_SIZE - 1) / PAGE_SIZE;
- nvec = max(nvec, nr_segs - seg);
- nvec = min(nvec, (unsigned long) BIO_MAX_PAGES);
-
- /* bio_alloc should not fail with GFP_KERNEL flag */
- bio = bio_alloc(GFP_KERNEL, nvec);
- bio->bi_bdev = I_BDEV(inode);
- bio->bi_end_io = blk_end_aio;
- bio->bi_private = iocb;
- bio->bi_sector = pos >> blkbits;
-same_bio:
- cur_off = addr & ~PAGE_MASK;
- cur_len = PAGE_SIZE - cur_off;
- if (count < cur_len)
- cur_len = count;
-
- page = blk_get_page(addr, count, rw, &pvec);
- if (unlikely(IS_ERR(page)))
- goto backout;
-
- if (bio_add_page(bio, page, cur_len, cur_off)) {
- pos += cur_len;
- addr += cur_len;
- count -= cur_len;
- nbytes -= cur_len;
-
- if (count)
- goto same_bio;
- while (++seg < nr_segs) {
- addr = (unsigned long) iov[seg].iov_base;
- count = iov[seg].iov_len;
- if (!count)
- continue;
- if (unlikely(addr & blocksize_mask ||
- count & blocksize_mask)) {
- page = ERR_PTR(-EINVAL);
- goto backout;
- }
- count = min(count, nbytes);
- goto same_bio;
- }
- } else {
- blk_unget_page(page, &pvec);
- }
-
- /* bio is ready, submit it */
- if (rw == READ)
- bio_set_pages_dirty(bio);
- atomic_inc(bio_count);
- submit_bio(rw, bio);
- }
-
-completion:
- iocb->ki_left -= nbytes;
- nbytes = iocb->ki_left;
- iocb->ki_pos += nbytes;
-
- blk_run_address_space(inode->i_mapping);
- if (atomic_dec_and_test(bio_count))
- aio_complete(iocb, nbytes, 0);
-
- return -EIOCBQUEUED;
-
-backout:
- /*
- * back out nbytes count constructed so far for this bio,
- * we will throw away current bio.
- */
- nbytes += bio->bi_size;
- bio_release_pages(bio);
- bio_put(bio);
-
- /*
- * if no bio was submmitted, return the error code.
- * otherwise, proceed with pending I/O completion.
- */
- if (atomic_read(bio_count) == 1)
- return PTR_ERR(page);
- goto completion;
-}
-#endif
-
static int blkdev_writepage(struct page *page, struct writeback_control *wbc)
{
return block_write_full_page(page, blkdev_get_block, wbc);
@@ -1334,7 +1139,7 @@ static long block_ioctl(struct file *file, unsigned cmd, unsigned long arg)
return blkdev_ioctl(file->f_mapping->host, file, cmd, arg);
}
-const struct address_space_operations def_blk_aops = {
+static const struct address_space_operations def_blk_aops = {
.readpage = blkdev_readpage,
.writepage = blkdev_writepage,
.sync_page = block_sync_page,
diff --git a/fs/dlm/rcom.c b/fs/dlm/rcom.c
index 035e6f9990b..67522c268c1 100644
--- a/fs/dlm/rcom.c
+++ b/fs/dlm/rcom.c
@@ -215,6 +215,8 @@ int dlm_rcom_names(struct dlm_ls *ls, int nodeid, char *last_name, int last_len)
ls->ls_recover_nodeid = nodeid;
if (nodeid == dlm_our_nodeid()) {
+ ls->ls_recover_buf->rc_header.h_length =
+ dlm_config.ci_buffer_size;
dlm_copy_master_names(ls, last_name, last_len,
ls->ls_recover_buf->rc_buf,
max_size, nodeid);
diff --git a/fs/efs/dir.c b/fs/efs/dir.c
index dfb5cb40021..49308a29798 100644
--- a/fs/efs/dir.c
+++ b/fs/efs/dir.c
@@ -5,8 +5,8 @@
*/
#include <linux/buffer_head.h>
-#include <linux/efs_fs.h>
#include <linux/smp_lock.h>
+#include "efs.h"
static int efs_readdir(struct file *, void *, filldir_t);
diff --git a/fs/efs/efs.h b/fs/efs/efs.h
new file mode 100644
index 00000000000..d8305b582ab
--- /dev/null
+++ b/fs/efs/efs.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 1999 Al Smith
+ *
+ * Portions derived from work (c) 1995,1996 Christian Vogelgsang.
+ * Portions derived from IRIX header files (c) 1988 Silicon Graphics
+ */
+#ifndef _EFS_EFS_H_
+#define _EFS_EFS_H_
+
+#include <linux/fs.h>
+#include <asm/uaccess.h>
+
+#define EFS_VERSION "1.0a"
+
+static const char cprt[] = "EFS: "EFS_VERSION" - (c) 1999 Al Smith <Al.Smith@aeschi.ch.eu.org>";
+
+
+/* 1 block is 512 bytes */
+#define EFS_BLOCKSIZE_BITS 9
+#define EFS_BLOCKSIZE (1 << EFS_BLOCKSIZE_BITS)
+
+typedef int32_t efs_block_t;
+typedef uint32_t efs_ino_t;
+
+#define EFS_DIRECTEXTENTS 12
+
+/*
+ * layout of an extent, in memory and on disk. 8 bytes exactly.
+ */
+typedef union extent_u {
+ unsigned char raw[8];
+ struct extent_s {
+ unsigned int ex_magic:8; /* magic # (zero) */
+ unsigned int ex_bn:24; /* basic block */
+ unsigned int ex_length:8; /* numblocks in this extent */
+ unsigned int ex_offset:24; /* logical offset into file */
+ } cooked;
+} efs_extent;
+
+typedef struct edevs {
+ __be16 odev;
+ __be32 ndev;
+} efs_devs;
+
+/*
+ * extent based filesystem inode as it appears on disk. The efs inode
+ * is exactly 128 bytes long.
+ */
+struct efs_dinode {
+ __be16 di_mode; /* mode and type of file */
+ __be16 di_nlink; /* number of links to file */
+ __be16 di_uid; /* owner's user id */
+ __be16 di_gid; /* owner's group id */
+ __be32 di_size; /* number of bytes in file */
+ __be32 di_atime; /* time last accessed */
+ __be32 di_mtime; /* time last modified */
+ __be32 di_ctime; /* time created */
+ __be32 di_gen; /* generation number */
+ __be16 di_numextents; /* # of extents */
+ u_char di_version; /* version of inode */
+ u_char di_spare; /* spare - used by AFS */
+ union di_addr {
+ efs_extent di_extents[EFS_DIRECTEXTENTS];
+ efs_devs di_dev; /* device for IFCHR/IFBLK */
+ } di_u;
+};
+
+/* efs inode storage in memory */
+struct efs_inode_info {
+ int numextents;
+ int lastextent;
+
+ efs_extent extents[EFS_DIRECTEXTENTS];
+ struct inode vfs_inode;
+};
+
+#include <linux/efs_fs_sb.h>
+
+#define EFS_DIRBSIZE_BITS EFS_BLOCKSIZE_BITS
+#define EFS_DIRBSIZE (1 << EFS_DIRBSIZE_BITS)
+
+struct efs_dentry {
+ __be32 inode;
+ unsigned char namelen;
+ char name[3];
+};
+
+#define EFS_DENTSIZE (sizeof(struct efs_dentry) - 3 + 1)
+#define EFS_MAXNAMELEN ((1 << (sizeof(char) * 8)) - 1)
+
+#define EFS_DIRBLK_HEADERSIZE 4
+#define EFS_DIRBLK_MAGIC 0xbeef /* moo */
+
+struct efs_dir {
+ __be16 magic;
+ unsigned char firstused;
+ unsigned char slots;
+
+ unsigned char space[EFS_DIRBSIZE - EFS_DIRBLK_HEADERSIZE];
+};
+
+#define EFS_MAXENTS \
+ ((EFS_DIRBSIZE - EFS_DIRBLK_HEADERSIZE) / \
+ (EFS_DENTSIZE + sizeof(char)))
+
+#define EFS_SLOTAT(dir, slot) EFS_REALOFF((dir)->space[slot])
+
+#define EFS_REALOFF(offset) ((offset << 1))
+
+
+static inline struct efs_inode_info *INODE_INFO(struct inode *inode)
+{
+ return container_of(inode, struct efs_inode_info, vfs_inode);
+}
+
+static inline struct efs_sb_info *SUPER_INFO(struct super_block *sb)
+{
+ return sb->s_fs_info;
+}
+
+struct statfs;
+struct fid;
+
+extern const struct inode_operations efs_dir_inode_operations;
+extern const struct file_operations efs_dir_operations;
+extern const struct address_space_operations efs_symlink_aops;
+
+extern struct inode *efs_iget(struct super_block *, unsigned long);
+extern efs_block_t efs_map_block(struct inode *, efs_block_t);
+extern int efs_get_block(struct inode *, sector_t, struct buffer_head *, int);
+
+extern struct dentry *efs_lookup(struct inode *, struct dentry *, struct nameidata *);
+extern struct dentry *efs_fh_to_dentry(struct super_block *sb, struct fid *fid,
+ int fh_len, int fh_type);
+extern struct dentry *efs_fh_to_parent(struct super_block *sb, struct fid *fid,
+ int fh_len, int fh_type);
+extern struct dentry *efs_get_parent(struct dentry *);
+extern int efs_bmap(struct inode *, int);
+
+#endif /* _EFS_EFS_H_ */
diff --git a/fs/efs/file.c b/fs/efs/file.c
index 5db20129681..1ccb364ffa6 100644
--- a/fs/efs/file.c
+++ b/fs/efs/file.c
@@ -7,7 +7,7 @@
*/
#include <linux/buffer_head.h>
-#include <linux/efs_fs.h>
+#include "efs.h"
int efs_get_block(struct inode *inode, sector_t iblock,
struct buffer_head *bh_result, int create)
diff --git a/fs/efs/inode.c b/fs/efs/inode.c
index 627c3026946..79e19e5958e 100644
--- a/fs/efs/inode.c
+++ b/fs/efs/inode.c
@@ -7,11 +7,11 @@
* and from work (c) 1998 Mike Shaver.
*/
-#include <linux/efs_fs.h>
-#include <linux/efs_fs_sb.h>
#include <linux/buffer_head.h>
#include <linux/module.h>
#include <linux/fs.h>
+#include "efs.h"
+#include <linux/efs_fs_sb.h>
static int efs_readpage(struct file *file, struct page *page)
{
diff --git a/fs/efs/namei.c b/fs/efs/namei.c
index e26704742d4..3a404e7fad5 100644
--- a/fs/efs/namei.c
+++ b/fs/efs/namei.c
@@ -8,9 +8,9 @@
#include <linux/buffer_head.h>
#include <linux/string.h>
-#include <linux/efs_fs.h>
#include <linux/smp_lock.h>
#include <linux/exportfs.h>
+#include "efs.h"
static efs_ino_t efs_find_entry(struct inode *inode, const char *name, int len) {
diff --git a/fs/efs/super.c b/fs/efs/super.c
index 14082405cdd..d733531b55e 100644
--- a/fs/efs/super.c
+++ b/fs/efs/super.c
@@ -8,14 +8,15 @@
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/efs_fs.h>
-#include <linux/efs_vh.h>
-#include <linux/efs_fs_sb.h>
#include <linux/exportfs.h>
#include <linux/slab.h>
#include <linux/buffer_head.h>
#include <linux/vfs.h>
+#include "efs.h"
+#include <linux/efs_vh.h>
+#include <linux/efs_fs_sb.h>
+
static int efs_statfs(struct dentry *dentry, struct kstatfs *buf);
static int efs_fill_super(struct super_block *s, void *d, int silent);
diff --git a/fs/efs/symlink.c b/fs/efs/symlink.c
index 1d30d2ff440..41911ec83aa 100644
--- a/fs/efs/symlink.c
+++ b/fs/efs/symlink.c
@@ -7,10 +7,10 @@
*/
#include <linux/string.h>
-#include <linux/efs_fs.h>
#include <linux/pagemap.h>
#include <linux/buffer_head.h>
#include <linux/smp_lock.h>
+#include "efs.h"
static int efs_symlink_readpage(struct file *file, struct page *page)
{
diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c
index 33888bb5814..2c23bade9aa 100644
--- a/fs/ext4/dir.c
+++ b/fs/ext4/dir.c
@@ -46,7 +46,7 @@ const struct file_operations ext4_dir_operations = {
#ifdef CONFIG_COMPAT
.compat_ioctl = ext4_compat_ioctl,
#endif
- .fsync = ext4_sync_file, /* BKL held */
+ .fsync = ext4_sync_file,
.release = ext4_release_dir,
};
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index bc7081f1fbe..9ae6e67090c 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -148,6 +148,7 @@ static ext4_fsblk_t ext4_ext_find_goal(struct inode *inode,
{
struct ext4_inode_info *ei = EXT4_I(inode);
ext4_fsblk_t bg_start;
+ ext4_fsblk_t last_block;
ext4_grpblk_t colour;
int depth;
@@ -169,8 +170,13 @@ static ext4_fsblk_t ext4_ext_find_goal(struct inode *inode,
/* OK. use inode's group */
bg_start = (ei->i_block_group * EXT4_BLOCKS_PER_GROUP(inode->i_sb)) +
le32_to_cpu(EXT4_SB(inode->i_sb)->s_es->s_first_data_block);
- colour = (current->pid % 16) *
+ last_block = ext4_blocks_count(EXT4_SB(inode->i_sb)->s_es) - 1;
+
+ if (bg_start + EXT4_BLOCKS_PER_GROUP(inode->i_sb) <= last_block)
+ colour = (current->pid % 16) *
(EXT4_BLOCKS_PER_GROUP(inode->i_sb) / 16);
+ else
+ colour = (current->pid % 16) * ((last_block - bg_start) / 16);
return bg_start + colour + block;
}
@@ -349,7 +355,7 @@ static void ext4_ext_show_leaf(struct inode *inode, struct ext4_ext_path *path)
#define ext4_ext_show_leaf(inode,path)
#endif
-static void ext4_ext_drop_refs(struct ext4_ext_path *path)
+void ext4_ext_drop_refs(struct ext4_ext_path *path)
{
int depth = path->p_depth;
int i;
@@ -2168,6 +2174,10 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
newblock = iblock - ee_block + ext_pblock(ex);
ex2 = ex;
+ err = ext4_ext_get_access(handle, inode, path + depth);
+ if (err)
+ goto out;
+
/* ex1: ee_block to iblock - 1 : uninitialized */
if (iblock > ee_block) {
ex1 = ex;
@@ -2200,16 +2210,20 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
newdepth = ext_depth(inode);
if (newdepth != depth) {
depth = newdepth;
- path = ext4_ext_find_extent(inode, iblock, NULL);
+ ext4_ext_drop_refs(path);
+ path = ext4_ext_find_extent(inode, iblock, path);
if (IS_ERR(path)) {
err = PTR_ERR(path);
- path = NULL;
goto out;
}
eh = path[depth].p_hdr;
ex = path[depth].p_ext;
if (ex2 != &newex)
ex2 = ex;
+
+ err = ext4_ext_get_access(handle, inode, path + depth);
+ if (err)
+ goto out;
}
allocated = max_blocks;
}
@@ -2230,9 +2244,6 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
ex2->ee_len = cpu_to_le16(allocated);
if (ex2 != ex)
goto insert;
- err = ext4_ext_get_access(handle, inode, path + depth);
- if (err)
- goto out;
/*
* New (initialized) extent starts from the first block
* in the current extent. i.e., ex2 == ex
@@ -2276,9 +2287,22 @@ out:
}
/*
+ * Block allocation/map/preallocation routine for extents based files
+ *
+ *
* Need to be called with
* down_read(&EXT4_I(inode)->i_data_sem) if not allocating file system block
* (ie, create is zero). Otherwise down_write(&EXT4_I(inode)->i_data_sem)
+ *
+ * return > 0, number of of blocks already mapped/allocated
+ * if create == 0 and these are pre-allocated blocks
+ * buffer head is unmapped
+ * otherwise blocks are mapped
+ *
+ * return = 0, if plain look up failed (blocks have not been allocated)
+ * buffer head is unmapped
+ *
+ * return < 0, error case.
*/
int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
ext4_lblk_t iblock,
@@ -2623,7 +2647,7 @@ long ext4_fallocate(struct inode *inode, int mode, loff_t offset, loff_t len)
* modify 1 super block, 1 block bitmap and 1 group descriptor.
*/
credits = EXT4_DATA_TRANS_BLOCKS(inode->i_sb) + 3;
- down_write((&EXT4_I(inode)->i_data_sem));
+ mutex_lock(&inode->i_mutex);
retry:
while (ret >= 0 && ret < max_blocks) {
block = block + ret;
@@ -2634,16 +2658,17 @@ retry:
break;
}
- ret = ext4_ext_get_blocks(handle, inode, block,
+ ret = ext4_get_blocks_wrap(handle, inode, block,
max_blocks, &map_bh,
EXT4_CREATE_UNINITIALIZED_EXT, 0);
- WARN_ON(ret <= 0);
if (ret <= 0) {
- ext4_error(inode->i_sb, "ext4_fallocate",
- "ext4_ext_get_blocks returned error: "
- "inode#%lu, block=%u, max_blocks=%lu",
+#ifdef EXT4FS_DEBUG
+ WARN_ON(ret <= 0);
+ printk(KERN_ERR "%s: ext4_ext_get_blocks "
+ "returned error inode#%lu, block=%u, "
+ "max_blocks=%lu", __func__,
inode->i_ino, block, max_blocks);
- ret = -EIO;
+#endif
ext4_mark_inode_dirty(handle, inode);
ret2 = ext4_journal_stop(handle);
break;
@@ -2680,7 +2705,6 @@ retry:
if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
goto retry;
- up_write((&EXT4_I(inode)->i_data_sem));
/*
* Time to update the file size.
* Update only when preallocation was requested beyond the file size.
@@ -2692,21 +2716,18 @@ retry:
* if no error, we assume preallocation succeeded
* completely
*/
- mutex_lock(&inode->i_mutex);
i_size_write(inode, offset + len);
EXT4_I(inode)->i_disksize = i_size_read(inode);
- mutex_unlock(&inode->i_mutex);
} else if (ret < 0 && nblocks) {
/* Handle partial allocation scenario */
loff_t newsize;
- mutex_lock(&inode->i_mutex);
newsize = (nblocks << blkbits) + i_size_read(inode);
i_size_write(inode, EXT4_BLOCK_ALIGN(newsize, blkbits));
EXT4_I(inode)->i_disksize = i_size_read(inode);
- mutex_unlock(&inode->i_mutex);
}
}
+ mutex_unlock(&inode->i_mutex);
return ret > 0 ? ret2 : ret;
}
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
index da18a74b966..8036b9b5376 100644
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -702,7 +702,12 @@ got:
ei->i_dir_start_lookup = 0;
ei->i_disksize = 0;
- ei->i_flags = EXT4_I(dir)->i_flags & ~EXT4_INDEX_FL;
+ /*
+ * Don't inherit extent flag from directory. We set extent flag on
+ * newly created directory and file only if -o extent mount option is
+ * specified
+ */
+ ei->i_flags = EXT4_I(dir)->i_flags & ~(EXT4_INDEX_FL|EXT4_EXTENTS_FL);
if (S_ISLNK(mode))
ei->i_flags &= ~(EXT4_IMMUTABLE_FL|EXT4_APPEND_FL);
/* dirsync only applies to directories */
@@ -745,12 +750,15 @@ got:
goto fail_free_drop;
}
if (test_opt(sb, EXTENTS)) {
- EXT4_I(inode)->i_flags |= EXT4_EXTENTS_FL;
- ext4_ext_tree_init(handle, inode);
- err = ext4_update_incompat_feature(handle, sb,
- EXT4_FEATURE_INCOMPAT_EXTENTS);
- if (err)
- goto fail;
+ /* set extent flag only for directory and file */
+ if (S_ISDIR(mode) || S_ISREG(mode)) {
+ EXT4_I(inode)->i_flags |= EXT4_EXTENTS_FL;
+ ext4_ext_tree_init(handle, inode);
+ err = ext4_update_incompat_feature(handle, sb,
+ EXT4_FEATURE_INCOMPAT_EXTENTS);
+ if (err)
+ goto fail;
+ }
}
ext4_debug("allocating inode %lu\n", inode->i_ino);
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 7dd9b50d5eb..945cbf6cb1f 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -403,6 +403,7 @@ static ext4_fsblk_t ext4_find_near(struct inode *inode, Indirect *ind)
__le32 *start = ind->bh ? (__le32*) ind->bh->b_data : ei->i_data;
__le32 *p;
ext4_fsblk_t bg_start;
+ ext4_fsblk_t last_block;
ext4_grpblk_t colour;
/* Try to find previous block */
@@ -420,8 +421,13 @@ static ext4_fsblk_t ext4_find_near(struct inode *inode, Indirect *ind)
* into the same cylinder group then.
*/
bg_start = ext4_group_first_block_no(inode->i_sb, ei->i_block_group);
- colour = (current->pid % 16) *
+ last_block = ext4_blocks_count(EXT4_SB(inode->i_sb)->s_es) - 1;
+
+ if (bg_start + EXT4_BLOCKS_PER_GROUP(inode->i_sb) <= last_block)
+ colour = (current->pid % 16) *
(EXT4_BLOCKS_PER_GROUP(inode->i_sb) / 16);
+ else
+ colour = (current->pid % 16) * ((last_block - bg_start) / 16);
return bg_start + colour;
}
@@ -768,7 +774,6 @@ err_out:
*
* `handle' can be NULL if create == 0.
*
- * The BKL may not be held on entry here. Be sure to take it early.
* return > 0, # of blocks mapped or allocated.
* return = 0, if plain lookup failed.
* return < 0, error case.
@@ -903,11 +908,38 @@ out:
*/
#define DIO_CREDITS 25
+
+/*
+ *
+ *
+ * ext4_ext4 get_block() wrapper function
+ * It will do a look up first, and returns if the blocks already mapped.
+ * Otherwise it takes the write lock of the i_data_sem and allocate blocks
+ * and store the allocated blocks in the result buffer head and mark it
+ * mapped.
+ *
+ * If file type is extents based, it will call ext4_ext_get_blocks(),
+ * Otherwise, call with ext4_get_blocks_handle() to handle indirect mapping
+ * based files
+ *
+ * On success, it returns the number of blocks being mapped or allocate.
+ * if create==0 and the blocks are pre-allocated and uninitialized block,
+ * the result buffer head is unmapped. If the create ==1, it will make sure
+ * the buffer head is mapped.
+ *
+ * It returns 0 if plain look up failed (blocks have not been allocated), in
+ * that casem, buffer head is unmapped
+ *
+ * It returns the error in case of allocation failure.
+ */
int ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, sector_t block,
unsigned long max_blocks, struct buffer_head *bh,
int create, int extend_disksize)
{
int retval;
+
+ clear_buffer_mapped(bh);
+
/*
* Try to see if we can get the block without requesting
* for new file system block.
@@ -921,12 +953,26 @@ int ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, sector_t block,
inode, block, max_blocks, bh, 0, 0);