return btrfs_map_bio(root, rw, bio, mirror_num, 0);
 }
 
-static int add_pending_csums(struct btrfs_trans_handle *trans,
+static noinline int add_pending_csums(struct btrfs_trans_handle *trans,
                             struct inode *inode, u64 file_offset,
                             struct list_head *list)
 {
        struct btrfs_ordered_sum *sum;
 
        btrfs_set_trans_block_group(trans, inode);
-       while(!list_empty(list)) {
-               cur = list->next;
+       list_for_each(cur, list) {
                sum = list_entry(cur, struct btrfs_ordered_sum, list);
                mutex_lock(&BTRFS_I(inode)->csum_mutex);
                btrfs_csum_file_blocks(trans, BTRFS_I(inode)->root,
                                       inode, sum);
                mutex_unlock(&BTRFS_I(inode)->csum_mutex);
-               list_del(&sum->list);
-               kfree(sum);
        }
        return 0;
 }
        int ret;
 
        ret = btrfs_dec_test_ordered_pending(inode, start, end - start + 1);
-       if (!ret) {
+       if (!ret)
                return 0;
-       }
 
        trans = btrfs_join_transaction(root, 1);
 
        path = btrfs_alloc_path();
        item = btrfs_lookup_csum(NULL, root, path, inode->i_ino, start, 0);
        if (IS_ERR(item)) {
+               /*
+                * It is possible there is an ordered extent that has
+                * not yet finished for this range in the file.  If so,
+                * that extent will have a csum cached, and it will insert
+                * the sum after all the blocks in the extent are fully
+                * on disk.  So, look for an ordered extent and use the
+                * sum if found.
+                */
+               ret = btrfs_find_ordered_sum(inode, start, &csum);
+               if (ret == 0)
+                       goto found;
+
                ret = PTR_ERR(item);
                /* a csum that isn't present is a preallocated region. */
                if (ret == -ENOENT || ret == -EFBIG)
        }
        read_extent_buffer(path->nodes[0], &csum, (unsigned long)item,
                           BTRFS_CRC32_SIZE);
+found:
        set_state_private(io_tree, start, csum);
 out:
        if (path)
                                    BTRFS_I(inode)->block_group->key.objectid);
 }
 
-int btrfs_update_inode(struct btrfs_trans_handle *trans,
+int noinline btrfs_update_inode(struct btrfs_trans_handle *trans,
                              struct btrfs_root *root,
                              struct inode *inode)
 {
                             inode->i_mapping, GFP_NOFS);
        extent_io_tree_init(&BTRFS_I(inode)->io_failure_tree,
                             inode->i_mapping, GFP_NOFS);
+       btrfs_ordered_inode_tree_init(&BTRFS_I(inode)->ordered_tree);
        mutex_init(&BTRFS_I(inode)->csum_mutex);
        return 0;
 }
                             inode->i_mapping, GFP_NOFS);
        extent_io_tree_init(&BTRFS_I(inode)->io_failure_tree,
                             inode->i_mapping, GFP_NOFS);
+       btrfs_ordered_inode_tree_init(&BTRFS_I(inode)->ordered_tree);
        mutex_init(&BTRFS_I(inode)->csum_mutex);
        BTRFS_I(inode)->delalloc_bytes = 0;
        BTRFS_I(inode)->disk_i_size = 0;
                BTRFS_I(inode)->delalloc_bytes = 0;
                BTRFS_I(inode)->disk_i_size = 0;
                BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops;
+               btrfs_ordered_inode_tree_init(&BTRFS_I(inode)->ordered_tree);
        }
        dir->i_sb->s_dirt = 1;
        btrfs_update_inode_block_group(trans, inode);
 
 static int btrfs_releasepage(struct page *page, gfp_t gfp_flags)
 {
-       struct btrfs_ordered_extent *ordered;
-
-       ordered = btrfs_lookup_ordered_extent(page->mapping->host,
-                                             page_offset(page));
-       if (ordered) {
-               btrfs_put_ordered_extent(ordered);
-               return 0;
-       }
        return __btrfs_releasepage(page, gfp_flags);
 }
 
                BTRFS_I(inode)->delalloc_bytes = 0;
                BTRFS_I(inode)->disk_i_size = 0;
                BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops;
+               btrfs_ordered_inode_tree_init(&BTRFS_I(inode)->ordered_tree);
        }
        dir->i_sb->s_dirt = 1;
        btrfs_update_inode_block_group(trans, inode);
 
 
 int btrfs_put_ordered_extent(struct btrfs_ordered_extent *entry)
 {
-       if (atomic_dec_and_test(&entry->refs))
+       struct list_head *cur;
+       struct btrfs_ordered_sum *sum;
+
+       if (atomic_dec_and_test(&entry->refs)) {
+               while(!list_empty(&entry->list)) {
+                       cur = entry->list.next;
+                       sum = list_entry(cur, struct btrfs_ordered_sum, list);
+                       list_del(&sum->list);
+                       kfree(sum);
+               }
                kfree(entry);
+       }
        return 0;
 }
 
         * if we find an ordered extent then we can't update disk i_size
         * yet
         */
+       node = &ordered->rb_node;
        while(1) {
-               node = rb_prev(&ordered->rb_node);
+               node = rb_prev(node);
                if (!node)
                        break;
                test = rb_entry(node, struct btrfs_ordered_extent, rb_node);
        mutex_unlock(&tree->mutex);
        return 0;
 }
+
+int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u32 *sum)
+{
+       struct btrfs_ordered_sum *ordered_sum;
+       struct btrfs_sector_sum *sector_sums;
+       struct btrfs_ordered_extent *ordered;
+       struct btrfs_ordered_inode_tree *tree = &BTRFS_I(inode)->ordered_tree;
+       struct list_head *cur;
+       int ret = 1;
+       int index;
+
+       ordered = btrfs_lookup_ordered_extent(inode, offset);
+       if (!ordered)
+               return 1;
+
+       mutex_lock(&tree->mutex);
+       list_for_each_prev(cur, &ordered->list) {
+               ordered_sum = list_entry(cur, struct btrfs_ordered_sum, list);
+               if (offset >= ordered_sum->file_offset &&
+                   offset < ordered_sum->file_offset + ordered_sum->len) {
+                       index = (offset - ordered_sum->file_offset) /
+                               BTRFS_I(inode)->root->sectorsize;;
+                       sector_sums = &ordered_sum->sums;
+                       *sum = sector_sums[index].sum;
+                       ret = 0;
+                       goto out;
+               }
+       }
+out:
+       mutex_unlock(&tree->mutex);
+       return ret;
+}
+