diff options
author | Josef Bacik <josef@redhat.com> | 2011-01-24 16:43:20 -0500 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2011-01-28 16:40:37 -0500 |
commit | 68a82277b8619e6d0f2738b1d9b160b627e81e92 (patch) | |
tree | 91d0f86f009cbbd8bf16643e41fb090a08e859a7 /fs | |
parent | e9e22899de661af94cb9995885fd04e4c738838b (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.c | 28 |
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 | } |