Add back pointers from extents to the file or btree referencing them
authorChris Mason <chris.mason@oracle.com>
Tue, 11 Dec 2007 14:21:42 +0000 (09:21 -0500)
committerDavid Woodhouse <dwmw2@hera.kernel.org>
Tue, 11 Dec 2007 14:21:42 +0000 (09:21 -0500)
btrfsck.c
ctree.c
ctree.h
extent-tree.c
mkfs.c
print-tree.c

index 02299bc..d13658e 100644 (file)
--- a/btrfsck.c
+++ b/btrfsck.c
@@ -382,7 +382,7 @@ static int run_next_block(struct btrfs_root *root,
                                add_extent_rec(extent_cache, NULL, 0,
                                               found.objectid,
                                               found.offset,
-                                              btrfs_extent_owner(ei),
+                                              0,
                                               btrfs_extent_refs(ei), 0, 0);
                                continue;
                        }
diff --git a/ctree.c b/ctree.c
index 7179606..e5b2356 100644 (file)
--- a/ctree.c
+++ b/ctree.c
@@ -59,6 +59,7 @@ int btrfs_cow_block(struct btrfs_trans_handle *trans, struct btrfs_root
                           **cow_ret)
 {
        struct btrfs_buffer *cow;
+       u64 root_gen;
 
        if (!list_empty(&buf->dirty)) {
                *cow_ret = buf;
@@ -72,19 +73,23 @@ int btrfs_cow_block(struct btrfs_trans_handle *trans, struct btrfs_root
        *cow_ret = cow;
        btrfs_inc_ref(trans, root, buf);
        if (buf == root->node) {
+               root_gen = btrfs_header_generation(&buf->node.header);
                root->node = cow;
                cow->count++;
                if (buf != root->commit_root)
                        btrfs_free_extent(trans, root, buf->bytenr,
-                                         buf->size, 1);
+                                         buf->size, root->root_key.objectid,
+                                         root_gen, 0, 0, 1);
                btrfs_block_release(root, buf);
        } else {
+               root_gen = btrfs_header_generation(&parent->node.header);
                btrfs_set_node_blockptr(&parent->node, parent_slot,
                                        cow->bytenr);
                btrfs_set_node_ptr_generation(&parent->node, parent_slot,
                                              trans->transid);
                BUG_ON(list_empty(&parent->dirty));
-               btrfs_free_extent(trans, root, buf->bytenr, buf->size, 1);
+               btrfs_free_extent(trans, root, buf->bytenr, buf->size,
+                                 root->root_key.objectid, root_gen, 0, 0, 1);
        }
        btrfs_block_release(root, buf);
        return 0;
@@ -362,8 +367,10 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root
                /* once for the root ptr */
                btrfs_block_release(root, mid_buf);
                clean_tree_block(trans, root, mid_buf);
-               return btrfs_free_extent(trans, root, bytenr,
-                                        root->nodesize, 1);
+               return btrfs_free_extent(trans, root, bytenr, root->nodesize,
+                                        root->root_key.objectid,
+                                        btrfs_header_generation(&mid->header),
+                                        0, 0, 1);
        }
        parent = &parent_buf->node;
 
@@ -396,7 +403,10 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root
                if (wret < 0)
                        ret = wret;
                if (btrfs_header_nritems(&right->header) == 0) {
+                       u64 generation;
                        u64 bytenr = right_buf->bytenr;
+
+                       generation = btrfs_header_generation(&parent->header);
                        btrfs_block_release(root, right_buf);
                        clean_tree_block(trans, root, right_buf);
                        right_buf = NULL;
@@ -406,7 +416,9 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root
                        if (wret)
                                ret = wret;
                        wret = btrfs_free_extent(trans, root, bytenr,
-                                                root->nodesize, 1);
+                                                root->nodesize,
+                                                root->root_key.objectid,
+                                                generation, 0, 0, 1);
                        if (wret)
                                ret = wret;
                } else {
@@ -435,6 +447,9 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root
        if (btrfs_header_nritems(&mid->header) == 0) {
                /* we've managed to empty the middle node, drop it */
                u64 bytenr = mid_buf->bytenr;
+               u64 generation;
+
+               generation = btrfs_header_generation(&parent->header);
                btrfs_block_release(root, mid_buf);
                clean_tree_block(trans, root, mid_buf);
                mid_buf = NULL;
@@ -442,8 +457,9 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root
                wret = del_ptr(trans, root, path, level + 1, pslot);
                if (wret)
                        ret = wret;
-               wret = btrfs_free_extent(trans, root, bytenr,
-                                        root->nodesize, 1);
+               wret = btrfs_free_extent(trans, root, bytenr, root->nodesize,
+                                        root->root_key.objectid,
+                                        generation, 0, 0, 1);
                if (wret)
                        ret = wret;
        } else {
@@ -1589,13 +1605,17 @@ int btrfs_del_item(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                        btrfs_set_header_level(&leaf->header, 0);
                        BUG_ON(list_empty(&leaf_buf->dirty));
                } else {
+                       u64 generation =
+                         btrfs_header_generation(&path->nodes[1]->node.header);
+
                        clean_tree_block(trans, root, leaf_buf);
                        wret = del_ptr(trans, root, path, 1, path->slots[1]);
                        if (wret)
                                ret = wret;
-                       wret = btrfs_free_extent(trans, root,
-                                                leaf_buf->bytenr,
-                                                leaf_buf->size, 1);
+                       wret = btrfs_free_extent(trans, root, leaf_buf->bytenr,
+                                                leaf_buf->size,
+                                                root->root_key.objectid,
+                                                generation, 0, 0, 1);
                        if (wret)
                                ret = wret;
                }
@@ -1628,12 +1648,18 @@ int btrfs_del_item(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                        }
                        if (btrfs_header_nritems(&leaf->header) == 0) {
                                u64 bytenr = leaf_buf->bytenr;
+                               struct btrfs_buffer *parent = path->nodes[1];
+                               u64 generation =
+                                 btrfs_header_generation(&parent->node.header);
+
                                clean_tree_block(trans, root, leaf_buf);
                                wret = del_ptr(trans, root, path, 1, slot);
                                if (wret)
                                        ret = wret;
                                wret = btrfs_free_extent(trans, root, bytenr,
-                                                leaf_buf->size, 1);
+                                                leaf_buf->size,
+                                                root->root_key.objectid,
+                                                generation, 0, 0, 1);
                                btrfs_block_release(root, leaf_buf);
                                if (wret)
                                        ret = wret;
diff --git a/ctree.h b/ctree.h
index d1df4f2..174fb23 100644 (file)
--- a/ctree.h
+++ b/ctree.h
@@ -183,7 +183,13 @@ struct btrfs_path {
  */
 struct btrfs_extent_item {
        __le32 refs;
-       __le64 owner;
+} __attribute__ ((__packed__));
+
+struct btrfs_extent_ref {
+       __le64 root;
+       __le64 generation;
+       __le64 objectid;
+       __le64 offset;
 } __attribute__ ((__packed__));
 
 struct btrfs_inode_timespec {
@@ -377,12 +383,13 @@ struct btrfs_root {
  * are used, and how many references there are to each block
  */
 #define BTRFS_EXTENT_ITEM_KEY  33
+#define BTRFS_EXTENT_REF_KEY   34
 
 /*
  * block groups give us hints into the extent allocation trees.  Which
  * blocks are free etc etc
  */
-#define BTRFS_BLOCK_GROUP_ITEM_KEY 34
+#define BTRFS_BLOCK_GROUP_ITEM_KEY 50
 
 /*
  * string items are for debugging.  They just store a short string of
@@ -390,6 +397,15 @@ struct btrfs_root {
  */
 #define BTRFS_STRING_ITEM_KEY  253
 
+#define BTRFS_SETGET_STACK_FUNCS(name, type, member, bits)             \
+static inline u##bits btrfs_##name(type *s)                            \
+{                                                                      \
+       return le##bits##_to_cpu(s->member);                            \
+}                                                                      \
+static inline void btrfs_set_##name(type *s, u##bits val)              \
+{                                                                      \
+       s->member = cpu_to_le##bits(val);                               \
+}
 
 static inline u64 btrfs_block_group_used(struct btrfs_block_group_item *bi)
 {
@@ -538,25 +554,13 @@ static inline void btrfs_set_timespec_nsec(struct btrfs_inode_timespec *ts,
        ts->nsec = cpu_to_le32(val);
 }
 
-static inline u32 btrfs_extent_refs(struct btrfs_extent_item *ei)
-{
-       return le32_to_cpu(ei->refs);
-}
-
-static inline void btrfs_set_extent_refs(struct btrfs_extent_item *ei, u32 val)
-{
-       ei->refs = cpu_to_le32(val);
-}
+BTRFS_SETGET_STACK_FUNCS(extent_refs, struct btrfs_extent_item, refs, 32);
 
-static inline u64 btrfs_extent_owner(struct btrfs_extent_item *ei)
-{
-       return le64_to_cpu(ei->owner);
-}
-
-static inline void btrfs_set_extent_owner(struct btrfs_extent_item *ei, u64 val)
-{
-       ei->owner = cpu_to_le64(val);
-}
+BTRFS_SETGET_STACK_FUNCS(ref_root, struct btrfs_extent_ref, root, 64);
+BTRFS_SETGET_STACK_FUNCS(ref_generation, struct btrfs_extent_ref,
+                        generation, 64);
+BTRFS_SETGET_STACK_FUNCS(ref_objectid, struct btrfs_extent_ref, objectid, 64);
+BTRFS_SETGET_STACK_FUNCS(ref_offset, struct btrfs_extent_ref, offset, 64);
 
 static inline u64 btrfs_node_blockptr(struct btrfs_node *n, int nr)
 {
@@ -1068,9 +1072,11 @@ struct btrfs_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
 int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                  struct btrfs_buffer *buf);
 int btrfs_inc_root_ref(struct btrfs_trans_handle *trans,
-                      struct btrfs_root *root);
+                      struct btrfs_root *root, u64 owner_objectid);
 int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
-                     *root, u64 bytenr, u64 num_bytes, int pin);
+                     *root, u64 bytenr, u64 num_bytes,
+                     u64 root_objectid, u64 root_generation,
+                     u64 owner, u64 owner_offset, int pin);
 int btrfs_cow_block(struct btrfs_trans_handle *trans,
                    struct btrfs_root *root, struct btrfs_buffer *buf,
                    struct btrfs_buffer *parent, int parent_slot,
index ac8ae75..c0695ec 100644 (file)
 #include "disk-io.h"
 #include "print-tree.h"
 #include "transaction.h"
+#include "crc32c.h"
 
 static int finish_current_insert(struct btrfs_trans_handle *trans, struct
                                 btrfs_root *extent_root);
 static int run_pending(struct btrfs_trans_handle *trans, struct btrfs_root
                       *extent_root);
 
+static u64 hash_extent_ref(u64 root_objectid, u64 ref_generation,
+                          u64 owner, u64 owner_offset)
+{
+       u32 high_crc = ~(u32)0;
+       u32 low_crc = ~(u32)0;
+       __le64 lenum;
+
+       lenum = cpu_to_le64(root_objectid);
+       high_crc = crc32c(high_crc, &lenum, sizeof(lenum));
+       lenum = cpu_to_le64(ref_generation);
+       low_crc = crc32c(low_crc, &lenum, sizeof(lenum));
+
+#if 0
+       lenum = cpu_to_le64(owner);
+       low_crc = crc32c(low_crc, &lenum, sizeof(lenum));
+       lenum = cpu_to_le64(owner_offset);
+       low_crc = crc32c(low_crc, &lenum, sizeof(lenum));
+#endif
+       return ((u64)high_crc << 32) | (u64)low_crc;
+}
+
+static int match_extent_ref(struct btrfs_extent_ref *disk_ref,
+                           struct btrfs_extent_ref *cpu_ref)
+{
+       int ret = memcmp(cpu_ref, disk_ref, sizeof(*cpu_ref));
+       return ret == 0;
+}
+
+static int lookup_extent_backref(struct btrfs_trans_handle *trans,
+                                struct btrfs_root *root,
+                                struct btrfs_path *path, u64 bytenr,
+                                u64 root_objectid, u64 ref_generation,
+                                u64 owner, u64 owner_offset, int del)
+{
+       u64 hash;
+       struct btrfs_key key;
+       struct btrfs_key found_key;
+       struct btrfs_extent_ref ref;
+       struct btrfs_buffer *leaf;
+       struct btrfs_extent_ref *disk_ref;
+       int ret;
+       int ret2;
+
+       btrfs_set_ref_root(&ref, root_objectid);
+       btrfs_set_ref_generation(&ref, ref_generation);
+       btrfs_set_ref_objectid(&ref, owner);
+       btrfs_set_ref_offset(&ref, owner_offset);
+
+       hash = hash_extent_ref(root_objectid, ref_generation, owner,
+                              owner_offset);
+       key.offset = hash;
+       key.objectid = bytenr;
+       key.type = BTRFS_EXTENT_REF_KEY;
+
+       while (1) {
+               ret = btrfs_search_slot(trans, root, &key, path,
+                                       del ? -1 : 0, del);
+               if (ret < 0)
+                       goto out;
+               leaf = path->nodes[0];
+               if (ret != 0) {
+                       u32 nritems = btrfs_header_nritems(&leaf->node.header);
+                       if (path->slots[0] >= nritems) {
+                               ret2 = btrfs_next_leaf(root, path);
+                               if (ret2)
+                                       goto out;
+                               leaf = path->nodes[0];
+                       }
+                       btrfs_disk_key_to_cpu(&found_key,
+                                        &leaf->leaf.items[path->slots[0]].key);
+                       if (found_key.objectid != bytenr ||
+                           found_key.type != BTRFS_EXTENT_REF_KEY)
+                               goto out;
+                       key.offset = found_key.offset;
+                       if (del) {
+                               btrfs_release_path(root, path);
+                               continue;
+                       }
+               }
+               disk_ref = btrfs_item_ptr(&path->nodes[0]->leaf,
+                                         path->slots[0],
+                                         struct btrfs_extent_ref);
+               if (match_extent_ref(disk_ref, &ref)) {
+                       ret = 0;
+                       goto out;
+               }
+               btrfs_disk_key_to_cpu(&found_key,
+                                     &leaf->leaf.items[path->slots[0]].key);
+               key.offset = found_key.offset + 1;
+               btrfs_release_path(root, path);
+       }
+out:
+       return ret;
+}
+
+static int insert_extent_backref(struct btrfs_trans_handle *trans,
+                                struct btrfs_root *root,
+                                struct btrfs_path *path, u64 bytenr,
+                                u64 root_objectid, u64 ref_generation,
+                                u64 owner, u64 owner_offset)
+{
+       u64 hash;
+       struct btrfs_key key;
+       struct btrfs_extent_ref ref;
+       struct btrfs_extent_ref *disk_ref;
+       int ret;
+
+       btrfs_set_ref_root(&ref, root_objectid);
+       btrfs_set_ref_generation(&ref, ref_generation);
+       btrfs_set_ref_objectid(&ref, owner);
+       btrfs_set_ref_offset(&ref, owner_offset);
+
+       hash = hash_extent_ref(root_objectid, ref_generation, owner,
+                              owner_offset);
+       key.offset = hash;
+       key.objectid = bytenr;
+       key.type = BTRFS_EXTENT_REF_KEY;
+
+       ret = btrfs_insert_empty_item(trans, root, path, &key, sizeof(ref));
+       while (ret == -EEXIST) {
+               disk_ref = btrfs_item_ptr(&path->nodes[0]->leaf, path->slots[0],
+                                         struct btrfs_extent_ref);
+               if (match_extent_ref(disk_ref, &ref))
+                       goto out;
+               key.offset++;
+               ret = btrfs_insert_empty_item(trans, root, path, &key,
+                                             sizeof(ref));
+       }
+       if (ret)
+               goto out;
+       disk_ref = btrfs_item_ptr(&path->nodes[0]->leaf, path->slots[0],
+                                 struct btrfs_extent_ref);
+       memcpy(disk_ref, &ref, sizeof(ref));
+       dirty_tree_block(trans, root, path->nodes[0]);
+out:
+       btrfs_release_path(root, path);
+       return ret;
+}
+
 static int inc_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root
-                        *root, u64 bytenr, u32 blocksize)
+                        *root, u64 bytenr, u32 blocksize,
+                        u64 root_objectid, u64 ref_generation,
+                        u64 owner, u64 owner_offset)
 {
        struct btrfs_path path;
        int ret;
@@ -56,6 +198,12 @@ static int inc_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root
 
        BUG_ON(list_empty(&path.nodes[0]->dirty));
        btrfs_release_path(root->fs_info->extent_root, &path);
+
+       ret = insert_extent_backref(trans, root->fs_info->extent_root, &path,
+                                   bytenr, root_objectid, ref_generation,
+                                   owner, owner_offset);
+       BUG_ON(ret);
+
        finish_current_insert(trans, root->fs_info->extent_root);
        run_pending(trans, root->fs_info->extent_root);
        return 0;
@@ -69,7 +217,9 @@ static int lookup_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root
        struct btrfs_key key;
        struct btrfs_leaf *l;
        struct btrfs_extent_item *item;
+
        btrfs_init_path(&path);
+
        key.objectid = bytenr;
        key.offset = blocksize;
        btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
@@ -103,17 +253,19 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
 
        for (i = 0; i < btrfs_header_nritems(&buf->node.header); i++) {
                bytenr = btrfs_node_blockptr(&buf->node, i);
-               inc_block_ref(trans, root, bytenr, blocksize);
+               inc_block_ref(trans, root, bytenr, blocksize,
+                             root->root_key.objectid, trans->transid, 0, 0);
        }
 
        return 0;
 }
 
 int btrfs_inc_root_ref(struct btrfs_trans_handle *trans,
-                      struct btrfs_root *root)
+                      struct btrfs_root *root, u64 owner_objectid)
 {
        return inc_block_ref(trans, root, root->node->bytenr,
-                            root->node->size);
+                            root->node->size, owner_objectid,
+                            trans->transid, 0, 0);
 }
 
 static int write_one_cache_group(struct btrfs_trans_handle *trans,
@@ -241,9 +393,10 @@ static int finish_current_insert(struct btrfs_trans_handle *trans, struct
        struct cache_extent *pe;
        struct cache_extent *next;
        struct cache_tree *pending_tree = &info->pending_tree;
+       struct btrfs_path path;
 
+       btrfs_init_path(&path);
        btrfs_set_extent_refs(&extent_item, 1);
-       btrfs_set_extent_owner(&extent_item, extent_root->root_key.objectid);
        ins.offset = 1;
        btrfs_set_key_type(&ins, BTRFS_EXTENT_ITEM_KEY);
        pe = find_first_cache_extent(pending_tree, 0);
@@ -265,6 +418,12 @@ static int finish_current_insert(struct btrfs_trans_handle *trans, struct
                        btrfs_print_tree(extent_root, extent_root->node);
                }
                BUG_ON(ret);
+
+               ret = insert_extent_backref(trans, extent_root, &path,
+                                           ins.objectid,
+                                           extent_root->root_key.objectid,
+                                           0, 0, 0);
+               BUG_ON(ret);
        }
        return 0;
 }
