Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7d7d6068 authored by Yan's avatar Yan Committed by David Woodhouse
Browse files

Btrfs: Fix cache_block_group to catch holes at the start of the group



Cache block group was overly complex and missed free blocks at the very start
of the group.  This patch simplifies things significantly.

Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent 6af858b2
Loading
Loading
Loading
Loading
+33 −28
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ static int cache_block_group(struct btrfs_root *root,
	u64 i;
	u64 last = 0;
	u64 hole_size;
	u64 first_free;
	int found = 0;

	root = root->fs_info->extent_root;
@@ -51,16 +52,22 @@ static int cache_block_group(struct btrfs_root *root,
	path = btrfs_alloc_path();
	if (!path)
		return -ENOMEM;

	path->reada = 2;
	first_free = block_group->key.objectid;
	key.objectid = block_group->key.objectid;
	key.flags = 0;
	key.offset = 0;

	btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
	ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);

	if (ret < 0)
		return ret;

	if (ret && path->slots[0] > 0)
		path->slots[0]--;

	while(1) {
		leaf = btrfs_buffer_leaf(path->nodes[0]);
		slot = path->slots[0];
@@ -71,50 +78,48 @@ static int cache_block_group(struct btrfs_root *root,
			if (ret == 0) {
				continue;
			} else {
				if (found) {
					hole_size = block_group->key.objectid +
						block_group->key.offset - last;
				} else {
					last = block_group->key.objectid;
					hole_size = block_group->key.offset;
				}
				for (i = 0; i < hole_size; i++) {
					set_radix_bit(extent_radix,
						      last + i);
				}
				break;
			}
		}

		btrfs_disk_key_to_cpu(&key, &leaf->items[slot].key);
		if (key.objectid < block_group->key.objectid) {
			if (key.objectid + key.offset > first_free)
				first_free = key.objectid + key.offset;
			goto next;
		}

		if (key.objectid >= block_group->key.objectid +
		    block_group->key.offset) {
			if (found) {
				hole_size = block_group->key.objectid +
					block_group->key.offset - last;
			} else {
				last = block_group->key.objectid;
				hole_size = block_group->key.offset;
			}
			for (i = 0; i < hole_size; i++) {
				set_radix_bit(extent_radix, last + i);
			}
			break;
		}

		if (btrfs_key_type(&key) == BTRFS_EXTENT_ITEM_KEY) {
			if (!found) {
				last = key.objectid + key.offset;
				last = first_free;
				found = 1;
			} else {
			}
			hole_size = key.objectid - last;
			for (i = 0; i < hole_size; i++) {
				set_radix_bit(extent_radix, last + i);
			}
			last = key.objectid + key.offset;
		}
		}
next:
		path->slots[0]++;
	}

	if (!found)
		last = first_free;
	if (block_group->key.objectid +
	    block_group->key.offset > last) {
		hole_size = block_group->key.objectid +
			block_group->key.offset - last;
		for (i = 0; i < hole_size; i++) {
			set_radix_bit(extent_radix,
					last + i);
		}
	}
	block_group->cached = 1;
err:
	btrfs_free_path(path);