Change btrfs_map_block to return a structure with mappings for all stripes
[deliverable/linux.git] / fs / btrfs / inode.c
index 515f8b01ab0480e50647209cd47b4ddac25cb915..7ae677d8a6dea67774abd294373e4d9674504825 100644 (file)
@@ -16,6 +16,7 @@
  * Boston, MA 021110-1307, USA.
  */
 
+#include <linux/bio.h>
 #include <linux/buffer_head.h>
 #include <linux/fs.h>
 #include <linux/pagemap.h>
@@ -39,6 +40,7 @@
 #include "btrfs_inode.h"
 #include "ioctl.h"
 #include "print-tree.h"
+#include "volumes.h"
 
 struct btrfs_iget_args {
        u64 ino;
@@ -134,6 +136,7 @@ static int cow_file_range(struct inode *inode, u64 start, u64 end)
                ret = btrfs_insert_file_extent(trans, root, inode->i_ino,
                                               start, ins.objectid, ins.offset,
                                               ins.offset);
+               inode->i_blocks += ins.offset >> 9;
                btrfs_check_file(root, inode);
                num_bytes -= cur_alloc_size;
                alloc_hint = ins.objectid + ins.offset;
@@ -142,6 +145,7 @@ static int cow_file_range(struct inode *inode, u64 start, u64 end)
        btrfs_drop_extent_cache(inode, orig_start,
                                orig_start + orig_num_bytes - 1);
        btrfs_add_ordered_inode(inode);
+       btrfs_update_inode(trans, root, inode);
 out:
        btrfs_end_transaction(trans, root);
        return ret;
@@ -260,11 +264,12 @@ static int run_delalloc_range(struct inode *inode, u64 start, u64 end)
 }
 
 int btrfs_set_bit_hook(struct inode *inode, u64 start, u64 end,
-                      unsigned long bits)
+                      unsigned long old, unsigned long bits)
 {
-       if ((bits & EXTENT_DELALLOC)) {
+       if (!(old & EXTENT_DELALLOC) && (bits & EXTENT_DELALLOC)) {
                struct btrfs_root *root = BTRFS_I(inode)->root;
                spin_lock(&root->fs_info->delalloc_lock);
+               BTRFS_I(inode)->delalloc_bytes += end - start + 1;
                root->fs_info->delalloc_bytes += end - start + 1;
                spin_unlock(&root->fs_info->delalloc_lock);
        }
@@ -272,40 +277,75 @@ int btrfs_set_bit_hook(struct inode *inode, u64 start, u64 end,
 }
 
 int btrfs_clear_bit_hook(struct inode *inode, u64 start, u64 end,
-                        unsigned long bits)
+                        unsigned long old, unsigned long bits)
 {
-       if ((bits & EXTENT_DELALLOC)) {
+       if ((old & EXTENT_DELALLOC) && (bits & EXTENT_DELALLOC)) {
                struct btrfs_root *root = BTRFS_I(inode)->root;
                spin_lock(&root->fs_info->delalloc_lock);
-               root->fs_info->delalloc_bytes -= end - start + 1;
+               if (end - start + 1 > root->fs_info->delalloc_bytes) {
+                       printk("warning: delalloc account %Lu %Lu\n",
+                              end - start + 1, root->fs_info->delalloc_bytes);
+                       root->fs_info->delalloc_bytes = 0;
+                       BTRFS_I(inode)->delalloc_bytes = 0;
+               } else {
+                       root->fs_info->delalloc_bytes -= end - start + 1;
+                       BTRFS_I(inode)->delalloc_bytes -= end - start + 1;
+               }
                spin_unlock(&root->fs_info->delalloc_lock);
        }
        return 0;
 }
 
-int btrfs_writepage_io_hook(struct page *page, u64 start, u64 end)
+int btrfs_merge_bio_hook(struct page *page, unsigned long offset,
+                        size_t size, struct bio *bio)
+{
+       struct btrfs_root *root = BTRFS_I(page->mapping->host)->root;
+       struct btrfs_mapping_tree *map_tree;
+       u64 logical = bio->bi_sector << 9;
+       u64 length = 0;
+       u64 map_length;
+       struct bio_vec *bvec;
+       int i;
+       int ret;
+
+       bio_for_each_segment(bvec, bio, i) {
+               length += bvec->bv_len;
+       }
+       map_tree = &root->fs_info->mapping_tree;
+       map_length = length;
+       ret = btrfs_map_block(map_tree, READ, logical,
+                             &map_length, NULL);
+
+       if (map_length < length + size) {
+               return 1;
+       }
+       return 0;
+}
+
+int btrfs_submit_bio_hook(struct inode *inode, int rw, struct bio *bio)
 {
-       struct inode *inode = page->mapping->host;
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct btrfs_trans_handle *trans;
-       char *kaddr;
        int ret = 0;
-       u64 page_start = (u64)page->index << PAGE_CACHE_SHIFT;
-       size_t offset = start - page_start;
+
+       if (rw != WRITE) {
+               goto mapit;
+       }
+
        if (btrfs_test_opt(root, NODATASUM) ||
-           btrfs_test_flag(inode, NODATASUM))
-               return 0;
+           btrfs_test_flag(inode, NODATASUM)) {
+               goto mapit;
+       }
+
        mutex_lock(&root->fs_info->fs_mutex);
        trans = btrfs_start_transaction(root, 1);
        btrfs_set_trans_block_group(trans, inode);
-       kaddr = kmap(page);
-       btrfs_csum_file_block(trans, root, inode, inode->i_ino,
-                             start, kaddr + offset, end - start + 1);
-       kunmap(page);
+       btrfs_csum_file_blocks(trans, root, inode, bio);
        ret = btrfs_end_transaction(trans, root);
        BUG_ON(ret);
        mutex_unlock(&root->fs_info->fs_mutex);
-       return ret;
+mapit:
+       return btrfs_map_bio(root, rw, bio);
 }
 
 int btrfs_readpage_io_hook(struct page *page, u64 start, u64 end)
@@ -358,8 +398,7 @@ int btrfs_readpage_end_io_hook(struct page *page, u64 start, u64 end,
        if (btrfs_test_opt(root, NODATASUM) ||
            btrfs_test_flag(inode, NODATASUM))
                return 0;
-
-       if (state->start == start) {
+       if (state && state->start == start) {
                private = state->private;
                ret = 0;
        } else {
@@ -395,7 +434,7 @@ void btrfs_read_locked_inode(struct inode *inode)
        struct btrfs_path *path;
        struct extent_buffer *leaf;
        struct btrfs_inode_item *inode_item;
-       struct btrfs_inode_timespec *tspec;
+       struct btrfs_timespec *tspec;
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct btrfs_key location;
        u64 alloc_group_block;
@@ -444,7 +483,8 @@ void btrfs_read_locked_inode(struct inode *inode)
        BTRFS_I(inode)->flags = btrfs_inode_flags(leaf, inode_item);
        if (!BTRFS_I(inode)->block_group) {
                BTRFS_I(inode)->block_group = btrfs_find_block_group(root,
-                                                        NULL, 0, 0, 0);
+                                                NULL, 0,
+                                                BTRFS_BLOCK_GROUP_METADATA, 0);
        }
        btrfs_free_path(path);
        inode_item = NULL;
@@ -454,6 +494,7 @@ void btrfs_read_locked_inode(struct inode *inode)
        switch (inode->i_mode & S_IFMT) {
        case S_IFREG:
                inode->i_mapping->a_ops = &btrfs_aops;
+               inode->i_mapping->backing_dev_info = &root->fs_info->bdi;
                BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops;
                inode->i_fop = &btrfs_file_operations;
                inode->i_op = &btrfs_file_inode_operations;
@@ -468,6 +509,7 @@ void btrfs_read_locked_inode(struct inode *inode)
        case S_IFLNK:
                inode->i_op = &btrfs_symlink_inode_operations;
                inode->i_mapping->a_ops = &btrfs_symlink_aops;
+               inode->i_mapping->backing_dev_info = &root->fs_info->bdi;
                break;
        default:
                init_special_inode(inode, inode->i_mode, rdev);
@@ -828,32 +870,37 @@ search_again:
                                btrfs_set_file_extent_num_bytes(leaf, fi,
                                                         extent_num_bytes);
                                num_dec = (orig_num_bytes -
-                                          extent_num_bytes) >> 9;
-                               if (extent_start != 0) {
-                                       inode->i_blocks -= num_dec;
-                               }
+                                          extent_num_bytes);
+                               if (extent_start != 0)
+                                       dec_i_blocks(inode, num_dec);
                                btrfs_mark_buffer_dirty(leaf);
                        } else {
                                extent_num_bytes =
                                        btrfs_file_extent_disk_num_bytes(leaf,
                                                                         fi);
                                /* FIXME blocksize != 4096 */
-                               num_dec = btrfs_file_extent_num_bytes(leaf,
-                                                                      fi) >> 9;
+                               num_dec = btrfs_file_extent_num_bytes(leaf, fi);
                                if (extent_start != 0) {
                                        found_extent = 1;
-                                       inode->i_blocks -= num_dec;
+                                       dec_i_blocks(inode, num_dec);
                                }
                                root_gen = btrfs_header_generation(leaf);
                                root_owner = btrfs_header_owner(leaf);
                        }
-               } else if (extent_type == BTRFS_FILE_EXTENT_INLINE &&
-                          !del_item) {
-                       u32 newsize = inode->i_size - found_key.offset;
-                       newsize = btrfs_file_extent_calc_inline_size(newsize);
-                       ret = btrfs_truncate_item(trans, root, path,
-                                                 newsize, 1);
-                       BUG_ON(ret);
+               } else if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
+                       if (!del_item) {
+                               u32 newsize = inode->i_size - found_key.offset;
+                               dec_i_blocks(inode, item_end + 1 -
+                                           found_key.offset - newsize);
+                               newsize =
+                                   btrfs_file_extent_calc_inline_size(newsize);
+                               ret = btrfs_truncate_item(trans, root, path,
+                                                         newsize, 1);
+                               BUG_ON(ret);
+                       } else {
+                               dec_i_blocks(inode, item_end + 1 -
+                                            found_key.offset);
+                       }
                }
 delete:
                if (del_item) {
@@ -1000,20 +1047,14 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr)
                struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
 
                u64 mask = root->sectorsize - 1;
-               u64 pos = (inode->i_size + mask) & ~mask;
+               u64 hole_start = (inode->i_size + mask) & ~mask;
                u64 block_end = (attr->ia_size + mask) & ~mask;
-               u64 hole_start;
                u64 hole_size;
                u64 alloc_hint = 0;
 
-               if (attr->ia_size <= pos)
+               if (attr->ia_size <= hole_start)
                        goto out;
 
-               if (pos != inode->i_size)
-                       hole_start = pos + root->sectorsize;
-               else
-                       hole_start = pos;
-
                mutex_lock(&root->fs_info->fs_mutex);
                err = btrfs_check_free_space(root, 1, 0);
                mutex_unlock(&root->fs_info->fs_mutex);
@@ -1022,14 +1063,14 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr)
 
                btrfs_truncate_page(inode->i_mapping, inode->i_size);
 
-               lock_extent(io_tree, pos, block_end - 1, GFP_NOFS);
+               lock_extent(io_tree, hole_start, block_end - 1, GFP_NOFS);
                hole_size = block_end - hole_start;
 
                mutex_lock(&root->fs_info->fs_mutex);
                trans = btrfs_start_transaction(root, 1);
                btrfs_set_trans_block_group(trans, inode);
                err = btrfs_drop_extents(trans, root, inode,
-                                        pos, block_end, pos,
+                                        hole_start, block_end, hole_start,
                                         &alloc_hint);
 
                if (alloc_hint != EXTENT_MAP_INLINE) {
@@ -1043,7 +1084,7 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr)
                }
                btrfs_end_transaction(trans, root);
                mutex_unlock(&root->fs_info->fs_mutex);
