aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosef Bacik <jbacik@fusionio.com>2013-01-30 17:02:51 -0500
committerJosef Bacik <jbacik@fusionio.com>2013-02-20 12:59:13 -0500
commit96f1bb57771f71bf1d55d5031a1cf47908494330 (patch)
treea5333d0eb2a778a043182dfedd1f8faa3fc69d87
parent0f5d42b287f32417e54485d79f2318cf2970b37d (diff)
Btrfs: do not overcommit if we don't have enough space for global rsv
Because of how little we allocate chunks now we can get really tight on metadata space before we will allocate a new chunk. This resulted in being unable to add device extents when allocating a new metadata chunk as we did not have enough space. This is because we were allowed to overcommit too much metadata without actually making sure we had enough space to make allocations. The idea behind overcommit is that we are allowed to say "sure you can have that reservation" when most of the free space is occupied by reservations, not actual allocations. But in this case where a majority of the total space is in use by actual allocations we can screw ourselves by not being able to make real allocations when it matters. So make sure we have enough real space for our global reserve, and if not then don't allow overcommitting. Thanks, Reported-and-tested-by: Jim Schutt <jaschut@sandia.gov> Signed-off-by: Josef Bacik <jbacik@fusionio.com>
-rw-r--r--fs/btrfs/extent-tree.c21
1 files changed, 19 insertions, 2 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index faff98f720de..e035731b3608 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -3672,13 +3672,30 @@ static int can_overcommit(struct btrfs_root *root,
3672 struct btrfs_space_info *space_info, u64 bytes, 3672 struct btrfs_space_info *space_info, u64 bytes,
3673 enum btrfs_reserve_flush_enum flush) 3673 enum btrfs_reserve_flush_enum flush)
3674{ 3674{
3675 struct btrfs_block_rsv *global_rsv = &root->fs_info->global_block_rsv;
3675 u64 profile = btrfs_get_alloc_profile(root, 0); 3676 u64 profile = btrfs_get_alloc_profile(root, 0);
3677 u64 rsv_size = 0;
3676 u64 avail; 3678 u64 avail;
3677 u64 used; 3679 u64 used;
3678 3680
3679 used = space_info->bytes_used + space_info->bytes_reserved + 3681 used = space_info->bytes_used + space_info->bytes_reserved +
3680 space_info->bytes_pinned + space_info->bytes_readonly + 3682 space_info->bytes_pinned + space_info->bytes_readonly;
3681 space_info->bytes_may_use; 3683
3684 spin_lock(&global_rsv->lock);
3685 rsv_size = global_rsv->size;
3686 spin_unlock(&global_rsv->lock);
3687
3688 /*
3689 * We only want to allow over committing if we have lots of actual space
3690 * free, but if we don't have enough space to handle the global reserve
3691 * space then we could end up having a real enospc problem when trying
3692 * to allocate a chunk or some other such important allocation.
3693 */
3694 rsv_size <<= 1;
3695 if (used + rsv_size >= space_info->total_bytes)
3696 return 0;
3697
3698 used += space_info->bytes_may_use;
3682 3699
3683 spin_lock(&root->fs_info->free_chunk_lock); 3700 spin_lock(&root->fs_info->free_chunk_lock);
3684 avail = root->fs_info->free_chunk_space; 3701 avail = root->fs_info->free_chunk_space;