Btrfs: fsx delalloc fixes
authorChris Mason <chris.mason@oracle.com>
Thu, 30 Aug 2007 15:54:02 +0000 (11:54 -0400)
committerDavid Woodhouse <dwmw2@hera.kernel.org>
Thu, 30 Aug 2007 15:54:02 +0000 (11:54 -0400)
Signed-off-by: Chris Mason <chris.mason@oracle.com>
fs/btrfs/extent_map.c
fs/btrfs/file.c
fs/btrfs/inode.c

index 6053f9db073911bd36e5dcdae76fb52133193ef9..8ad6f8efc5a003a039c43f47753e278ce182393e 100644 (file)
@@ -77,6 +77,8 @@ EXPORT_SYMBOL(alloc_extent_map);
 
 void free_extent_map(struct extent_map *em)
 {
+       if (!em)
+               return;
        if (atomic_dec_and_test(&em->refs)) {
                WARN_ON(em->in_tree);
                kmem_cache_free(extent_map_cache, em);
@@ -102,6 +104,8 @@ EXPORT_SYMBOL(alloc_extent_state);
 
 void free_extent_state(struct extent_state *state)
 {
+       if (!state)
+               return;
        if (atomic_dec_and_test(&state->refs)) {
                WARN_ON(state->in_tree);
                kmem_cache_free(extent_state_cache, state);
@@ -1395,8 +1399,8 @@ int extent_read_full_page(struct extent_map_tree *tree, struct page *page,
 
        if (!PagePrivate(page)) {
                SetPagePrivate(page);
-               set_page_private(page, 1);
                WARN_ON(!page->mapping->a_ops->invalidatepage);
+               set_page_private(page, 1);
                page_cache_get(page);
        }
 
@@ -1638,7 +1642,8 @@ int extent_invalidatepage(struct extent_map_tree *tree,
 
        lock_extent(tree, start, end, GFP_NOFS);
        wait_on_extent_writeback(tree, start, end);
-       clear_extent_bit(tree, start, end, EXTENT_LOCKED | EXTENT_DIRTY,
+       clear_extent_bit(tree, start, end,
+                        EXTENT_LOCKED | EXTENT_DIRTY | EXTENT_DELALLOC,
                         1, 1, GFP_NOFS);
        return 0;
 }
index d3d39e4a27979a9ea5d9122527b491d0e2463395..07b121d4bd930f6a6996126b94b186c52a881b86 100644 (file)
@@ -186,8 +186,16 @@ static int dirty_and_release_pages(struct btrfs_trans_handle *trans,
                u64 mask = root->blocksize - 1;
                last_pos_in_file = (isize + mask) & ~mask;
                hole_size = (start_pos - last_pos_in_file + mask) & ~mask;
-               hole_size >>= inode->i_blkbits;
+
                if (last_pos_in_file < start_pos) {
+                       err = btrfs_drop_extents(trans, root, inode,
+                                                last_pos_in_file,
+                                                last_pos_in_file + hole_size,
+                                                &hint_block);
+                       if (err)
+                               goto failed;
+
+                       hole_size >>= inode->i_blkbits;
                        err = btrfs_insert_file_extent(trans, root,
                                                       inode->i_ino,
                                                       last_pos_in_file,
@@ -217,13 +225,11 @@ static int dirty_and_release_pages(struct btrfs_trans_handle *trans,
                struct page *p = pages[0];
                /* step one, delete the existing extents in this range */
                /* FIXME blocksize != pagesize */
-               if (start_pos < inode->i_size) {
-                       err = btrfs_drop_extents(trans, root, inode, start_pos,
-                                (pos + write_bytes + root->blocksize -1) &
-                                ~((u64)root->blocksize - 1), &hint_block);
-                       if (err)
-                               goto failed;
-               }
+               err = btrfs_drop_extents(trans, root, inode, start_pos,
+                        (pos + write_bytes + root->blocksize -1) &
+                        ~((u64)root->blocksize - 1), &hint_block);
+               if (err)
+                       goto failed;
 
                err = insert_inline_extent(trans, root, inode, start_pos,
                                           end_pos - start_pos, p, 0);
@@ -400,6 +406,8 @@ next_slot:
                        keep = 1;
                        WARN_ON(start & (root->blocksize - 1));
                        if (found_extent) {
+                               btrfs_drop_extent_cache(inode, key.offset,
+                                                       start - 1 );
                                new_num = (start - key.offset) >>
                                        inode->i_blkbits;
                                old_num = btrfs_file_extent_num_blocks(extent);
@@ -464,7 +472,7 @@ next_slot:
 
                        if (ret) {
                                btrfs_print_leaf(root, btrfs_buffer_leaf(path->nodes[0]));
-                               printk("got %d on inserting %Lu %u %Lu start %Lu end %Lu found %Lu %Lu\n", ret , ins.objectid, ins.flags, ins.offset, start, end, key.offset, extent_end);
+                               printk("got %d on inserting %Lu %u %Lu start %Lu end %Lu found %Lu %Lu keep was %d\n", ret , ins.objectid, ins.flags, ins.offset, start, end, key.offset, extent_end, keep);
                        }
                        BUG_ON(ret);
                        extent = btrfs_item_ptr(
index 3ee6b2fadf5835b15f15b2d9a9045a9fe043b0cf..64710fa77d01500f789c547541cb97baaff33bdd 100644 (file)
@@ -721,25 +721,35 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr)
            attr->ia_valid & ATTR_SIZE && attr->ia_size > inode->i_size) {
                struct btrfs_trans_handle *trans;
                struct btrfs_root *root = BTRFS_I(inode)->root;
+               struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
+
                u64 mask = root->blocksize - 1;
                u64 pos = (inode->i_size + mask) & ~mask;
+               u64 block_end = attr->ia_size | mask;
                u64 hole_size;
+               u64 alloc_hint;
 
                if (attr->ia_size <= pos)
                        goto out;
 
                btrfs_truncate_page(inode->i_mapping, inode->i_size);
 
+               lock_extent(em_tree, pos, block_end, GFP_NOFS);
                hole_size = (attr->ia_size - pos + mask) & ~mask;
-               hole_size >>= inode->i_blkbits;
 
                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, pos + hole_size, &alloc_hint);
+
+               hole_size >>= inode->i_blkbits;
+
                err = btrfs_insert_file_extent(trans, root, inode->i_ino,
                                               pos, 0, 0, hole_size);
                btrfs_end_transaction(trans, root);
                mutex_unlock(&root->fs_info->fs_mutex);
+               unlock_extent(em_tree, pos, block_end, GFP_NOFS);
                if (err)
                        return err;
        }
@@ -1529,13 +1539,13 @@ insert:
        ret = add_extent_mapping(em_tree, em);
        if (ret == -EEXIST) {
                free_extent_map(em);
+               em = NULL;
                failed_insert++;
                if (failed_insert > 5) {
                        printk("failing to insert %Lu %Lu\n", start, end);
                        err = -EIO;
                        goto out;
                }
-               em = NULL;
                goto again;
        }
        err = 0;
@@ -1555,167 +1565,6 @@ out:
        return em;
 }
 
-
-/*
- * FIBMAP and others want to pass in a fake buffer head.  They need to
- * use BTRFS_GET_BLOCK_NO_DIRECT to make sure we don't try to memcpy
- * any packed file data into the fake bh
- */
-#define BTRFS_GET_BLOCK_NO_CREATE 0
-#define BTRFS_GET_BLOCK_CREATE 1
-#define BTRFS_GET_BLOCK_NO_DIRECT 2
-
-/*
- * FIXME create==1 doe not work.
- */
-static int btrfs_get_block_lock(struct inode *inode, sector_t iblock,
-                               struct buffer_head *result, int create)
-{
-       int ret;
-       int err = 0;
-       u64 blocknr;
-       u64 extent_start = 0;
-       u64 extent_end = 0;
-       u64 objectid = inode->i_ino;
-       u32 found_type;
-       u64 alloc_hint = 0;
-       struct btrfs_path *path;
-       struct btrfs_root *root = BTRFS_I(inode)->root;
-       struct btrfs_file_extent_item *item;
-       struct btrfs_leaf *leaf;
-       struct btrfs_disk_key *found_key;
-       struct btrfs_trans_handle *trans = NULL;
-
-       path = btrfs_alloc_path();
-       BUG_ON(!path);
-       if (create & BTRFS_GET_BLOCK_CREATE) {
-               /*
-                * danger!, this only works if the page is properly up
-                * to date somehow
-                */
-               trans = btrfs_start_transaction(root, 1);
-               if (!trans) {
-                       err = -ENOMEM;
-                       goto out;
-               }
-               ret = btrfs_drop_extents(trans, root, inode,
-                                        iblock << inode->i_blkbits,
-                                        (iblock + 1) << inode->i_blkbits,
-                                        &alloc_hint);
-               BUG_ON(ret);
-       }
-
-       ret = btrfs_lookup_file_extent(NULL, root, path,
-                                      objectid,
-                                      iblock << inode->i_blkbits, 0);
-       if (ret < 0) {
-               err = ret;
-               goto out;
-       }
-
-       if (ret != 0) {
-               if (path->slots[0] == 0) {
-                       btrfs_release_path(root, path);
-                       goto not_found;
-               }
-               path->slots[0]--;
-       }
-
-       item = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0],
-                             struct btrfs_file_extent_item);
-       leaf = btrfs_buffer_leaf(path->nodes[0]);
-       blocknr = btrfs_file_extent_disk_blocknr(item);
-       blocknr += btrfs_file_extent_offset(item);
-
-       /* are we inside the extent that was found? */
-       found_key = &leaf->items[path->slots[0]].key;
-       found_type = btrfs_disk_key_type(found_key);
-       if (btrfs_disk_key_objectid(found_key) != objectid ||
-           found_type != BTRFS_EXTENT_DATA_KEY) {
-               extent_end = 0;
-               extent_start = 0;
-               goto not_found;
-       }
-       found_type = btrfs_file_extent_type(item);
-       extent_start = btrfs_disk_key_offset(&leaf->items[path->slots[0]].key);
-       if (found_type == BTRFS_FILE_EXTENT_REG) {
-               extent_start = extent_start >> inode->i_blkbits;
-               extent_end = extent_start + btrfs_file_extent_num_blocks(item);
-               err = 0;
-               if (btrfs_file_extent_disk_blocknr(item) == 0)
-                       goto out;
-               if (iblock >= extent_start && iblock < extent_end) {
-                       btrfs_map_bh_to_logical(root, result, blocknr +
-                                               iblock - extent_start);
-                       goto out;
-               }
-       } else if (found_type == BTRFS_FILE_EXTENT_INLINE) {
-               char *ptr;
-               char *map;
-               u32 size;
-
-               if (create & BTRFS_GET_BLOCK_NO_DIRECT) {
-                       err = -EINVAL;
-                       goto out;
-               }
-               size = btrfs_file_extent_inline_len(leaf->items +
-                                                   path->slots[0]);
-               extent_end = (extent_start + size) >> inode->i_blkbits;
-               extent_start >>= inode->i_blkbits;
-               if (iblock < extent_start || iblock > extent_end) {
-                       goto not_found;
-               }
-               ptr = btrfs_file_extent_inline_start(item);
-               map = kmap(result->b_page);
-               memcpy(map, ptr, size);
-               memset(map + size, 0, PAGE_CACHE_SIZE - size);
-               flush_dcache_page(result->b_page);
-               kunmap(result->b_page);
-               set_buffer_uptodate(result);
-               SetPageChecked(result->b_page);
-               btrfs_map_bh_to_logical(root, result, 0);
-       }
-not_found:
-       if (create & BTRFS_GET_BLOCK_CREATE) {
-               struct btrfs_key ins;
-               ret = btrfs_alloc_extent(trans, root, inode->i_ino,
-                                        1, 0, alloc_hint, (u64)-1,
-                                        &ins, 1);
-               if (ret) {
-                       err = ret;
-                       goto out;
-               }
-               ret = btrfs_insert_file_extent(trans, root, inode->i_ino,
-                                              iblock << inode->i_blkbits,
-                                              ins.objectid, ins.offset,
-                                              ins.offset);
-               if (ret) {
-                       err = ret;
-                       goto out;
-               }
-               btrfs_map_bh_to_logical(root, result, ins.objectid);
-       }
-out:
-       if (trans) {
-               ret = btrfs_end_transaction(trans, root);
-               if (!err)
-                       err = ret;
-       }
-       btrfs_free_path(path);
-       return err;
-}
-
-int btrfs_get_block(struct inode *inode, sector_t iblock,
-                   struct buffer_head *result, int create)
-{
-       int err;
-       struct btrfs_root *root = BTRFS_I(inode)->root;
-       mutex_lock(&root->fs_info->fs_mutex);
-       err = btrfs_get_block_lock(inode, iblock, result, create);
-       mutex_unlock(&root->fs_info->fs_mutex);
-       return err;
-}
-
 static int btrfs_get_block_bmap(struct inode *inode, sector_t iblock,
                           struct buffer_head *result, int create)
 {
@@ -2469,6 +2318,8 @@ static struct address_space_operations btrfs_aops = {
 static struct address_space_operations btrfs_symlink_aops = {
        .readpage       = btrfs_readpage,
        .writepage      = btrfs_writepage,
+       .invalidatepage = btrfs_invalidatepage,
+       .releasepage    = btrfs_releasepage,
 };
 
 static struct inode_operations btrfs_file_inode_operations = {