@@ -273,7 +432,9 @@ static int finish_current_insert(struct btrfs_trans_handle *trans, struct
  * remove an extent from the root, returns 0 on success
  */
 static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
-                        *root, u64 bytenr, u64 num_bytes, int pin)
+                        *root, u64 bytenr, u64 num_bytes,
+                        u64 root_objectid, u64 ref_generation,
+                        u64 owner_objectid, u64 owner_offset, int pin)
 {
        struct btrfs_path path;
        struct btrfs_key key;
@@ -288,6 +449,19 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
        key.offset = num_bytes;
 
        btrfs_init_path(&path);
+
+       ret = lookup_extent_backref(trans, extent_root, &path,
+                                   bytenr, root_objectid,
+                                   ref_generation,
+                                   owner_objectid, owner_offset, 1);
+       if (ret == 0) {
+               ret = btrfs_del_item(trans, extent_root, &path);
+       } else {
+               // FIXME deal with missing references here
+       }
+
+       btrfs_release_path(extent_root, &path);
+
        ret = btrfs_search_slot(trans, extent_root, &key, &path, -1, 1);
        if (ret) {
                btrfs_print_tree(extent_root, extent_root->node);
@@ -345,7 +519,9 @@ static int del_pending_extents(struct btrfs_trans_handle *trans, struct
        while(pe) {
                remove_cache_extent(del_pending, pe);
                ret = __free_extent(trans, extent_root,
-                                   pe->start, pe->size, 1);
+                                   pe->start, pe->size,
+                                   extent_root->root_key.objectid,
+                                   0, 0, 0, 1);
                BUG_ON(ret);
                next = next_cache_extent(pe);
                if (!next)
@@ -368,19 +544,26 @@ static int run_pending(struct btrfs_trans_handle *trans, struct btrfs_root
  * remove an extent from the root, returns 0 on success
  */
 int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
-                     *root, u64 bytenr, u64 num_bytes, int pin)
+                     *root, u64 bytenr, u64 num_bytes,
+                     u64 root_objectid, u64 root_generation,
+                     u64 owner_objectid, u64 owner_offset, int pin)
 {
        struct btrfs_root *extent_root = root->fs_info->extent_root;
        int pending_ret;
        int ret;
 
+       if (!root->ref_cows)
+               root_generation = 0;
+
        if (root == extent_root) {
                ret = insert_cache_extent(&root->fs_info->del_pending,
                                            bytenr, num_bytes);
                BUG_ON(ret);
                return 0;
        }
-       ret = __free_extent(trans, root, bytenr, num_bytes, pin);
+       ret = __free_extent(trans, root, bytenr, num_bytes,
+                           root_objectid, root_generation, owner_objectid,
+                           owner_offset, pin);
        pending_ret = run_pending(trans, root->fs_info->extent_root);
        return ret ? ret : pending_ret;
 }
@@ -509,8 +692,9 @@ error:
  * returns 0 if everything worked, non-zero otherwise.
  */
 static int alloc_extent(struct btrfs_trans_handle *trans,
-                       struct btrfs_root *root, u64 owner,
-                       u64 num_bytes, u64 search_start,
+                       struct btrfs_root *root, u64 num_bytes,
+                       u64 root_objectid, u64 ref_generation, u64 owner,
+                       u64 owner_offset, u64 search_start,
                        u64 search_end, struct btrfs_key *ins)
 {
        int ret;
@@ -519,9 +703,11 @@ static int alloc_extent(struct btrfs_trans_handle *trans,
        struct btrfs_fs_info *info = root->fs_info;
        struct btrfs_root *extent_root = info->extent_root;
        struct btrfs_extent_item extent_item;
+       struct btrfs_path path;
+
+       btrfs_init_path(&path);
 
        btrfs_set_extent_refs(&extent_item, 1);
-       btrfs_set_extent_owner(&extent_item, owner);
 
        ret = find_free_extent(trans, root, num_bytes, search_start,
                               search_end, ins);
@@ -543,6 +729,12 @@ static int alloc_extent(struct btrfs_trans_handle *trans,
        ret = btrfs_insert_item(trans, extent_root, ins, &extent_item,
                                sizeof(extent_item));
 
+       BUG_ON(ret);
+       ret = insert_extent_backref(trans, extent_root, &path, ins->objectid,
+                                   root_objectid, ref_generation,
+                                   owner, owner_offset);
+       BUG_ON(ret);
+
        finish_current_insert(trans, extent_root);
        pending_ret = run_pending(trans, extent_root);
        if (ret)
@@ -562,11 +754,19 @@ struct btrfs_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
                                            struct btrfs_root *root,
                                            u32 blocksize)
 {
+       u64 ref_generation;
        struct btrfs_key ins;
        int ret;
        struct btrfs_buffer *buf;
-       ret = alloc_extent(trans, root, root->root_key.objectid,
-                          blocksize, 0, (u64)-1, &ins);
+
+       if (root->ref_cows)
+               ref_generation = trans->transid;
+       else
+               ref_generation = 0;
+
+       ret = alloc_extent(trans, root, blocksize,
+                          root->root_key.objectid, ref_generation,
+                          0, 0, 0, (u64)-1, &ins);
        if (ret) {
                BUG();
                return NULL;
@@ -590,6 +790,9 @@ static int walk_down_tree(struct btrfs_trans_handle *trans, struct btrfs_root
 {
        struct btrfs_buffer *next;
        struct btrfs_buffer *cur;
+       struct btrfs_buffer *parent;
+       u64 root_owner;
+       u64 root_gen;
        u64 bytenr;
        int ret;
        u32 refs;
@@ -612,8 +815,13 @@ static int walk_down_tree(struct btrfs_trans_handle *trans, struct btrfs_root
                bytenr = btrfs_node_blockptr(&cur->node, path->slots[*level]);
                ret = lookup_block_ref(trans, root, bytenr, size, &refs);
                if (refs != 1 || *level == 1) {
+                       parent = path->nodes[*level];
+                       root_owner = btrfs_header_owner(&parent->node.header);
+                       root_gen =
+                               btrfs_header_generation(&parent->node.header);
                        path->slots[*level]++;
-                       ret = btrfs_free_extent(trans, root, bytenr, size, 1);
+                       ret = btrfs_free_extent(trans, root, bytenr, size,
+                                               root_owner, root_gen, 0, 0, 1);
                        BUG_ON(ret);
                        continue;
                }
@@ -626,8 +834,16 @@ static int walk_down_tree(struct btrfs_trans_handle *trans, struct btrfs_root
                path->slots[*level] = 0;
        }
 out:
+       if (*level == BTRFS_MAX_LEVEL - 1 || !path->nodes[*level + 1])
+               parent = path->nodes[*level];
+       else
+               parent = path->nodes[*level + 1];
+
+       root_owner = btrfs_header_owner(&parent->node.header);
+       root_gen = btrfs_header_generation(&parent->node.header);
        ret = btrfs_free_extent(trans, root, path->nodes[*level]->bytenr,
-                               btrfs_level_size(root, *level), 1);
+                               btrfs_level_size(root, *level),
+                               root_owner, root_gen, 0, 0, 1);
        btrfs_block_release(root, path->nodes[*level]);
        path->nodes[*level] = NULL;
        *level += 1;
@@ -646,6 +862,9 @@ static int walk_up_tree(struct btrfs_trans_handle *trans, struct btrfs_root
        int i;
        int slot;
        int ret;
+       u64 root_owner;
+       u64 root_gen;
+       struct btrfs_buffer *parent;
        for(i = *level; i < BTRFS_MAX_LEVEL - 1 && path->nodes[i]; i++) {
                slot = path->slots[i];
                if (slot <
@@ -654,9 +873,18 @@ static int walk_up_tree(struct btrfs_trans_handle *trans, struct btrfs_root
                        *level = i;
                        return 0;
                } else {
+                       if (path->nodes[*level] == root->node)
+                               parent = path->nodes[*level];
+                       else
+                               parent = path->nodes[*level + 1];
+
+                       root_owner = btrfs_header_owner(&parent->node.header);
+                       root_gen =
+                               btrfs_header_generation(&parent->node.header);
                        ret = btrfs_free_extent(trans, root,
                                        path->nodes[*level]->bytenr,
-                                       btrfs_level_size(root, *level), 1);
+                                       btrfs_level_size(root, *level),
+                                       root_owner, root_gen, 0, 0, 1);
                        btrfs_block_release(root, path->nodes[*level]);
                        path->nodes[*level] = NULL;
                        *level = i + 1;
diff --git a/mkfs.c b/mkfs.c
index 2b1b500..ffc6af1 100644 (file)
--- a/mkfs.c
+++ b/mkfs.c
@@ -278,7 +278,6 @@ printf("blocksize is %d\n", leafsize);
        btrfs_set_item_offset(&item, itemoff);
        btrfs_set_item_size(&item, sizeof(struct btrfs_extent_item));
        btrfs_set_extent_refs(&extent_item, 1);
-       btrfs_set_extent_owner(&extent_item, BTRFS_ROOT_TREE_OBJECTID);
        memcpy(empty_leaf->items, &item, sizeof(item));
        memcpy(btrfs_leaf_data(empty_leaf) + btrfs_item_offset(&item),
                &extent_item, btrfs_item_size(&item));
index 8a30919..9c85f63 100644 (file)
@@ -57,6 +57,7 @@ void btrfs_print_leaf(struct btrfs_root *root, struct btrfs_leaf *l)
        struct btrfs_file_extent_item *fi;
        struct btrfs_csum_item *ci;
        struct btrfs_block_group_item *bi;
+       struct btrfs_extent_ref *ref;
        u32 type;
 
        printf("leaf %llu ptrs %d free space %d generation %llu owner %llu\n",
@@ -114,9 +115,17 @@ void btrfs_print_leaf(struct btrfs_root *root, struct btrfs_leaf *l)
                        break;
                case BTRFS_EXTENT_ITEM_KEY:
                        ei = btrfs_item_ptr(l, i, struct btrfs_extent_item);
-                       printf("\t\textent data refs %u owner %llu\n",
-                               btrfs_extent_refs(ei),
-                               (unsigned long long)btrfs_extent_owner(ei));
+                       printf("\t\textent data refs %u\n",
+                               btrfs_extent_refs(ei));
+                       break;
+               case BTRFS_EXTENT_REF_KEY:
+                       ref = btrfs_item_ptr(l, i, struct btrfs_extent_ref);
+                       printf("\t\textent back ref root %llu gen %llu "
+                              "owner %llu offset %llu\n",
+                              (unsigned long long)btrfs_ref_root(ref),
+                              (unsigned long long)btrfs_ref_generation(ref),
+                              (unsigned long long)btrfs_ref_objectid(ref),
+                              (unsigned long long)btrfs_ref_offset(ref));
                        break;
                case BTRFS_CSUM_ITEM_KEY:
                        ci = btrfs_item_ptr(l, i,