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;
+}
+