Btrfs: Fix cache_block_group to catch holes at the start of the group
[deliverable/linux.git] / fs / btrfs / extent-tree.c
index b074ad1416ddca63329543e0d2c96f1c4437aa4a..9151850266b0bb7ae85cec3703d1bc4780f1bdb8 100644 (file)
@@ -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);
This page took 0.0371 seconds and 5 git commands to generate.