diff options
author | Josef Bacik <jbacik@fusionio.com> | 2013-08-14 14:02:47 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@fusionio.com> | 2013-09-01 08:05:05 -0400 |
commit | 00361589d2eebd90fca022148c763e40d3e90871 (patch) | |
tree | 161dfa7f29d5aa907de0fee6bdc487f9a2bcb342 /fs/btrfs/extent-tree.c | |
parent | 9ffba8cda917c0158857426f0e74b64d0206aaa9 (diff) |
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: Josef Bacik <jbacik@fusionio.com>
Signed-off-by: Chris Mason <chris.mason@fusionio.com>
Diffstat (limited to 'fs/btrfs/extent-tree.c')
-rw-r--r-- | fs/btrfs/extent-tree.c | 35 |
1 files changed, 22 insertions, 13 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 277d2c26b034..f1c1694d34b7 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -6121,8 +6121,7 @@ enum btrfs_loop_type { | |||
6121 | * ins->offset == number of blocks | 6121 | * ins->offset == number of blocks |
6122 | * Any available blocks before search_start are skipped. | 6122 | * Any available blocks before search_start are skipped. |
6123 | */ | 6123 | */ |
6124 | static noinline int find_free_extent(struct btrfs_trans_handle *trans, | 6124 | static noinline int find_free_extent(struct btrfs_root *orig_root, |
6125 | struct btrfs_root *orig_root, | ||
6126 | u64 num_bytes, u64 empty_size, | 6125 | u64 num_bytes, u64 empty_size, |
6127 | u64 hint_byte, struct btrfs_key *ins, | 6126 | u64 hint_byte, struct btrfs_key *ins, |
6128 | u64 flags) | 6127 | u64 flags) |
@@ -6345,10 +6344,10 @@ refill_cluster: | |||
6345 | block_group->full_stripe_len); | 6344 | block_group->full_stripe_len); |
6346 | 6345 | ||
6347 | /* allocate a cluster in this block group */ | 6346 | /* allocate a cluster in this block group */ |
6348 | ret = btrfs_find_space_cluster(trans, root, | 6347 | ret = btrfs_find_space_cluster(root, block_group, |
6349 | block_group, last_ptr, | 6348 | last_ptr, search_start, |
6350 | search_start, num_bytes, | 6349 | num_bytes, |
6351 | aligned_cluster); | 6350 | aligned_cluster); |
6352 | if (ret == 0) { | 6351 | if (ret == 0) { |
6353 | /* | 6352 | /* |
6354 | * now pull our allocation out of this | 6353 | * now pull our allocation out of this |
@@ -6479,17 +6478,28 @@ loop: | |||
6479 | index = 0; | 6478 | index = 0; |
6480 | loop++; | 6479 | loop++; |
6481 | if (loop == LOOP_ALLOC_CHUNK) { | 6480 | if (loop == LOOP_ALLOC_CHUNK) { |
6481 | struct btrfs_trans_handle *trans; | ||
6482 | |||
6483 | trans = btrfs_join_transaction(root); | ||
6484 | if (IS_ERR(trans)) { | ||
6485 | ret = PTR_ERR(trans); | ||
6486 | goto out; | ||
6487 | } | ||
6488 | |||
6482 | ret = do_chunk_alloc(trans, root, flags, | 6489 | ret = do_chunk_alloc(trans, root, flags, |
6483 | CHUNK_ALLOC_FORCE); | 6490 | CHUNK_ALLOC_FORCE); |
6484 | /* | 6491 | /* |
6485 | * Do not bail out on ENOSPC since we | 6492 | * Do not bail out on ENOSPC since we |
6486 | * can do more things. | 6493 | * can do more things. |
6487 | */ | 6494 | */ |
6488 | if (ret < 0 && ret != -ENOSPC) { | 6495 | if (ret < 0 && ret != -ENOSPC) |
6489 | btrfs_abort_transaction(trans, | 6496 | btrfs_abort_transaction(trans, |
6490 | root, ret); | 6497 | root, ret); |
6498 | else | ||
6499 | ret = 0; | ||
6500 | btrfs_end_transaction(trans, root); | ||
6501 | if (ret) | ||
6491 | goto out; | 6502 | goto out; |
6492 | } | ||
6493 | } | 6503 | } |
6494 | 6504 | ||
6495 | if (loop == LOOP_NO_EMPTY_SIZE) { | 6505 | if (loop == LOOP_NO_EMPTY_SIZE) { |
@@ -6553,8 +6563,7 @@ again: | |||
6553 | up_read(&info->groups_sem); | 6563 | up_read(&info->groups_sem); |
6554 | } | 6564 | } |
6555 | 6565 | ||
6556 | int btrfs_reserve_extent(struct btrfs_trans_handle *trans, | 6566 | int btrfs_reserve_extent(struct btrfs_root *root, |
6557 | struct btrfs_root *root, | ||
6558 | u64 num_bytes, u64 min_alloc_size, | 6567 | u64 num_bytes, u64 min_alloc_size, |
6559 | u64 empty_size, u64 hint_byte, | 6568 | u64 empty_size, u64 hint_byte, |
6560 | struct btrfs_key *ins, int is_data) | 6569 | struct btrfs_key *ins, int is_data) |
@@ -6566,8 +6575,8 @@ int btrfs_reserve_extent(struct btrfs_trans_handle *trans, | |||
6566 | flags = btrfs_get_alloc_profile(root, is_data); | 6575 | flags = btrfs_get_alloc_profile(root, is_data); |
6567 | again: | 6576 | again: |
6568 | WARN_ON(num_bytes < root->sectorsize); | 6577 | WARN_ON(num_bytes < root->sectorsize); |
6569 | ret = find_free_extent(trans, root, num_bytes, empty_size, | 6578 | ret = find_free_extent(root, num_bytes, empty_size, hint_byte, ins, |
6570 | hint_byte, ins, flags); | 6579 | flags); |
6571 | 6580 | ||
6572 | if (ret == -ENOSPC) { | 6581 | if (ret == -ENOSPC) { |
6573 | if (!final_tried) { | 6582 | if (!final_tried) { |
@@ -6955,7 +6964,7 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans, | |||
6955 | if (IS_ERR(block_rsv)) | 6964 | if (IS_ERR(block_rsv)) |
6956 | return ERR_CAST(block_rsv); | 6965 | return ERR_CAST(block_rsv); |
6957 | 6966 | ||
6958 | ret = btrfs_reserve_extent(trans, root, blocksize, blocksize, | 6967 | ret = btrfs_reserve_extent(root, blocksize, blocksize, |
6959 | empty_size, hint, &ins, 0); | 6968 | empty_size, hint, &ins, 0); |
6960 | if (ret) { | 6969 | if (ret) { |
6961 | unuse_block_rsv(root->fs_info, block_rsv, blocksize); | 6970 | unuse_block_rsv(root->fs_info, block_rsv, blocksize); |