aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/extent-tree.c74
1 files changed, 31 insertions, 43 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index db0b23b14f20..05e1386b8bec 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -5106,11 +5106,11 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans,
5106 struct btrfs_root *root = orig_root->fs_info->extent_root; 5106 struct btrfs_root *root = orig_root->fs_info->extent_root;
5107 struct btrfs_free_cluster *last_ptr = NULL; 5107 struct btrfs_free_cluster *last_ptr = NULL;
5108 struct btrfs_block_group_cache *block_group = NULL; 5108 struct btrfs_block_group_cache *block_group = NULL;
5109 struct btrfs_block_group_cache *used_block_group;
5109 int empty_cluster = 2 * 1024 * 1024; 5110 int empty_cluster = 2 * 1024 * 1024;
5110 int allowed_chunk_alloc = 0; 5111 int allowed_chunk_alloc = 0;
5111 int done_chunk_alloc = 0; 5112 int done_chunk_alloc = 0;
5112 struct btrfs_space_info *space_info; 5113 struct btrfs_space_info *space_info;
5113 int last_ptr_loop = 0;
5114 int loop = 0; 5114 int loop = 0;
5115 int index = 0; 5115 int index = 0;
5116 int alloc_type = (data & BTRFS_BLOCK_GROUP_DATA) ? 5116 int alloc_type = (data & BTRFS_BLOCK_GROUP_DATA) ?
@@ -5172,6 +5172,7 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans,
5172ideal_cache: 5172ideal_cache:
5173 block_group = btrfs_lookup_block_group(root->fs_info, 5173 block_group = btrfs_lookup_block_group(root->fs_info,
5174 search_start); 5174 search_start);
5175 used_block_group = block_group;
5175 /* 5176 /*
5176 * we don't want to use the block group if it doesn't match our 5177 * we don't want to use the block group if it doesn't match our
5177 * allocation bits, or if its not cached. 5178 * allocation bits, or if its not cached.
@@ -5209,6 +5210,7 @@ search:
5209 u64 offset; 5210 u64 offset;
5210 int cached; 5211 int cached;
5211 5212
5213 used_block_group = block_group;
5212 btrfs_get_block_group(block_group); 5214 btrfs_get_block_group(block_group);
5213 search_start = block_group->key.objectid; 5215 search_start = block_group->key.objectid;
5214 5216
@@ -5294,49 +5296,33 @@ alloc:
5294 * people trying to start a new cluster 5296 * people trying to start a new cluster
5295 */ 5297 */
5296 spin_lock(&last_ptr->refill_lock); 5298 spin_lock(&last_ptr->refill_lock);
5297 if (!last_ptr->block_group || 5299 used_block_group = last_ptr->block_group;
5298 last_ptr->block_group->ro || 5300 if (used_block_group != block_group &&
5299 !block_group_bits(last_ptr->block_group, data)) 5301 (!used_block_group ||
5302 used_block_group->ro ||
5303 !block_group_bits(used_block_group, data))) {
5304 used_block_group = block_group;
5300 goto refill_cluster; 5305 goto refill_cluster;
5306 }
5307
5308 if (used_block_group != block_group)
5309 btrfs_get_block_group(used_block_group);
5301 5310
5302 offset = btrfs_alloc_from_cluster(block_group, last_ptr, 5311 offset = btrfs_alloc_from_cluster(used_block_group,
5303 num_bytes, search_start); 5312 last_ptr, num_bytes, used_block_group->key.objectid);
5304 if (offset) { 5313 if (offset) {
5305 /* we have a block, we're done */ 5314 /* we have a block, we're done */
5306 spin_unlock(&last_ptr->refill_lock); 5315 spin_unlock(&last_ptr->refill_lock);
5307 goto checks; 5316 goto checks;
5308 } 5317 }
5309 5318
5310 spin_lock(&last_ptr->lock); 5319 WARN_ON(last_ptr->block_group != used_block_group);
5311 /* 5320 if (used_block_group != block_group) {
5312 * whoops, this cluster doesn't actually point to 5321 btrfs_put_block_group(used_block_group);
5313 * this block group. Get a ref on the block 5322 used_block_group = block_group;
5314 * group is does point to and try again
5315 */
5316 if (!last_ptr_loop && last_ptr->block_group &&
5317 last_ptr->block_group != block_group &&
5318 index <=
5319 get_block_group_index(last_ptr->block_group)) {
5320
5321 btrfs_put_block_group(block_group);
5322 block_group = last_ptr->block_group;
5323 btrfs_get_block_group(block_group);
5324 spin_unlock(&last_ptr->lock);
5325 spin_unlock(&last_ptr->refill_lock);
5326
5327 last_ptr_loop = 1;
5328 search_start = block_group->key.objectid;
5329 /*
5330 * we know this block group is properly
5331 * in the list because
5332 * btrfs_remove_block_group, drops the
5333 * cluster before it removes the block
5334 * group from the list
5335 */
5336 goto have_block_group;
5337 } 5323 }
5338 spin_unlock(&last_ptr->lock);
5339refill_cluster: 5324refill_cluster:
5325 BUG_ON(used_block_group != block_group);
5340 /* If we are on LOOP_NO_EMPTY_SIZE, we can't 5326 /* If we are on LOOP_NO_EMPTY_SIZE, we can't
5341 * set up a new clusters, so lets just skip it 5327 * set up a new clusters, so lets just skip it
5342 * and let the allocator find whatever block 5328 * and let the allocator find whatever block
@@ -5357,8 +5343,6 @@ refill_cluster:
5357 */ 5343 */
5358 btrfs_return_cluster_to_free_space(NULL, last_ptr); 5344 btrfs_return_cluster_to_free_space(NULL, last_ptr);
5359 5345
5360 last_ptr_loop = 0;
5361
5362 /* allocate a cluster in this block group */ 5346 /* allocate a cluster in this block group */
5363 ret = btrfs_find_space_cluster(trans, root, 5347 ret = btrfs_find_space_cluster(trans, root,
5364 block_group, last_ptr, 5348 block_group, last_ptr,
@@ -5425,14 +5409,14 @@ checks:
5425 search_start = stripe_align(root, offset); 5409 search_start = stripe_align(root, offset);
5426 /* move on to the next group */ 5410 /* move on to the next group */
5427 if (search_start + num_bytes >= search_end) { 5411 if (search_start + num_bytes >= search_end) {
5428 btrfs_add_free_space(block_group, offset, num_bytes); 5412 btrfs_add_free_space(used_block_group, offset, num_bytes);
5429 goto loop; 5413 goto loop;
5430 } 5414 }
5431 5415
5432 /* move on to the next group */ 5416 /* move on to the next group */
5433 if (search_start + num_bytes > 5417 if (search_start + num_bytes >
5434 block_group->key.objectid + block_group->key.offset) { 5418 used_block_group->key.objectid + used_block_group->key.offset) {
5435 btrfs_add_free_space(block_group, offset, num_bytes); 5419 btrfs_add_free_space(used_block_group, offset, num_bytes);
5436 goto loop; 5420 goto loop;
5437 } 5421 }
5438 5422
@@ -5440,14 +5424,14 @@ checks:
5440 ins->offset = num_bytes; 5424 ins->offset = num_bytes;
5441 5425
5442 if (offset < search_start) 5426 if (offset < search_start)
5443 btrfs_add_free_space(block_group, offset, 5427 btrfs_add_free_space(used_block_group, offset,
5444 search_start - offset); 5428 search_start - offset);
5445 BUG_ON(offset > search_start); 5429 BUG_ON(offset > search_start);
5446 5430
5447 ret = btrfs_update_reserved_bytes(block_group, num_bytes, 5431 ret = btrfs_update_reserved_bytes(used_block_group, num_bytes,
5448 alloc_type); 5432 alloc_type);
5449 if (ret == -EAGAIN) { 5433 if (ret == -EAGAIN) {
5450 btrfs_add_free_space(block_group, offset, num_bytes); 5434 btrfs_add_free_space(used_block_group, offset, num_bytes);
5451 goto loop; 5435 goto loop;
5452 } 5436 }
5453 5437
@@ -5456,15 +5440,19 @@ checks:
5456 ins->offset = num_bytes; 5440 ins->offset = num_bytes;
5457 5441
5458 if (offset < search_start) 5442 if (offset < search_start)
5459 btrfs_add_free_space(block_group, offset, 5443 btrfs_add_free_space(used_block_group, offset,
5460 search_start - offset); 5444 search_start - offset);
5461 BUG_ON(offset > search_start); 5445 BUG_ON(offset > search_start);
5446 if (used_block_group != block_group)
5447 btrfs_put_block_group(used_block_group);
5462 btrfs_put_block_group(block_group); 5448 btrfs_put_block_group(block_group);
5463 break; 5449 break;
5464loop: 5450loop:
5465 failed_cluster_refill = false; 5451 failed_cluster_refill = false;
5466 failed_alloc = false; 5452 failed_alloc = false;
5467 BUG_ON(index != get_block_group_index(block_group)); 5453 BUG_ON(index != get_block_group_index(block_group));
5454 if (used_block_group != block_group)
5455 btrfs_put_block_group(used_block_group);
5468 btrfs_put_block_group(block_group); 5456 btrfs_put_block_group(block_group);
5469 } 5457 }
5470 up_read(&space_info->groups_sem); 5458 up_read(&space_info->groups_sem);