Răsfoiți Sursa

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: Chris Mason <chris.mason@oracle.com>
Yan 17 ani în urmă
părinte
comite
7d7d6068be
1 a modificat fișierele cu 33 adăugiri și 28 ștergeri
  1. 33 28
      fs/btrfs/extent-tree.c

+ 33 - 28
fs/btrfs/extent-tree.c

@@ -39,6 +39,7 @@ static int cache_block_group(struct btrfs_root *root,
 	u64 i;
 	u64 i;
 	u64 last = 0;
 	u64 last = 0;
 	u64 hole_size;
 	u64 hole_size;
+	u64 first_free;
 	int found = 0;
 	int found = 0;
 
 
 	root = root->fs_info->extent_root;
 	root = root->fs_info->extent_root;
@@ -51,16 +52,22 @@ static int cache_block_group(struct btrfs_root *root,
 	path = btrfs_alloc_path();
 	path = btrfs_alloc_path();
 	if (!path)
 	if (!path)
 		return -ENOMEM;
 		return -ENOMEM;
+
 	path->reada = 2;
 	path->reada = 2;
+	first_free = block_group->key.objectid;
 	key.objectid = block_group->key.objectid;
 	key.objectid = block_group->key.objectid;
 	key.flags = 0;
 	key.flags = 0;
 	key.offset = 0;
 	key.offset = 0;
+
 	btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
 	btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
 	ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
 	ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
+
 	if (ret < 0)
 	if (ret < 0)
 		return ret;
 		return ret;
+
 	if (ret && path->slots[0] > 0)
 	if (ret && path->slots[0] > 0)
 		path->slots[0]--;
 		path->slots[0]--;
+
 	while(1) {
 	while(1) {
 		leaf = btrfs_buffer_leaf(path->nodes[0]);
 		leaf = btrfs_buffer_leaf(path->nodes[0]);
 		slot = path->slots[0];
 		slot = path->slots[0];
@@ -71,50 +78,48 @@ static int cache_block_group(struct btrfs_root *root,
 			if (ret == 0) {
 			if (ret == 0) {
 				continue;
 				continue;
 			} else {
 			} 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;
 				break;
 			}
 			}
 		}
 		}
+
 		btrfs_disk_key_to_cpu(&key, &leaf->items[slot].key);
 		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 +
 		if (key.objectid >= block_group->key.objectid +
 		    block_group->key.offset) {
 		    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;
 			break;
 		}
 		}
+
 		if (btrfs_key_type(&key) == BTRFS_EXTENT_ITEM_KEY) {
 		if (btrfs_key_type(&key) == BTRFS_EXTENT_ITEM_KEY) {
 			if (!found) {
 			if (!found) {
-				last = key.objectid + key.offset;
+				last = first_free;
 				found = 1;
 				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;
 			}
 			}
+			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]++;
 		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;
 	block_group->cached = 1;
 err:
 err:
 	btrfs_free_path(path);
 	btrfs_free_path(path);