summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYan <yanzheng@21cn.com>2007-09-15 00:15:28 +0400
committerDavid Woodhouse <dwmw2@hera.kernel.org>2007-09-15 00:15:28 +0400
commit7d7d6068bee9d8004ea7cc8a2ebda2c99a57caec (patch)
tree399cf89116a0110d74ea4c26562bd7aef380734a
parent6af858b24c0c4e91ce0b40b5dd5fdfc1fe2dda70 (diff)
downloadlinux-7d7d6068bee9d8004ea7cc8a2ebda2c99a57caec.tar.xz
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>
-rw-r--r--fs/btrfs/extent-tree.c61
1 files changed, 33 insertions, 28 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index b074ad1416dd..9151850266b0 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -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;
}
+ 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);