-               unlock_extent(io_tree, pos, block_end - 1, GFP_NOFS);
+               unlock_extent(io_tree, hole_start, block_end - 1, GFP_NOFS);
                if (err)
                        return err;
        }
@@ -1223,6 +1264,7 @@ static int btrfs_init_locked_inode(struct inode *inode, void *p)
        struct btrfs_iget_args *args = p;
        inode->i_ino = args->ino;
        BTRFS_I(inode)->root = args->root;
+       BTRFS_I(inode)->delalloc_bytes = 0;
        extent_map_tree_init(&BTRFS_I(inode)->extent_tree, GFP_NOFS);
        extent_io_tree_init(&BTRFS_I(inode)->io_tree,
                             inode->i_mapping, GFP_NOFS);
@@ -1455,7 +1497,10 @@ read_dir_items:
                        di = (struct btrfs_dir_item *)((char *)di + di_len);
                }
        }
-       filp->f_pos = INT_LIMIT(typeof(filp->f_pos));
+       if (key_type == BTRFS_DIR_INDEX_KEY)
+               filp->f_pos = INT_LIMIT(typeof(filp->f_pos));
+       else
+               filp->f_pos++;
 nopos:
        ret = 0;
 err:
@@ -1510,6 +1555,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
 {
        struct inode *inode;
        struct btrfs_inode_item *inode_item;
+       struct btrfs_block_group_cache *new_inode_group;
        struct btrfs_key *location;
        struct btrfs_path *path;
        struct btrfs_inode_ref *ref;
@@ -1529,14 +1575,20 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
        extent_map_tree_init(&BTRFS_I(inode)->extent_tree, GFP_NOFS);
        extent_io_tree_init(&BTRFS_I(inode)->io_tree,
                             inode->i_mapping, GFP_NOFS);
+       BTRFS_I(inode)->delalloc_bytes = 0;
        BTRFS_I(inode)->root = root;
 
        if (mode & S_IFDIR)
                owner = 0;
        else
                owner = 1;
-       group = btrfs_find_block_group(root, group, 0, 0, owner);
-       BTRFS_I(inode)->block_group = group;
+       new_inode_group = btrfs_find_block_group(root, group, 0,
+                                      BTRFS_BLOCK_GROUP_METADATA, owner);
+       if (!new_inode_group) {
+               printk("find_block group failed\n");
+               new_inode_group = group;
+       }
+       BTRFS_I(inode)->block_group = new_inode_group;
        BTRFS_I(inode)->flags = 0;
 
        key[0].objectid = objectid;
@@ -1742,11 +1794,13 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry,
                drop_inode = 1;
        else {
                inode->i_mapping->a_ops = &btrfs_aops;
+               inode->i_mapping->backing_dev_info = &root->fs_info->bdi;
                inode->i_fop = &btrfs_file_operations;
                inode->i_op = &btrfs_file_inode_operations;
                extent_map_tree_init(&BTRFS_I(inode)->extent_tree, GFP_NOFS);
                extent_io_tree_init(&BTRFS_I(inode)->io_tree,
                                     inode->i_mapping, GFP_NOFS);
+               BTRFS_I(inode)->delalloc_bytes = 0;
                BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops;
        }
        dir->i_sb->s_dirt = 1;
@@ -2798,6 +2852,7 @@ static int btrfs_getattr(struct vfsmount *mnt,
        struct inode *inode = dentry->d_inode;
        generic_fillattr(inode, stat);
        stat->blksize = PAGE_CACHE_SIZE;
+       stat->blocks = inode->i_blocks + (BTRFS_I(inode)->delalloc_bytes >> 9);
        return 0;
 }
 
@@ -2908,11 +2963,13 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
                drop_inode = 1;
        else {
                inode->i_mapping->a_ops = &btrfs_aops;
+               inode->i_mapping->backing_dev_info = &root->fs_info->bdi;
                inode->i_fop = &btrfs_file_operations;
                inode->i_op = &btrfs_file_inode_operations;
                extent_map_tree_init(&BTRFS_I(inode)->extent_tree, GFP_NOFS);
                extent_io_tree_init(&BTRFS_I(inode)->io_tree,
                                     inode->i_mapping, GFP_NOFS);
+               BTRFS_I(inode)->delalloc_bytes = 0;
                BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops;
        }
        dir->i_sb->s_dirt = 1;
@@ -2946,6 +3003,7 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
 
        inode->i_op = &btrfs_symlink_inode_operations;
        inode->i_mapping->a_ops = &btrfs_symlink_aops;
+       inode->i_mapping->backing_dev_info = &root->fs_info->bdi;
        inode->i_size = name_len - 1;
        err = btrfs_update_inode(trans, root, inode);
        if (err)
@@ -3005,9 +3063,12 @@ static struct file_operations btrfs_dir_file_operations = {
 
 static struct extent_io_ops btrfs_extent_io_ops = {
        .fill_delalloc = run_delalloc_range,
-       .writepage_io_hook = btrfs_writepage_io_hook,
+       .submit_bio_hook = btrfs_submit_bio_hook,
+       .merge_bio_hook = btrfs_merge_bio_hook,
        .readpage_io_hook = btrfs_readpage_io_hook,
        .readpage_end_io_hook = btrfs_readpage_end_io_hook,
+       .set_bit_hook = btrfs_set_bit_hook,
+       .clear_bit_hook = btrfs_clear_bit_hook,
 };
 
 static struct address_space_operations btrfs_aops = {
This page took 0.032279 seconds and 5 git commands to generate.