aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorChris Mason <clm@fb.com>2015-02-04 09:59:29 -0500
committerChris Mason <clm@fb.com>2015-04-10 17:06:34 -0400
commit28f75a0e6cdfbce8115487ecbc0968a2c4e01806 (patch)
tree14c32d9251117f3ec0f771e95ab17c1d96fe2b94 /fs
parent1262133b8d6f10f5ca7621cd4cf65ddf6254126a (diff)
Btrfs: refill block reserves during truncate
When truncate starts, it allocates some space in the block reserves so that we'll have enough to update metadata along the way. For very large files, we can easily go through all of that space as we loop through the extents. This changes truncate to refill the space reservation as it progresses through the file. Signed-off-by: Chris Mason <clm@fb.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/ctree.h3
-rw-r--r--fs/btrfs/extent-tree.c9
-rw-r--r--fs/btrfs/inode.c45
3 files changed, 46 insertions, 11 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 95944b81ed5c..6bf16d5134c5 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -3297,6 +3297,9 @@ static inline gfp_t btrfs_alloc_write_mask(struct address_space *mapping)
3297} 3297}
3298 3298
3299/* extent-tree.c */ 3299/* extent-tree.c */
3300
3301u64 btrfs_csum_bytes_to_leaves(struct btrfs_root *root, u64 csum_bytes);
3302
3300static inline u64 btrfs_calc_trans_metadata_size(struct btrfs_root *root, 3303static inline u64 btrfs_calc_trans_metadata_size(struct btrfs_root *root,
3301 unsigned num_items) 3304 unsigned num_items)
3302{ 3305{
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index a6f88eb57b39..75f4bed6e6db 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -2636,7 +2636,7 @@ static inline u64 heads_to_leaves(struct btrfs_root *root, u64 heads)
2636 * Takes the number of bytes to be csumm'ed and figures out how many leaves it 2636 * Takes the number of bytes to be csumm'ed and figures out how many leaves it
2637 * would require to store the csums for that many bytes. 2637 * would require to store the csums for that many bytes.
2638 */ 2638 */
2639static u64 csum_bytes_to_leaves(struct btrfs_root *root, u64 csum_bytes) 2639u64 btrfs_csum_bytes_to_leaves(struct btrfs_root *root, u64 csum_bytes)
2640{ 2640{
2641 u64 csum_size; 2641 u64 csum_size;
2642 u64 num_csums_per_leaf; 2642 u64 num_csums_per_leaf;
@@ -2665,7 +2665,7 @@ int btrfs_check_space_for_delayed_refs(struct btrfs_trans_handle *trans,
2665 if (num_heads > 1) 2665 if (num_heads > 1)
2666 num_bytes += (num_heads - 1) * root->nodesize; 2666 num_bytes += (num_heads - 1) * root->nodesize;
2667 num_bytes <<= 1; 2667 num_bytes <<= 1;
2668 num_bytes += csum_bytes_to_leaves(root, csum_bytes) * root->nodesize; 2668 num_bytes += btrfs_csum_bytes_to_leaves(root, csum_bytes) * root->nodesize;
2669 global_rsv = &root->fs_info->global_block_rsv; 2669 global_rsv = &root->fs_info->global_block_rsv;
2670 2670
2671 /* 2671 /*
@@ -5098,13 +5098,12 @@ static u64 calc_csum_metadata_size(struct inode *inode, u64 num_bytes,
5098 BTRFS_I(inode)->csum_bytes == 0) 5098 BTRFS_I(inode)->csum_bytes == 0)
5099 return 0; 5099 return 0;
5100 5100
5101 old_csums = csum_bytes_to_leaves(root, BTRFS_I(inode)->csum_bytes); 5101 old_csums = btrfs_csum_bytes_to_leaves(root, BTRFS_I(inode)->csum_bytes);
5102
5103 if (reserve) 5102 if (reserve)
5104 BTRFS_I(inode)->csum_bytes += num_bytes; 5103 BTRFS_I(inode)->csum_bytes += num_bytes;
5105 else 5104 else
5106 BTRFS_I(inode)->csum_bytes -= num_bytes; 5105 BTRFS_I(inode)->csum_bytes -= num_bytes;
5107 num_csums = csum_bytes_to_leaves(root, BTRFS_I(inode)->csum_bytes); 5106 num_csums = btrfs_csum_bytes_to_leaves(root, BTRFS_I(inode)->csum_bytes);
5108 5107
5109 /* No change, no need to reserve more */ 5108 /* No change, no need to reserve more */
5110 if (old_csums == num_csums) 5109 if (old_csums == num_csums)
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index cec23cf812ee..88537c52e114 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -4163,6 +4163,21 @@ out:
4163 return err; 4163 return err;
4164} 4164}
4165 4165
4166static int truncate_space_check(struct btrfs_trans_handle *trans,
4167 struct btrfs_root *root,
4168 u64 bytes_deleted)
4169{
4170 int ret;
4171
4172 bytes_deleted = btrfs_csum_bytes_to_leaves(root, bytes_deleted);
4173 ret = btrfs_block_rsv_add(root, &root->fs_info->trans_block_rsv,
4174 bytes_deleted, BTRFS_RESERVE_NO_FLUSH);
4175 if (!ret)
4176 trans->bytes_reserved += bytes_deleted;
4177 return ret;
4178
4179}
4180
4166/* 4181/*
4167 * this can truncate away extent items, csum items and directory items. 4182 * this can truncate away extent items, csum items and directory items.
4168 * It starts at a high offset and removes keys until it can't find 4183 * It starts at a high offset and removes keys until it can't find
@@ -4201,6 +4216,7 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
4201 u64 bytes_deleted = 0; 4216 u64 bytes_deleted = 0;
4202 bool be_nice = 0; 4217 bool be_nice = 0;
4203 bool should_throttle = 0; 4218 bool should_throttle = 0;
4219 bool should_end = 0;
4204 4220
4205 BUG_ON(new_size > 0 && min_type != BTRFS_EXTENT_DATA_KEY); 4221 BUG_ON(new_size > 0 && min_type != BTRFS_EXTENT_DATA_KEY);
4206 4222
@@ -4396,6 +4412,8 @@ delete:
4396 } else { 4412 } else {
4397 break; 4413 break;
4398 } 4414 }
4415 should_throttle = 0;
4416
4399 if (found_extent && 4417 if (found_extent &&
4400 (test_bit(BTRFS_ROOT_REF_COWS, &root->state) || 4418 (test_bit(BTRFS_ROOT_REF_COWS, &root->state) ||
4401 root == root->fs_info->tree_root)) { 4419 root == root->fs_info->tree_root)) {
@@ -4409,17 +4427,24 @@ delete:
4409 if (btrfs_should_throttle_delayed_refs(trans, root)) 4427 if (btrfs_should_throttle_delayed_refs(trans, root))
4410 btrfs_async_run_delayed_refs(root, 4428 btrfs_async_run_delayed_refs(root,
4411 trans->delayed_ref_updates * 2, 0); 4429 trans->delayed_ref_updates * 2, 0);
4430 if (be_nice) {
4431 if (truncate_space_check(trans, root,
4432 extent_num_bytes)) {
4433 should_end = 1;
4434 }
4435 if (btrfs_should_throttle_delayed_refs(trans,
4436 root)) {
4437 should_throttle = 1;
4438 }
4439 }
4412 } 4440 }
4413 4441
4414 if (found_type == BTRFS_INODE_ITEM_KEY) 4442 if (found_type == BTRFS_INODE_ITEM_KEY)
4415 break; 4443 break;
4416 4444
4417 should_throttle =
4418 btrfs_should_throttle_delayed_refs(trans, root);
4419
4420 if (path->slots[0] == 0 || 4445 if (path->slots[0] == 0 ||
4421 path->slots[0] != pending_del_slot || 4446 path->slots[0] != pending_del_slot ||
4422 (be_nice && should_throttle)) { 4447 should_throttle || should_end) {
4423 if (pending_del_nr) { 4448 if (pending_del_nr) {
4424 ret = btrfs_del_items(trans, root, path, 4449 ret = btrfs_del_items(trans, root, path,
4425 pending_del_slot, 4450 pending_del_slot,
@@ -4432,7 +4457,7 @@ delete:
4432 pending_del_nr = 0; 4457 pending_del_nr = 0;
4433 } 4458 }
4434 btrfs_release_path(path); 4459 btrfs_release_path(path);
4435 if (be_nice && should_throttle) { 4460 if (should_throttle) {
4436 unsigned long updates = trans->delayed_ref_updates; 4461 unsigned long updates = trans->delayed_ref_updates;
4437 if (updates) { 4462 if (updates) {
4438 trans->delayed_ref_updates = 0; 4463 trans->delayed_ref_updates = 0;
@@ -4441,6 +4466,14 @@ delete:
4441 err = ret; 4466 err = ret;
4442 } 4467 }
4443 } 4468 }
4469 /*
4470 * if we failed to refill our space rsv, bail out
4471 * and let the transaction restart
4472 */
4473 if (should_end) {
4474 err = -EAGAIN;
4475 goto error;
4476 }
4444 goto search_again; 4477 goto search_again;
4445 } else { 4478 } else {
4446 path->slots[0]--; 4479 path->slots[0]--;
@@ -4460,7 +4493,7 @@ error:
4460 4493
4461 btrfs_free_path(path); 4494 btrfs_free_path(path);
4462 4495
4463 if (be_nice && btrfs_should_throttle_delayed_refs(trans, root)) { 4496 if (be_nice && bytes_deleted > 32 * 1024 * 1024) {
4464 unsigned long updates = trans->delayed_ref_updates; 4497 unsigned long updates = trans->delayed_ref_updates;
4465 if (updates) { 4498 if (updates) {
4466 trans->delayed_ref_updates = 0; 4499 trans->delayed_ref_updates = 0;