Skip to content

Commit

Permalink
Btrfs: fill the global reserve when unpinning space
Browse files Browse the repository at this point in the history
Dave gave me an image of a very full file system that would abort the
transaction because it ran out of space while committing the transaction.
This is because we would think there was plenty of room to create a snapshot
even though the global reserve was not full.  This happens because we
calculate the global reserve size before we unpin any space, so after we
unpin the space we allow reservations to occur even though we haven't
reserved all of the space for our global reserve.  Fix this by adding to the
global reserve while unpinning in order to make sure we always have enough
space to do our work.  With this patch we no longer end up with an aborted
transaction, we return ENOSPC properly to the person trying to create the
snapshot.  Thanks,

Signed-off-by: Josef Bacik <jbacik@fusionio.com>
Signed-off-by: Chris Mason <chris.mason@fusionio.com>
  • Loading branch information
Josef Bacik committed Dec 11, 2012
1 parent 32adf09 commit 7b398f8
Showing 1 changed file with 24 additions and 5 deletions.
29 changes: 24 additions & 5 deletions fs/btrfs/extent-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -4949,9 +4949,13 @@ static int unpin_extent_range(struct btrfs_root *root, u64 start, u64 end)
{
struct btrfs_fs_info *fs_info = root->fs_info;
struct btrfs_block_group_cache *cache = NULL;
struct btrfs_space_info *space_info;
struct btrfs_block_rsv *global_rsv = &fs_info->global_block_rsv;
u64 len;
bool readonly;

while (start <= end) {
readonly = false;
if (!cache ||
start >= cache->key.objectid + cache->key.offset) {
if (cache)
Expand All @@ -4969,15 +4973,30 @@ static int unpin_extent_range(struct btrfs_root *root, u64 start, u64 end)
}

start += len;
space_info = cache->space_info;

spin_lock(&cache->space_info->lock);
spin_lock(&space_info->lock);
spin_lock(&cache->lock);
cache->pinned -= len;
cache->space_info->bytes_pinned -= len;
if (cache->ro)
cache->space_info->bytes_readonly += len;
space_info->bytes_pinned -= len;
if (cache->ro) {
space_info->bytes_readonly += len;
readonly = true;
}
spin_unlock(&cache->lock);
spin_unlock(&cache->space_info->lock);
if (!readonly && global_rsv->space_info == space_info) {
spin_lock(&global_rsv->lock);
if (!global_rsv->full) {
len = min(len, global_rsv->size -
global_rsv->reserved);
global_rsv->reserved += len;
space_info->bytes_may_use += len;
if (global_rsv->reserved >= global_rsv->size)
global_rsv->full = 1;
}
spin_unlock(&global_rsv->lock);
}
spin_unlock(&space_info->lock);
}

if (cache)
Expand Down

0 comments on commit 7b398f8

Please sign in to comment.