Commit e19caa5f authored by Chris Mason's avatar Chris Mason
Browse files

Btrfs: Fix allocation routines to avoid intermixing data and metadata allocations

parent 6b80053d
Loading
Loading
Loading
Loading
+22 −16
Original line number Diff line number Diff line
@@ -165,7 +165,7 @@ static u64 find_search_start(struct btrfs_root *root,
{
	int ret;
	struct btrfs_block_group_cache *cache = *cache_ret;
	u64 last = max(search_start, cache->key.objectid);
	u64 last;
	u64 start = 0;
	u64 end = 0;

@@ -173,11 +173,14 @@ static u64 find_search_start(struct btrfs_root *root,
	ret = cache_block_group(root, cache);
	if (ret)
		goto out;
	last = max(search_start, cache->key.objectid);

	while(1) {
		ret = find_first_extent_bit(&root->fs_info->free_space_cache,
					    last, &start, &end, EXTENT_DIRTY);
		if (ret)
			goto out;
		if (ret) {
			goto new_group;
		}

		start = max(last, start);
		last = end + 1;
@@ -191,15 +194,13 @@ static u64 find_search_start(struct btrfs_root *root,
	return search_start;

new_group:
	cache = btrfs_lookup_block_group(root->fs_info,
					 last + cache->key.offset - 1);
	last = cache->key.objectid + cache->key.offset;
	cache = btrfs_lookup_block_group(root->fs_info, last);
	if (!cache) {
		return search_start;
	}
	cache = btrfs_find_block_group(root, cache,
				       last + cache->key.offset - 1, data, 0);
	cache = btrfs_find_block_group(root, cache, last, data, 0);
	*cache_ret = cache;
	last = min(cache->key.objectid, last);
	goto again;
}

@@ -257,11 +258,6 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root,
		if (used < div_factor(hint->key.offset, factor)) {
			return hint;
		}
		last = hint->key.offset * 3;
		if (hint->key.objectid >= last)
			last = max(search_start + hint->key.offset - 1,
				   hint->key.objectid - last);
		else
		last = hint->key.objectid + hint->key.offset;
		hint_last = last;
	} else {
@@ -913,7 +909,6 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
check_failed:
	search_start = find_search_start(root, &block_group,
					 search_start, total_needed, data);

	btrfs_init_path(path);
	ins->objectid = search_start;
	ins->offset = 0;
@@ -958,6 +953,9 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
				continue;
			if (ret < 0)
				goto error;

			search_start = max(search_start,
					   block_group->key.objectid);
			if (!start_found) {
				ins->objectid = search_start;
				ins->offset = search_end - search_start;
@@ -967,6 +965,7 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
			ins->objectid = last_byte > search_start ?
					last_byte : search_start;
			ins->offset = search_end - ins->objectid;
			BUG_ON(ins->objectid >= search_end);
			goto check_pending;
		}
		btrfs_item_key_to_cpu(l, &key, slot);
@@ -998,7 +997,7 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
		    block_group->key.offset) {
			btrfs_release_path(root, path);
			search_start = block_group->key.objectid +
				block_group->key.offset * 2;
				block_group->key.offset;
			goto new_group;
		}
next:
@@ -1015,6 +1014,12 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
	if (ins->objectid + num_bytes >= search_end)
		goto enospc;

	if (!full_scan && ins->objectid + num_bytes >= block_group->
	    key.objectid + block_group->key.offset) {
		search_start = block_group->key.objectid +
			block_group->key.offset;
		goto new_group;
	}
	if (test_range_bit(&info->extent_ins, ins->objectid,
			   ins->objectid + num_bytes -1, EXTENT_LOCKED, 0)) {
		search_start = ins->objectid + num_bytes;
@@ -1114,6 +1119,7 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
		set_extent_bits(&root->fs_info->extent_ins, ins->objectid,
				ins->objectid + ins->offset - 1,
				EXTENT_LOCKED, GFP_NOFS);
		WARN_ON(data == 1);
		goto update_block;
	}

+3 −3
Original line number Diff line number Diff line
@@ -981,7 +981,7 @@ int find_first_extent_bit(struct extent_map_tree *tree, u64 start,
	struct extent_state *state;
	int ret = 1;

	write_lock_irq(&tree->lock);
	read_lock_irq(&tree->lock);
	/*
	 * this search will find all the extents that end after
	 * our range starts.
@@ -993,7 +993,7 @@ int find_first_extent_bit(struct extent_map_tree *tree, u64 start,

	while(1) {
		state = rb_entry(node, struct extent_state, rb_node);
		if (state->state & bits) {
		if (state->end >= start && (state->state & bits)) {
			*start_ret = state->start;
			*end_ret = state->end;
			ret = 0;
@@ -1004,7 +1004,7 @@ int find_first_extent_bit(struct extent_map_tree *tree, u64 start,
			break;
	}
out:
	write_unlock_irq(&tree->lock);
	read_unlock_irq(&tree->lock);
	return ret;
}
EXPORT_SYMBOL(find_first_extent_bit);