aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorJosef Bacik <josef@redhat.com>2011-01-24 16:43:20 -0500
committerChris Mason <chris.mason@oracle.com>2011-01-28 16:40:37 -0500
commit68a82277b8619e6d0f2738b1d9b160b627e81e92 (patch)
tree91d0f86f009cbbd8bf16643e41fb090a08e859a7 /fs
parente9e22899de661af94cb9995885fd04e4c738838b (diff)
Btrfs: use the global block reserve if we cannot reserve space
We call use_block_rsv right before we make an allocation in order to make sure we have enough space. Now normally people have called btrfs_start_transaction() with the appropriate amount of space that we need, so we just use some of that pre-reserved space and move along happily. The problem is where people use btrfs_join_transaction(), which doesn't actually reserve any space. So we try and reserve space here, but we cannot flush delalloc, so this forces us to return -ENOSPC when in reality we have plenty of space. The most common symptom is seeing a bunch of "couldn't dirty inode" messages in syslog. With xfstests 224 we end up falling back to start_transaction and then doing all the flush delalloc stuff which causes to hang for a very long time. So instead steal from the global reserve, which is what this is meant for anyway. With this patch and the other 2 I have sent xfstests 224 now passes successfully. Thanks, Signed-off-by: Josef Bacik <josef@redhat.com> Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/extent-tree.c28
1 files changed, 27 insertions, 1 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 7af618dcf2c..ff6bbfd75cf 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -5646,6 +5646,7 @@ use_block_rsv(struct btrfs_trans_handle *trans,
5646 struct btrfs_root *root, u32 blocksize) 5646 struct btrfs_root *root, u32 blocksize)
5647{ 5647{
5648 struct btrfs_block_rsv *block_rsv; 5648 struct btrfs_block_rsv *block_rsv;
5649 struct btrfs_block_rsv *global_rsv = &root->fs_info->global_block_rsv;
5649 int ret; 5650 int ret;
5650 5651
5651 block_rsv = get_block_rsv(trans, root); 5652 block_rsv = get_block_rsv(trans, root);
@@ -5653,14 +5654,39 @@ use_block_rsv(struct btrfs_trans_handle *trans,
5653 if (block_rsv->size == 0) { 5654 if (block_rsv->size == 0) {
5654 ret = reserve_metadata_bytes(trans, root, block_rsv, 5655 ret = reserve_metadata_bytes(trans, root, block_rsv,
5655 blocksize, 0); 5656 blocksize, 0);
5656 if (ret) 5657 /*
5658 * If we couldn't reserve metadata bytes try and use some from
5659 * the global reserve.
5660 */
5661 if (ret && block_rsv != global_rsv) {
5662 ret = block_rsv_use_bytes(global_rsv, blocksize);
5663 if (!ret)
5664 return global_rsv;
5665 return ERR_PTR(ret);
5666 } else if (ret) {
5657 return ERR_PTR(ret); 5667 return ERR_PTR(ret);
5668 }
5658 return block_rsv; 5669 return block_rsv;
5659 } 5670 }
5660 5671
5661 ret = block_rsv_use_bytes(block_rsv, blocksize); 5672 ret = block_rsv_use_bytes(block_rsv, blocksize);
5662 if (!ret) 5673 if (!ret)
5663 return block_rsv; 5674 return block_rsv;
5675 if (ret) {
5676 WARN_ON(1);
5677 ret = reserve_metadata_bytes(trans, root, block_rsv, blocksize,
5678 0);
5679 if (!ret) {
5680 spin_lock(&block_rsv->lock);
5681 block_rsv->size += blocksize;
5682 spin_unlock(&block_rsv->lock);
5683 return block_rsv;
5684 } else if (ret && block_rsv != global_rsv) {
5685 ret = block_rsv_use_bytes(global_rsv, blocksize);
5686 if (!ret)
5687 return global_rsv;
5688 }
5689 }
5664 5690
5665 return ERR_PTR(-ENOSPC); 5691 return ERR_PTR(-ENOSPC);
5666} 5692}