summaryrefslogtreecommitdiffstats
path: root/fs/btrfs/extent-tree.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/extent-tree.c')
-rw-r--r--fs/btrfs/extent-tree.c61
1 files changed, 35 insertions, 26 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index e785f0a0632..af2de30dbea 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -1794,7 +1794,7 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags,
*space_info = found;
return 0;
}
- found = kmalloc(sizeof(*found), GFP_NOFS);
+ found = kzalloc(sizeof(*found), GFP_NOFS);
if (!found)
return -ENOMEM;
@@ -1807,6 +1807,7 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags,
found->bytes_used = bytes_used;
found->bytes_pinned = 0;
found->bytes_reserved = 0;
+ found->bytes_readonly = 0;
found->full = 0;
found->force_alloc = 0;
*space_info = found;
@@ -1829,6 +1830,19 @@ static void set_avail_alloc_bits(struct btrfs_fs_info *fs_info, u64 flags)
}
}
+static void set_block_group_readonly(struct btrfs_block_group_cache *cache)
+{
+ spin_lock(&cache->space_info->lock);
+ spin_lock(&cache->lock);
+ if (!cache->ro) {
+ cache->space_info->bytes_readonly += cache->key.offset -
+ btrfs_block_group_used(&cache->item);
+ cache->ro = 1;
+ }
+ spin_unlock(&cache->lock);
+ spin_unlock(&cache->space_info->lock);
+}
+
static u64 reduce_alloc_profile(struct btrfs_root *root, u64 flags)
{
u64 num_devices = root->fs_info->fs_devices->num_devices;
@@ -1865,7 +1879,9 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans,
u64 thresh;
u64 start;
u64 num_bytes;
- int ret = 0, waited = 0;
+ int ret = 0;
+
+ mutex_lock(&extent_root->fs_info->chunk_mutex);
flags = reduce_alloc_profile(extent_root, flags);
@@ -1887,46 +1903,28 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans,
goto out;
}
- thresh = div_factor(space_info->total_bytes, 6);
+ thresh = space_info->total_bytes - space_info->bytes_readonly;
+ thresh = div_factor(thresh, 6);
if (!force &&
(space_info->bytes_used + space_info->bytes_pinned +
space_info->bytes_reserved + alloc_bytes) < thresh) {
spin_unlock(&space_info->lock);
goto out;
}
-
spin_unlock(&space_info->lock);
- ret = mutex_trylock(&extent_root->fs_info->chunk_mutex);
- if (!ret && !force) {
- goto out;
- } else if (!ret) {
- mutex_lock(&extent_root->fs_info->chunk_mutex);
- waited = 1;
- }
-
- if (waited) {
- spin_lock(&space_info->lock);
- if (space_info->full) {
- spin_unlock(&space_info->lock);
- goto out_unlock;
- }
- spin_unlock(&space_info->lock);
- }
-
ret = btrfs_alloc_chunk(trans, extent_root, &start, &num_bytes, flags);
if (ret) {
printk("space info full %Lu\n", flags);
space_info->full = 1;
- goto out_unlock;
+ goto out;
}
ret = btrfs_make_block_group(trans, extent_root, 0, flags,
BTRFS_FIRST_CHUNK_TREE_OBJECTID, start, num_bytes);
BUG_ON(ret);
-out_unlock:
- mutex_unlock(&extent_root->fs_info->chunk_mutex);
out:
+ mutex_unlock(&extent_root->fs_info->chunk_mutex);
return ret;
}
@@ -1956,12 +1954,18 @@ static int update_block_group(struct btrfs_trans_handle *trans,
if (alloc) {
old_val += num_bytes;
cache->space_info->bytes_used += num_bytes;
+ if (cache->ro) {
+ cache->space_info->bytes_readonly -= num_bytes;
+ WARN_ON(1);
+ }
btrfs_set_block_group_used(&cache->item, old_val);
spin_unlock(&cache->lock);
spin_unlock(&cache->space_info->lock);
} else {
old_val -= num_bytes;
cache->space_info->bytes_used -= num_bytes;
+ if (cache->ro)
+ cache->space_info->bytes_readonly += num_bytes;
btrfs_set_block_group_used(&cache->item, old_val);
spin_unlock(&cache->lock);
spin_unlock(&cache->space_info->lock);
@@ -5560,8 +5564,7 @@ int btrfs_relocate_block_group(struct btrfs_root *root, u64 group_start)
BUG_ON(IS_ERR(reloc_inode));
__alloc_chunk_for_shrink(root, block_group, 1);
- block_group->ro = 1;
- block_group->space_info->total_bytes -= block_group->key.offset;
+ set_block_group_readonly(block_group);
btrfs_start_delalloc_inodes(info->tree_root);
btrfs_wait_ordered_extents(info->tree_root, 0);
@@ -5868,6 +5871,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
block_group = btrfs_lookup_block_group(root->fs_info, group_start);
BUG_ON(!block_group);
+ BUG_ON(!block_group->ro);
memcpy(&key, &block_group->key, sizeof(key));
@@ -5881,6 +5885,11 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
list_del(&block_group->list);
up_write(&block_group->space_info->groups_sem);
+ spin_lock(&block_group->space_info->lock);
+ block_group->space_info->total_bytes -= block_group->key.offset;
+ block_group->space_info->bytes_readonly -= block_group->key.offset;
+ spin_unlock(&block_group->space_info->lock);
+
/*
memset(shrink_block_group, 0, sizeof(*shrink_block_group));
kfree(shrink_block_group);