aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosef Bacik <jbacik@fusionio.com>2012-08-27 17:48:15 -0400
committerChris Mason <chris.mason@fusionio.com>2012-10-01 15:19:04 -0400
commitca7e70f59078046db28501519308c2061b0e7a6f (patch)
tree9685496d94625bc732e029f2a21f049506bf8618
parent06d3d22b456c2f87aeb1eb4517eeabb47e21fcc9 (diff)
Btrfs: do not needlessly restart the transaction for enospc
We will stop and restart a transaction every time we move to a different leaf when truncating a file. This is for enospc reasons, but really we could probably get away with doing this a little better by actually working until we hit an ENOSPC. So add a ->failfast flag to the block_rsv and set it when we do truncates which will fail as soon as the block rsv runs out of space, and then at that point we can stop and restart the transaction and refill the block rsv and carry on. This will make rm'ing of a file with lots of extents a bit faster. Thanks, Signed-off-by: Josef Bacik <jbacik@fusionio.com>
-rw-r--r--fs/btrfs/ctree.h1
-rw-r--r--fs/btrfs/extent-tree.c2
-rw-r--r--fs/btrfs/inode.c53
3 files changed, 20 insertions, 36 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 4b81ea3fa1b2..81c772b5dc8e 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -1034,6 +1034,7 @@ struct btrfs_block_rsv {
1034 struct btrfs_space_info *space_info; 1034 struct btrfs_space_info *space_info;
1035 spinlock_t lock; 1035 spinlock_t lock;
1036 unsigned int full; 1036 unsigned int full;
1037 unsigned int failfast;
1037}; 1038};
1038 1039
1039/* 1040/*
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 62fc92f2b9d7..df2f17b0ac5d 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -6308,7 +6308,7 @@ use_block_rsv(struct btrfs_trans_handle *trans,
6308 ret = block_rsv_use_bytes(block_rsv, blocksize); 6308 ret = block_rsv_use_bytes(block_rsv, blocksize);
6309 if (!ret) 6309 if (!ret)
6310 return block_rsv; 6310 return block_rsv;
6311 if (ret) { 6311 if (ret && !block_rsv->failfast) {
6312 static DEFINE_RATELIMIT_STATE(_rs, 6312 static DEFINE_RATELIMIT_STATE(_rs,
6313 DEFAULT_RATELIMIT_INTERVAL, 6313 DEFAULT_RATELIMIT_INTERVAL,
6314 /*DEFAULT_RATELIMIT_BURST*/ 2); 6314 /*DEFAULT_RATELIMIT_BURST*/ 2);
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 1b99fe8a129d..ca4fa05171ab 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -3448,12 +3448,6 @@ delete:
3448 3448
3449 if (path->slots[0] == 0 || 3449 if (path->slots[0] == 0 ||
3450 path->slots[0] != pending_del_slot) { 3450 path->slots[0] != pending_del_slot) {
3451 if (root->ref_cows &&
3452 BTRFS_I(inode)->location.objectid !=
3453 BTRFS_FREE_INO_OBJECTID) {
3454 err = -EAGAIN;
3455 goto out;
3456 }
3457 if (pending_del_nr) { 3451 if (pending_del_nr) {
3458 ret = btrfs_del_items(trans, root, path, 3452 ret = btrfs_del_items(trans, root, path,
3459 pending_del_slot, 3453 pending_del_slot,
@@ -3826,6 +3820,7 @@ void btrfs_evict_inode(struct inode *inode)
3826 goto no_delete; 3820 goto no_delete;
3827 } 3821 }
3828 rsv->size = min_size; 3822 rsv->size = min_size;
3823 rsv->failfast = 1;
3829 global_rsv = &root->fs_info->global_block_rsv; 3824 global_rsv = &root->fs_info->global_block_rsv;
3830 3825
3831 btrfs_i_size_write(inode, 0); 3826 btrfs_i_size_write(inode, 0);
@@ -3870,7 +3865,7 @@ void btrfs_evict_inode(struct inode *inode)
3870 trans->block_rsv = rsv; 3865 trans->block_rsv = rsv;
3871 3866
3872 ret = btrfs_truncate_inode_items(trans, root, inode, 0, 0); 3867 ret = btrfs_truncate_inode_items(trans, root, inode, 0, 0);
3873 if (ret != -EAGAIN) 3868 if (ret != -ENOSPC)
3874 break; 3869 break;
3875 3870
3876 nr = trans->blocks_used; 3871 nr = trans->blocks_used;
@@ -6852,6 +6847,7 @@ static int btrfs_truncate(struct inode *inode)
6852 if (!rsv) 6847 if (!rsv)
6853 return -ENOMEM; 6848 return -ENOMEM;
6854 rsv->size = min_size; 6849 rsv->size = min_size;
6850 rsv->failfast = 1;
6855 6851
6856 /* 6852 /*
6857 * 1 for the truncate slack space 6853 * 1 for the truncate slack space
@@ -6905,37 +6901,13 @@ static int btrfs_truncate(struct inode *inode)
6905 * safe. 6901 * safe.
6906 */ 6902 */
6907 set_bit(BTRFS_INODE_NEEDS_FULL_SYNC, &BTRFS_I(inode)->runtime_flags); 6903 set_bit(BTRFS_INODE_NEEDS_FULL_SYNC, &BTRFS_I(inode)->runtime_flags);
6904 trans->block_rsv = rsv;
6908 6905
6909 while (1) { 6906 while (1) {
6910 ret = btrfs_block_rsv_refill(root, rsv, min_size);
6911 if (ret) {
6912 /*
6913 * This can only happen with the original transaction we
6914 * started above, every other time we shouldn't have a
6915 * transaction started yet.
6916 */
6917 if (ret == -EAGAIN)
6918 goto end_trans;
6919 err = ret;
6920 break;
6921 }
6922
6923 if (!trans) {
6924 /* Just need the 1 for updating the inode */
6925 trans = btrfs_start_transaction(root, 1);
6926 if (IS_ERR(trans)) {
6927 ret = err = PTR_ERR(trans);
6928 trans = NULL;
6929 break;
6930 }
6931 }
6932
6933 trans->block_rsv = rsv;
6934
6935 ret = btrfs_truncate_inode_items(trans, root, inode, 6907 ret = btrfs_truncate_inode_items(trans, root, inode,
6936 inode->i_size, 6908 inode->i_size,
6937 BTRFS_EXTENT_DATA_KEY); 6909 BTRFS_EXTENT_DATA_KEY);
6938 if (ret != -EAGAIN) { 6910 if (ret != -ENOSPC) {
6939 err = ret; 6911 err = ret;
6940 break; 6912 break;
6941 } 6913 }
@@ -6946,11 +6918,22 @@ static int btrfs_truncate(struct inode *inode)
6946 err = ret; 6918 err = ret;
6947 break; 6919 break;
6948 } 6920 }
6949end_trans: 6921
6950 nr = trans->blocks_used; 6922 nr = trans->blocks_used;
6951 btrfs_end_transaction(trans, root); 6923 btrfs_end_transaction(trans, root);
6952 trans = NULL;
6953 btrfs_btree_balance_dirty(root, nr); 6924 btrfs_btree_balance_dirty(root, nr);
6925
6926 trans = btrfs_start_transaction(root, 2);
6927 if (IS_ERR(trans)) {
6928 ret = err = PTR_ERR(trans);
6929 trans = NULL;
6930 break;
6931 }
6932
6933 ret = btrfs_block_rsv_migrate(&root->fs_info->trans_block_rsv,
6934 rsv, min_size);
6935 BUG_ON(ret); /* shouldn't happen */
6936 trans->block_rsv = rsv;
6954 } 6937 }
6955 6938
6956 if (ret == 0 && inode->i_nlink > 0) { 6939 if (ret == 0 && inode->i_nlink > 0) {