Btrfs: early reference counting
[deliverable/linux.git] / fs / btrfs / extent-tree.c
index 26321524c186de63f46a5d33169535859586315f..25d9cd169209d362b4d77ed9a07c5a53bc541344 100644 (file)
  */
 #define CTREE_EXTENT_PENDING 0
 
+static int inc_block_ref(struct ctree_root *root, u64 blocknr)
+{
+       struct ctree_path path;
+       int ret;
+       struct key key;
+       struct leaf *l;
+       struct extent_item *item;
+       init_path(&path);
+       key.objectid = blocknr;
+       key.flags = 0;
+       key.offset = 1;
+       ret = search_slot(root->extent_root, &key, &path, 0, 1);
+       BUG_ON(ret != 0);
+       l = &path.nodes[0]->leaf;
+       item = (struct extent_item *)(l->data +
+                                     l->items[path.slots[0]].offset);
+       item->refs++;
+       BUG_ON(list_empty(&path.nodes[0]->dirty));
+       release_path(root->extent_root, &path);
+       return 0;
+}
+
+int btrfs_inc_ref(struct ctree_root *root, struct tree_buffer *buf)
+{
+       u64 blocknr;
+       int i;
+       for (i = 0; i < buf->node.header.nritems; i++) {
+               blocknr = buf->node.blockptrs[i];
+               inc_block_ref(root, blocknr);
+       }
+       return 0;
+}
+
 /*
  * find all the blocks marked as pending in the radix tree and remove
  * them from the extent map
@@ -39,7 +72,7 @@ static int del_pending_extents(struct ctree_root *extent_root)
                        key.flags = 0;
                        key.offset = 1;
                        init_path(&path);
-                       ret = search_slot(extent_root, &key, &path, 0);
+                       ret = search_slot(extent_root, &key, &path, -1, 1);
                        if (ret) {
                                print_tree(extent_root, extent_root->node);
                                printf("unable to find %Lu\n", key.objectid);
@@ -83,7 +116,7 @@ int free_extent(struct ctree_root *root, u64 blocknr, u64 num_blocks)
                return 0;
        }
        init_path(&path);
-       ret = search_slot(extent_root, &key, &path, 0);
+       ret = search_slot(extent_root, &key, &path, -1, 1);
        if (ret) {
                print_tree(extent_root, extent_root->node);
                printf("failed to find %Lu\n", key.objectid);
@@ -105,8 +138,8 @@ int free_extent(struct ctree_root *root, u64 blocknr, u64 num_blocks)
  * ins->offset == number of blocks
  * Any available blocks before search_start are skipped.
  */
-int find_free_extent(struct ctree_root *orig_root, u64 num_blocks,
-                    u64 search_start, u64 search_end, struct key *ins)
+static int find_free_extent(struct ctree_root *orig_root, u64 num_blocks,
+                           u64 search_start, u64 search_end, struct key *ins)
 {
        struct ctree_path path;
        struct key *key;
@@ -124,7 +157,10 @@ check_failed:
        ins->offset = 0;
        ins->flags = 0;
        start_found = 0;
-       ret = search_slot(root, ins, &path, 0);
+       ret = search_slot(root, ins, &path, 0, 0);
+       if (ret < 0)
+               goto error;
+
        while (1) {
                l = &path.nodes[0]->leaf;
                slot = path.slots[0];
@@ -132,6 +168,8 @@ check_failed:
                        ret = next_leaf(root, &path);
                        if (ret == 0)
                                continue;
+                       if (ret < 0)
+                               goto error;
                        if (!start_found) {
                                ins->objectid = search_start;
                                ins->offset = num_blocks;
@@ -182,6 +220,9 @@ check_pending:
        if (ins->offset != 1)
                BUG();
        return 0;
+error:
+       release_path(root, &path);
+       return ret;
 }
 
 /*
@@ -213,6 +254,8 @@ static int insert_pending_extents(struct ctree_root *extent_root)
                        ret = insert_item(extent_root, &key, &item,
                                          sizeof(item));
                        if (ret) {
+                               printf("%Lu already in tree\n", key.objectid);
+                               print_tree(extent_root, extent_root->node);
                                BUG();
                                // FIXME undo it and return sane
                                return ret;
@@ -220,6 +263,7 @@ static int insert_pending_extents(struct ctree_root *extent_root)
                        radix_tree_tag_clear(&extent_root->cache_radix,
                                             gang[i]->blocknr,
                                             CTREE_EXTENT_PENDING);
+                       printf("%Lu is not pending\n", gang[i]->blocknr);
                        tree_block_release(extent_root, gang[i]);
                }
        }
@@ -258,15 +302,18 @@ int alloc_extent(struct ctree_root *root, u64 num_blocks, u64 search_start,
                if (pending_ret)
                        return pending_ret;
                *buf = find_tree_block(root, ins->objectid);
+               dirty_tree_block(root, *buf);
                return 0;
        }
        /* we're allocating an extent for the extent tree, don't recurse */
        BUG_ON(ins->offset != 1);
        *buf = find_tree_block(root, ins->objectid);
        BUG_ON(!*buf);
+       printf("%Lu is pending\n", ins->objectid);
        radix_tree_tag_set(&root->cache_radix, ins->objectid,
                           CTREE_EXTENT_PENDING);
        (*buf)->count++;
+       dirty_tree_block(root, *buf);
        return 0;
 
 }
This page took 0.024461 seconds and 5 git commands to generate.