Commit 00361589 authored by Josef Bacik's avatar Josef Bacik Committed by Chris Mason

Btrfs: avoid starting a transaction in the write path

I noticed while looking at a deadlock that we are always starting a transaction
in cow_file_range().  This isn't really needed since we only need a transaction
if we are doing an inline extent, or if the allocator needs to allocate a chunk.
So push down all the transaction start stuff to be closer to where we actually
need a transaction in all of these cases.  This will hopefully reduce our write
latency when we are committing often.  Thanks,
Signed-off-by: default avatarJosef Bacik <jbacik@fusionio.com>
Signed-off-by: default avatarChris Mason <chris.mason@fusionio.com>
parent 9ffba8cd
...@@ -3165,11 +3165,9 @@ int btrfs_alloc_logged_file_extent(struct btrfs_trans_handle *trans, ...@@ -3165,11 +3165,9 @@ int btrfs_alloc_logged_file_extent(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
u64 root_objectid, u64 owner, u64 offset, u64 root_objectid, u64 owner, u64 offset,
struct btrfs_key *ins); struct btrfs_key *ins);
int btrfs_reserve_extent(struct btrfs_trans_handle *trans, int btrfs_reserve_extent(struct btrfs_root *root, u64 num_bytes,
struct btrfs_root *root, u64 min_alloc_size, u64 empty_size, u64 hint_byte,
u64 num_bytes, u64 min_alloc_size, struct btrfs_key *ins, int is_data);
u64 empty_size, u64 hint_byte,
struct btrfs_key *ins, int is_data);
int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
struct extent_buffer *buf, int full_backref, int for_cow); struct extent_buffer *buf, int full_backref, int for_cow);
int btrfs_dec_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, int btrfs_dec_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
...@@ -3612,8 +3610,7 @@ void btrfs_wait_and_free_delalloc_work(struct btrfs_delalloc_work *work); ...@@ -3612,8 +3610,7 @@ void btrfs_wait_and_free_delalloc_work(struct btrfs_delalloc_work *work);
struct extent_map *btrfs_get_extent_fiemap(struct inode *inode, struct page *page, struct extent_map *btrfs_get_extent_fiemap(struct inode *inode, struct page *page,
size_t pg_offset, u64 start, u64 len, size_t pg_offset, u64 start, u64 len,
int create); int create);
noinline int can_nocow_extent(struct btrfs_trans_handle *trans, noinline int can_nocow_extent(struct inode *inode, u64 offset, u64 *len,
struct inode *inode, u64 offset, u64 *len,
u64 *orig_start, u64 *orig_block_len, u64 *orig_start, u64 *orig_block_len,
u64 *ram_bytes); u64 *ram_bytes);
......
...@@ -6121,8 +6121,7 @@ enum btrfs_loop_type { ...@@ -6121,8 +6121,7 @@ enum btrfs_loop_type {
* ins->offset == number of blocks * ins->offset == number of blocks
* Any available blocks before search_start are skipped. * Any available blocks before search_start are skipped.
*/ */
static noinline int find_free_extent(struct btrfs_trans_handle *trans, static noinline int find_free_extent(struct btrfs_root *orig_root,
struct btrfs_root *orig_root,
u64 num_bytes, u64 empty_size, u64 num_bytes, u64 empty_size,
u64 hint_byte, struct btrfs_key *ins, u64 hint_byte, struct btrfs_key *ins,
u64 flags) u64 flags)
...@@ -6345,10 +6344,10 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans, ...@@ -6345,10 +6344,10 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans,
block_group->full_stripe_len); block_group->full_stripe_len);
/* allocate a cluster in this block group */ /* allocate a cluster in this block group */
ret = btrfs_find_space_cluster(trans, root, ret = btrfs_find_space_cluster(root, block_group,
block_group, last_ptr, last_ptr, search_start,
search_start, num_bytes, num_bytes,
aligned_cluster); aligned_cluster);
if (ret == 0) { if (ret == 0) {
/* /*
* now pull our allocation out of this * now pull our allocation out of this
...@@ -6479,17 +6478,28 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans, ...@@ -6479,17 +6478,28 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans,
index = 0; index = 0;
loop++; loop++;
if (loop == LOOP_ALLOC_CHUNK) { if (loop == LOOP_ALLOC_CHUNK) {
struct btrfs_trans_handle *trans;
trans = btrfs_join_transaction(root);
if (IS_ERR(trans)) {
ret = PTR_ERR(trans);
goto out;
}
ret = do_chunk_alloc(trans, root, flags, ret = do_chunk_alloc(trans, root, flags,
CHUNK_ALLOC_FORCE); CHUNK_ALLOC_FORCE);
/* /*
* Do not bail out on ENOSPC since we * Do not bail out on ENOSPC since we
* can do more things. * can do more things.
*/ */
if (ret < 0 && ret != -ENOSPC) { if (ret < 0 && ret != -ENOSPC)
btrfs_abort_transaction(trans, btrfs_abort_transaction(trans,
root, ret); root, ret);
else
ret = 0;
btrfs_end_transaction(trans, root);
if (ret)
goto out; goto out;
}
} }
if (loop == LOOP_NO_EMPTY_SIZE) { if (loop == LOOP_NO_EMPTY_SIZE) {
...@@ -6553,8 +6563,7 @@ static void dump_space_info(struct btrfs_space_info *info, u64 bytes, ...@@ -6553,8 +6563,7 @@ static void dump_space_info(struct btrfs_space_info *info, u64 bytes,
up_read(&info->groups_sem); up_read(&info->groups_sem);
} }
int btrfs_reserve_extent(struct btrfs_trans_handle *trans, int btrfs_reserve_extent(struct btrfs_root *root,
struct btrfs_root *root,
u64 num_bytes, u64 min_alloc_size, u64 num_bytes, u64 min_alloc_size,
u64 empty_size, u64 hint_byte, u64 empty_size, u64 hint_byte,
struct btrfs_key *ins, int is_data) struct btrfs_key *ins, int is_data)
...@@ -6566,8 +6575,8 @@ int btrfs_reserve_extent(struct btrfs_trans_handle *trans, ...@@ -6566,8 +6575,8 @@ int btrfs_reserve_extent(struct btrfs_trans_handle *trans,
flags = btrfs_get_alloc_profile(root, is_data); flags = btrfs_get_alloc_profile(root, is_data);
again: again:
WARN_ON(num_bytes < root->sectorsize); WARN_ON(num_bytes < root->sectorsize);
ret = find_free_extent(trans, root, num_bytes, empty_size, ret = find_free_extent(root, num_bytes, empty_size, hint_byte, ins,
hint_byte, ins, flags); flags);
if (ret == -ENOSPC) { if (ret == -ENOSPC) {
if (!final_tried) { if (!final_tried) {
...@@ -6955,7 +6964,7 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans, ...@@ -6955,7 +6964,7 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
if (IS_ERR(block_rsv)) if (IS_ERR(block_rsv))
return ERR_CAST(block_rsv); return ERR_CAST(block_rsv);
ret = btrfs_reserve_extent(trans, root, blocksize, blocksize, ret = btrfs_reserve_extent(root, blocksize, blocksize,
empty_size, hint, &ins, 0); empty_size, hint, &ins, 0);
if (ret) { if (ret) {
unuse_block_rsv(root->fs_info, block_rsv, blocksize); unuse_block_rsv(root->fs_info, block_rsv, blocksize);
......
...@@ -1339,7 +1339,6 @@ static noinline int prepare_pages(struct btrfs_root *root, struct file *file, ...@@ -1339,7 +1339,6 @@ static noinline int prepare_pages(struct btrfs_root *root, struct file *file,
static noinline int check_can_nocow(struct inode *inode, loff_t pos, static noinline int check_can_nocow(struct inode *inode, loff_t pos,
size_t *write_bytes) size_t *write_bytes)
{ {
struct btrfs_trans_handle *trans;
struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_root *root = BTRFS_I(inode)->root;
struct btrfs_ordered_extent *ordered; struct btrfs_ordered_extent *ordered;
u64 lockstart, lockend; u64 lockstart, lockend;
...@@ -1361,16 +1360,8 @@ static noinline int check_can_nocow(struct inode *inode, loff_t pos, ...@@ -1361,16 +1360,8 @@ static noinline int check_can_nocow(struct inode *inode, loff_t pos,
btrfs_put_ordered_extent(ordered); btrfs_put_ordered_extent(ordered);
} }
trans = btrfs_join_transaction(root);
if (IS_ERR(trans)) {
unlock_extent(&BTRFS_I(inode)->io_tree, lockstart, lockend);
return PTR_ERR(trans);
}
num_bytes = lockend - lockstart + 1; num_bytes = lockend - lockstart + 1;
ret = can_nocow_extent(trans, inode, lockstart, &num_bytes, NULL, NULL, ret = can_nocow_extent(inode, lockstart, &num_bytes, NULL, NULL, NULL);
NULL);
btrfs_end_transaction(trans, root);
if (ret <= 0) { if (ret <= 0) {
ret = 0; ret = 0;
} else { } else {
......
...@@ -2525,8 +2525,7 @@ setup_cluster_bitmap(struct btrfs_block_group_cache *block_group, ...@@ -2525,8 +2525,7 @@ setup_cluster_bitmap(struct btrfs_block_group_cache *block_group,
* returns zero and sets up cluster if things worked out, otherwise * returns zero and sets up cluster if things worked out, otherwise
* it returns -enospc * it returns -enospc
*/ */
int btrfs_find_space_cluster(struct btrfs_trans_handle *trans, int btrfs_find_space_cluster(struct btrfs_root *root,
struct btrfs_root *root,
struct btrfs_block_group_cache *block_group, struct btrfs_block_group_cache *block_group,
struct btrfs_free_cluster *cluster, struct btrfs_free_cluster *cluster,
u64 offset, u64 bytes, u64 empty_size) u64 offset, u64 bytes, u64 empty_size)
......
...@@ -98,8 +98,7 @@ u64 btrfs_find_space_for_alloc(struct btrfs_block_group_cache *block_group, ...@@ -98,8 +98,7 @@ u64 btrfs_find_space_for_alloc(struct btrfs_block_group_cache *block_group,
u64 btrfs_find_ino_for_alloc(struct btrfs_root *fs_root); u64 btrfs_find_ino_for_alloc(struct btrfs_root *fs_root);
void btrfs_dump_free_space(struct btrfs_block_group_cache *block_group, void btrfs_dump_free_space(struct btrfs_block_group_cache *block_group,
u64 bytes); u64 bytes);
int btrfs_find_space_cluster(struct btrfs_trans_handle *trans, int btrfs_find_space_cluster(struct btrfs_root *root,
struct btrfs_root *root,
struct btrfs_block_group_cache *block_group, struct btrfs_block_group_cache *block_group,
struct btrfs_free_cluster *cluster, struct btrfs_free_cluster *cluster,
u64 offset, u64 bytes, u64 empty_size); u64 offset, u64 bytes, u64 empty_size);
......
...@@ -230,12 +230,13 @@ static noinline int insert_inline_extent(struct btrfs_trans_handle *trans, ...@@ -230,12 +230,13 @@ static noinline int insert_inline_extent(struct btrfs_trans_handle *trans,
* does the checks required to make sure the data is small enough * does the checks required to make sure the data is small enough
* to fit as an inline extent. * to fit as an inline extent.
*/ */
static noinline int cow_file_range_inline(struct btrfs_trans_handle *trans, static noinline int cow_file_range_inline(struct btrfs_root *root,
struct btrfs_root *root, struct inode *inode, u64 start,
struct inode *inode, u64 start, u64 end, u64 end, size_t compressed_size,
size_t compressed_size, int compress_type, int compress_type,
struct page **compressed_pages) struct page **compressed_pages)
{ {
struct btrfs_trans_handle *trans;
u64 isize = i_size_read(inode); u64 isize = i_size_read(inode);
u64 actual_end = min(end + 1, isize); u64 actual_end = min(end + 1, isize);
u64 inline_len = actual_end - start; u64 inline_len = actual_end - start;
...@@ -256,9 +257,16 @@ static noinline int cow_file_range_inline(struct btrfs_trans_handle *trans, ...@@ -256,9 +257,16 @@ static noinline int cow_file_range_inline(struct btrfs_trans_handle *trans,
return 1; return 1;
} }
trans = btrfs_join_transaction(root);
if (IS_ERR(trans))
return PTR_ERR(trans);
trans->block_rsv = &root->fs_info->delalloc_block_rsv;
ret = btrfs_drop_extents(trans, root, inode, start, aligned_end, 1); ret = btrfs_drop_extents(trans, root, inode, start, aligned_end, 1);
if (ret) if (ret) {
return ret; btrfs_abort_transaction(trans, root, ret);
goto out;
}
if (isize > actual_end) if (isize > actual_end)
inline_len = min_t(u64, isize, actual_end); inline_len = min_t(u64, isize, actual_end);
...@@ -267,15 +275,18 @@ static noinline int cow_file_range_inline(struct btrfs_trans_handle *trans, ...@@ -267,15 +275,18 @@ static noinline int cow_file_range_inline(struct btrfs_trans_handle *trans,
compress_type, compressed_pages); compress_type, compressed_pages);
if (ret && ret != -ENOSPC) { if (ret && ret != -ENOSPC) {
btrfs_abort_transaction(trans, root, ret); btrfs_abort_transaction(trans, root, ret);
return ret; goto out;
} else if (ret == -ENOSPC) { } else if (ret == -ENOSPC) {
return 1; ret = 1;
goto out;
} }
set_bit(BTRFS_INODE_NEEDS_FULL_SYNC, &BTRFS_I(inode)->runtime_flags); set_bit(BTRFS_INODE_NEEDS_FULL_SYNC, &BTRFS_I(inode)->runtime_flags);
btrfs_delalloc_release_metadata(inode, end + 1 - start); btrfs_delalloc_release_metadata(inode, end + 1 - start);
btrfs_drop_extent_cache(inode, start, aligned_end - 1, 0); btrfs_drop_extent_cache(inode, start, aligned_end - 1, 0);
return 0; out:
btrfs_end_transaction(trans, root);
return ret;
} }
struct async_extent { struct async_extent {
...@@ -343,7 +354,6 @@ static noinline int compress_file_range(struct inode *inode, ...@@ -343,7 +354,6 @@ static noinline int compress_file_range(struct inode *inode,
int *num_added) int *num_added)
{ {
struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_root *root = BTRFS_I(inode)->root;
struct btrfs_trans_handle *trans;
u64 num_bytes; u64 num_bytes;
u64 blocksize = root->sectorsize; u64 blocksize = root->sectorsize;
u64 actual_end; u64 actual_end;
...@@ -461,25 +471,16 @@ static noinline int compress_file_range(struct inode *inode, ...@@ -461,25 +471,16 @@ static noinline int compress_file_range(struct inode *inode,
} }
cont: cont:
if (start == 0) { if (start == 0) {
trans = btrfs_join_transaction(root);
if (IS_ERR(trans)) {
ret = PTR_ERR(trans);
trans = NULL;
goto cleanup_and_out;
}
trans->block_rsv = &root->fs_info->delalloc_block_rsv;
/* lets try to make an inline extent */ /* lets try to make an inline extent */
if (ret || total_in < (actual_end - start)) { if (ret || total_in < (actual_end - start)) {
/* we didn't compress the entire range, try /* we didn't compress the entire range, try
* to make an uncompressed inline extent. * to make an uncompressed inline extent.
*/ */
ret = cow_file_range_inline(trans, root, inode, ret = cow_file_range_inline(root, inode, start, end,
start, end, 0, 0, NULL); 0, 0, NULL);
} else { } else {
/* try making a compressed inline extent */ /* try making a compressed inline extent */
ret = cow_file_range_inline(trans, root, inode, ret = cow_file_range_inline(root, inode, start, end,
start, end,
total_compressed, total_compressed,
compress_type, pages); compress_type, pages);
} }
...@@ -498,10 +499,8 @@ static noinline int compress_file_range(struct inode *inode, ...@@ -498,10 +499,8 @@ static noinline int compress_file_range(struct inode *inode,
PAGE_CLEAR_DIRTY | PAGE_CLEAR_DIRTY |
PAGE_SET_WRITEBACK | PAGE_SET_WRITEBACK |
PAGE_END_WRITEBACK); PAGE_END_WRITEBACK);
btrfs_end_transaction(trans, root);
goto free_pages_out; goto free_pages_out;
} }
btrfs_end_transaction(trans, root);
} }
if (will_compress) { if (will_compress) {
...@@ -592,18 +591,6 @@ static noinline int compress_file_range(struct inode *inode, ...@@ -592,18 +591,6 @@ static noinline int compress_file_range(struct inode *inode,
kfree(pages); kfree(pages);
goto out; goto out;
cleanup_and_out:
extent_clear_unlock_delalloc(inode, start, end, NULL,
EXTENT_DELALLOC | EXTENT_DO_ACCOUNTING |
EXTENT_DEFRAG, PAGE_UNLOCK |
PAGE_CLEAR_DIRTY | PAGE_SET_WRITEBACK |
PAGE_END_WRITEBACK);
if (!trans || IS_ERR(trans))
btrfs_error(root->fs_info, ret, "Failed to join transaction");
else
btrfs_abort_transaction(trans, root, ret);
goto free_pages_out;
} }
/* /*
...@@ -617,7 +604,6 @@ static noinline int submit_compressed_extents(struct inode *inode, ...@@ -617,7 +604,6 @@ static noinline int submit_compressed_extents(struct inode *inode,
{ {
struct async_extent *async_extent; struct async_extent *async_extent;
u64 alloc_hint = 0; u64 alloc_hint = 0;
struct btrfs_trans_handle *trans;
struct btrfs_key ins; struct btrfs_key ins;
struct extent_map *em; struct extent_map *em;
struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_root *root = BTRFS_I(inode)->root;
...@@ -678,20 +664,10 @@ static noinline int submit_compressed_extents(struct inode *inode, ...@@ -678,20 +664,10 @@ static noinline int submit_compressed_extents(struct inode *inode,
lock_extent(io_tree, async_extent->start, lock_extent(io_tree, async_extent->start,
async_extent->start + async_extent->ram_size - 1); async_extent->start + async_extent->ram_size - 1);
trans = btrfs_join_transaction(root); ret = btrfs_reserve_extent(root,
if (IS_ERR(trans)) {
ret = PTR_ERR(trans);
} else {
trans->block_rsv = &root->fs_info->delalloc_block_rsv;
ret = btrfs_reserve_extent(trans, root,
async_extent->compressed_size, async_extent->compressed_size,
async_extent->compressed_size, async_extent->compressed_size,
0, alloc_hint, &ins, 1); 0, alloc_hint, &ins, 1);
if (ret && ret != -ENOSPC)
btrfs_abort_transaction(trans, root, ret);
btrfs_end_transaction(trans, root);
}
if (ret) { if (ret) {
int i; int i;
...@@ -850,14 +826,13 @@ static u64 get_extent_allocation_hint(struct inode *inode, u64 start, ...@@ -850,14 +826,13 @@ static u64 get_extent_allocation_hint(struct inode *inode, u64 start,
* required to start IO on it. It may be clean and already done with * required to start IO on it. It may be clean and already done with
* IO when we return. * IO when we return.
*/ */
static noinline int __cow_file_range(struct btrfs_trans_handle *trans, static noinline int cow_file_range(struct inode *inode,
struct inode *inode, struct page *locked_page,
struct btrfs_root *root, u64 start, u64 end, int *page_started,
struct page *locked_page, unsigned long *nr_written,
u64 start, u64 end, int *page_started, int unlock)
unsigned long *nr_written,
int unlock)
{ {
struct btrfs_root *root = BTRFS_I(inode)->root;
u64 alloc_hint = 0; u64 alloc_hint = 0;
u64 num_bytes; u64 num_bytes;
unsigned long ram_size; unsigned long ram_size;
...@@ -878,12 +853,12 @@ static noinline int __cow_file_range(struct btrfs_trans_handle *trans, ...@@ -878,12 +853,12 @@ static noinline int __cow_file_range(struct btrfs_trans_handle *trans,
/* if this is a small write inside eof, kick off defrag */ /* if this is a small write inside eof, kick off defrag */
if (num_bytes < 64 * 1024 && if (num_bytes < 64 * 1024 &&
(start > 0 || end + 1 < BTRFS_I(inode)->disk_i_size)) (start > 0 || end + 1 < BTRFS_I(inode)->disk_i_size))
btrfs_add_inode_defrag(trans, inode); btrfs_add_inode_defrag(NULL, inode);
if (start == 0) { if (start == 0) {
/* lets try to make an inline extent */ /* lets try to make an inline extent */
ret = cow_file_range_inline(trans, root, inode, ret = cow_file_range_inline(root, inode, start, end, 0, 0,
start, end, 0, 0, NULL); NULL);
if (ret == 0) { if (ret == 0) {
extent_clear_unlock_delalloc(inode, start, end, NULL, extent_clear_unlock_delalloc(inode, start, end, NULL,
EXTENT_LOCKED | EXTENT_DELALLOC | EXTENT_LOCKED | EXTENT_DELALLOC |
...@@ -896,7 +871,6 @@ static noinline int __cow_file_range(struct btrfs_trans_handle *trans, ...@@ -896,7 +871,6 @@ static noinline int __cow_file_range(struct btrfs_trans_handle *trans,
*page_started = 1; *page_started = 1;
goto out; goto out;
} else if (ret < 0) { } else if (ret < 0) {
btrfs_abort_transaction(trans, root, ret);
goto out_unlock; goto out_unlock;
} }
} }
...@@ -911,13 +885,11 @@ static noinline int __cow_file_range(struct btrfs_trans_handle *trans, ...@@ -911,13 +885,11 @@ static noinline int __cow_file_range(struct btrfs_trans_handle *trans,
unsigned long op; unsigned long op;
cur_alloc_size = disk_num_bytes; cur_alloc_size = disk_num_bytes;
ret = btrfs_reserve_extent(trans, root, cur_alloc_size, ret = btrfs_reserve_extent(root, cur_alloc_size,
root->sectorsize, 0, alloc_hint, root->sectorsize, 0, alloc_hint,
&ins, 1); &ins, 1);
if (ret < 0) { if (ret < 0)
btrfs_abort_transaction(trans, root, ret);
goto out_unlock; goto out_unlock;
}
em = alloc_extent_map(); em = alloc_extent_map();
if (!em) { if (!em) {
...@@ -963,10 +935,8 @@ static noinline int __cow_file_range(struct btrfs_trans_handle *trans, ...@@ -963,10 +935,8 @@ static noinline int __cow_file_range(struct btrfs_trans_handle *trans,
BTRFS_DATA_RELOC_TREE_OBJECTID) { BTRFS_DATA_RELOC_TREE_OBJECTID) {
ret = btrfs_reloc_clone_csums(inode, start, ret = btrfs_reloc_clone_csums(inode, start,
cur_alloc_size); cur_alloc_size);
if (ret) { if (ret)
btrfs_abort_transaction(trans, root, ret);
goto out_reserve; goto out_reserve;
}
} }
if (disk_num_bytes < cur_alloc_size) if (disk_num_bytes < cur_alloc_size)
...@@ -1005,37 +975,6 @@ static noinline int __cow_file_range(struct btrfs_trans_handle *trans, ...@@ -1005,37 +975,6 @@ static noinline int __cow_file_range(struct btrfs_trans_handle *trans,
goto out; goto out;
} }
static noinline int cow_file_range(struct inode *inode,
struct page *locked_page,
u64 start, u64 end, int *page_started,
unsigned long *nr_written,
int unlock)
{
struct btrfs_trans_handle *trans;
struct btrfs_root *root = BTRFS_I(inode)->root;
int ret;
trans = btrfs_join_transaction(root);
if (IS_ERR(trans)) {
extent_clear_unlock_delalloc(inode, start, end, locked_page,
EXTENT_LOCKED | EXTENT_DELALLOC |
EXTENT_DO_ACCOUNTING |
EXTENT_DEFRAG, PAGE_UNLOCK |
PAGE_CLEAR_DIRTY |
PAGE_SET_WRITEBACK |
PAGE_END_WRITEBACK);
return PTR_ERR(trans);
}
trans->block_rsv = &root->fs_info->delalloc_block_rsv;
ret = __cow_file_range(trans, inode, root, locked_page, start, end,
page_started, nr_written, unlock);
btrfs_end_transaction(trans, root);
return ret;
}
/* /*
* work queue call back to started compression on a file and pages * work queue call back to started compression on a file and pages
*/ */
...@@ -1347,9 +1286,9 @@ static noinline int run_delalloc_nocow(struct inode *inode, ...@@ -1347,9 +1286,9 @@ static noinline int run_delalloc_nocow(struct inode *inode,
btrfs_release_path(path); btrfs_release_path(path);
if (cow_start != (u64)-1) { if (cow_start != (u64)-1) {
ret = __cow_file_range(trans, inode, root, locked_page, ret = cow_file_range(inode, locked_page,
cow_start, found_key.offset - 1, cow_start, found_key.offset - 1,
page_started, nr_written, 1); page_started, nr_written, 1);
if (ret) { if (ret) {
btrfs_abort_transaction(trans, root, ret); btrfs_abort_transaction(trans, root, ret);
goto error; goto error;
...@@ -1423,9 +1362,8 @@ static noinline int run_delalloc_nocow(struct inode *inode, ...@@ -1423,9 +1362,8 @@ static noinline int run_delalloc_nocow(struct inode *inode,
} }
if (cow_start != (u64)-1) { if (cow_start != (u64)-1) {
ret = __cow_file_range(trans, inode, root, locked_page, ret = cow_file_range(inode, locked_page, cow_start, end,
cow_start, end, page_started, nr_written, 1);
page_started, nr_written, 1);
if (ret) { if (ret) {
btrfs_abort_transaction(trans, root, ret); btrfs_abort_transaction(trans, root, ret);
goto error; goto error;
...@@ -6344,39 +6282,32 @@ static struct extent_map *btrfs_new_extent_direct(struct inode *inode, ...@@ -6344,39 +6282,32 @@ static struct extent_map *btrfs_new_extent_direct(struct inode *inode,
u64 start, u64 len) u64 start, u64 len)
{ {
struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_root *root = BTRFS_I(inode)->root;
struct btrfs_trans_handle *trans;
struct extent_map *em; struct extent_map *em;
struct btrfs_key ins; struct btrfs_key ins;
u64 alloc_hint; u64 alloc_hint;
int ret; int ret;
trans = btrfs_join_transaction(root);
if (IS_ERR(trans))
return ERR_CAST(trans);
trans->block_rsv = &root->fs_info->delalloc_block_rsv;
alloc_hint = get_extent_allocation_hint(inode, start, len); alloc_hint = get_extent_allocation_hint(inode, start, len);
ret = btrfs_reserve_extent(trans, root, len, root->sectorsize, 0, ret = btrfs_reserve_extent(root, len, root->sectorsize, 0,
alloc_hint, &ins, 1); alloc_hint, &ins, 1);
if (ret) { if (ret)
em = ERR_PTR(ret); return ERR_PTR(ret);
goto out;
}
em = create_pinned_em(inode, start, ins.offset, start, ins.objectid, em = create_pinned_em(inode, start, ins.offset, start, ins.objectid,
ins.offset, ins.offset, ins.offset, 0); ins.offset, ins.offset, ins.offset, 0);
if (IS_ERR(em)) if (IS_ERR(em)) {
goto out; btrfs_free_reserved_extent(root, ins.objectid, ins.offset);
return em;
}
ret = btrfs_add_ordered_extent_dio(inode, start, ins.objectid, ret = btrfs_add_ordered_extent_dio(inode, start, ins.objectid,
ins.offset, ins.offset, 0); ins.offset, ins.offset, 0);
if (ret) { if (ret) {
btrfs_free_reserved_extent(root, ins.objectid, ins.offset); btrfs_free_reserved_extent(root, ins.objectid, ins.offset);
em = ERR_PTR(ret); free_extent_map(em);
return ERR_PTR(ret);
} }
out:
btrfs_end_transaction(trans, root);
return em; return em;
} }
...@@ -6384,11 +6315,11 @@ static struct extent_map *btrfs_new_extent_direct(struct inode *inode, ...@@ -6384,11 +6315,11 @@ static struct extent_map *btrfs_new_extent_direct(struct inode *inode,
* returns 1 when the nocow is safe, < 1 on error, 0 if the * returns 1 when the nocow is safe, < 1 on error, 0 if the
* block must be cow'd * block must be cow'd
*/ */
noinline int can_nocow_extent(struct btrfs_trans_handle *trans, noinline int can_nocow_extent(struct inode *inode, u64 offset, u64 *len,
struct inode *inode, u64 offset, u64 *len,
u64 *orig_start, u64 *orig_block_len, u64 *orig_start, u64 *orig_block_len,
u64 *ram_bytes) u64 *ram_bytes)
{ {
struct btrfs_trans_handle *trans;
struct btrfs_path *path; struct btrfs_path *path;
int ret; int ret;
struct extent_buffer *leaf; struct extent_buffer *leaf;
...@@ -6406,7 +6337,7 @@ noinline int can_nocow_extent(struct btrfs_trans_handle *trans, ...@@ -6406,7 +6337,7 @@ noinline int can_nocow_extent(struct btrfs_trans_handle *trans,
if (!path) if (!path)
return -ENOMEM; return -ENOMEM;
ret = btrfs_lookup_file_extent(trans, root, path, btrfs_ino(inode), ret = btrfs_lookup_file_extent(NULL, root, path, btrfs_ino(inode),
offset, 0); offset, 0);
if (ret < 0) if (ret < 0)
goto out; goto out;
...@@ -6471,9 +6402,19 @@ noinline int can_nocow_extent(struct btrfs_trans_handle *trans, ...@@ -6471,9 +6402,19 @@ noinline int can_nocow_extent(struct btrfs_trans_handle *trans,
* look for other files referencing this extent, if we * look for other files referencing this extent, if we
* find any we must cow * find any we must cow
*/ */
if (btrfs_cross_ref_exist(trans, root, btrfs_ino(inode), trans = btrfs_join_transaction(root);
key.offset - backref_offset, disk_bytenr)) if (IS_ERR(trans)) {
ret = 0;
goto out; goto out;
}
ret = btrfs_cross_ref_exist(trans, root, btrfs_ino(inode),
key.offset - backref_offset, disk_bytenr);
btrfs_end_transaction(trans, root);
if (ret) {
ret = 0;
goto out;
}
/* /*
* adjust disk_bytenr and num_bytes to cover just the bytes * adjust disk_bytenr and num_bytes to cover just the bytes
...@@ -6615,7 +6556,6 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock, ...@@ -6615,7 +6556,6 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock,
u64 start = iblock << inode->i_blkbits; u64 start = iblock << inode->i_blkbits;
u64 lockstart, lockend; u64 lockstart, lockend;
u64 len = bh_result->b_size; u64 len = bh_result->b_size;
struct btrfs_trans_handle *trans;
int unlock_bits = EXTENT_LOCKED; int unlock_bits = EXTENT_LOCKED;
int ret = 0; int ret = 0;
...@@ -6697,16 +6637,7 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock, ...@@ -6697,16 +6637,7 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock,
len = min(len, em->len - (start - em->start)); len = min(len, em->len - (start - em->start));
block_start = em->block_start + (start - em->start); block_start = em->block_start + (start - em->start);
/* if (can_nocow_extent(inode, start, &len, &orig_start,
* we're not going to log anything, but we do need
* to make sure the current transaction stays open
* while we look for nocow cross refs
*/
trans = btrfs_join_transaction(root);
if (IS_ERR(trans))
goto must_cow;
if (can_nocow_extent(trans, inode, start, &len, &orig_start,
&orig_block_len, &ram_bytes) == 1) { &orig_block_len, &ram_bytes) == 1) {
if (type == BTRFS_ORDERED_PREALLOC) { if (type == BTRFS_ORDERED_PREALLOC) {
free_extent_map(em); free_extent_map(em);
...@@ -6715,24 +6646,20 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock, ...@@ -6715,24 +6646,20 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock,
block_start, len, block_start, len,
orig_block_len, orig_block_len,
ram_bytes, type); ram_bytes, type);
if (IS_ERR(em)) { if (IS_ERR(em))
btrfs_end_transaction(trans, root);
goto unlock_err; goto unlock_err;
}
} }
ret = btrfs_add_ordered_extent_dio(inode, start, ret = btrfs_add_ordered_extent_dio(inode, start,
block_start, len, len, type); block_start, len, len, type);
btrfs_end_transaction(trans, root);
if (ret) { if (ret) {
free_extent_map(em); free_extent_map(em);
goto unlock_err; goto unlock_err;
} }
goto unlock; goto unlock;
} }
btrfs_end_transaction(trans, root);
} }
must_cow:
/* /*
* this will cow the extent, reset the len in case we changed * this will cow the extent, reset the len in case we changed
* it above * it above
...@@ -8495,8 +8422,8 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode, ...@@ -8495,8 +8422,8 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode,
cur_bytes = min(num_bytes, 256ULL * 1024 * 1024); cur_bytes = min(num_bytes, 256ULL * 1024 * 1024);
cur_bytes = max(cur_bytes, min_size); cur_bytes = max(cur_bytes, min_size);
ret = btrfs_reserve_extent(trans, root, cur_bytes, ret = btrfs_reserve_extent(root, cur_bytes, min_size, 0,
min_size, 0, *alloc_hint, &ins, 1); *alloc_hint, &ins, 1);
if (ret) { if (ret) {
if (own_trans) if (own_trans)
btrfs_end_transaction(trans, root); btrfs_end_transaction(trans, root);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment