Btrfs: Add back pointers from extents to the btree or file referencing them
[linux-2.6-block.git] / fs / btrfs / extent-tree.c
index 0f1ebdd4e925a28dd1ab69d0772962c78ecd26d7..32991f73e9dbf39953164a2793764068c6dd9d5d 100644 (file)
@@ -17,6 +17,7 @@
  */
 
 #include <linux/sched.h>
+#include <linux/crc32c.h>
 #include "hash.h"
 #include "ctree.h"
 #include "disk-io.h"
@@ -89,7 +90,8 @@ static int cache_block_group(struct btrfs_root *root,
 
                btrfs_item_key_to_cpu(leaf, &key, slot);
                if (key.objectid < block_group->key.objectid) {
-                       if (key.objectid + key.offset > first_free)
+                       if (btrfs_key_type(&key) != BTRFS_EXTENT_REF_KEY &&
+                           key.objectid + key.offset > first_free)
                                first_free = key.objectid + key.offset;
                        goto next;
                }
@@ -353,7 +355,7 @@ found:
        return found_group;
 }
 
-static u64 hash_extent_ref(u64 root_objectid, u64 root_generation,
+static u64 hash_extent_ref(u64 root_objectid, u64 ref_generation,
                           u64 owner, u64 owner_offset)
 {
        u32 high_crc = ~(u32)0;
@@ -362,53 +364,149 @@ static u64 hash_extent_ref(u64 root_objectid, u64 root_generation,
 
        lenum = cpu_to_le64(root_objectid);
        high_crc = crc32c(high_crc, &lenum, sizeof(lenum));
-       lenum = cpu_to_le64(root_generation);
-       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;
 }
 
-int insert_extent_ref(struct btrfs_trans_handle *trans,
-                               struct btrfs_root *root,
-                               struct btrfs_path *path,
-                               u64 bytenr,
-                               u64 root_objectid, u64 root_generation,
-                               u64 owner, u64 owner_offset)
+static int match_extent_ref(struct extent_buffer *leaf,
+                           struct btrfs_extent_ref *disk_ref,
+                           struct btrfs_extent_ref *cpu_ref)
+{
+       int ret;
+       int len;
+
+       if (cpu_ref->objectid)
+               len = sizeof(*cpu_ref);
+       else
+               len = 2 * sizeof(u64);
+       ret = memcmp_extent_buffer(leaf, cpu_ref, (unsigned long)disk_ref,
+                                  len);
+       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 extent_buffer *l;
-       struct btrfs_extent_item *item;
+       struct extent_buffer *leaf;
+       struct btrfs_extent_ref *disk_ref;
+       int ret;
+       int ret2;
+
+       btrfs_set_stack_ref_root(&ref, root_objectid);
+       btrfs_set_stack_ref_generation(&ref, ref_generation);
+       btrfs_set_stack_ref_objectid(&ref, owner);
+       btrfs_set_stack_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);
+                       if (path->slots[0] >= nritems) {
+                               ret2 = btrfs_next_leaf(root, path);
+                               if (ret2)
+                                       goto out;
+                               leaf = path->nodes[0];
+                       }
+                       btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
+                       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],
+                                         path->slots[0],
+                                         struct btrfs_extent_ref);
+               if (match_extent_ref(path->nodes[0], disk_ref, &ref)) {
+                       ret = 0;
+                       goto out;
+               }
+               btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
+               key.offset = found_key.offset + 1;
+               btrfs_release_path(root, path);
+       }
+out:
+       return ret;
+}
+
+int btrfs_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_stack_ref_root(&ref, root_objectid);
-       btrfs_set_stack_ref_generation(&ref, root_generation);
+       btrfs_set_stack_ref_generation(&ref, ref_generation);
        btrfs_set_stack_ref_objectid(&ref, owner);
        btrfs_set_stack_ref_offset(&ref, owner_offset);
 
-       ret = btrfs_name_hash(&ref, sizeof(ref), &hash);
+       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], path->slots[0],
+                                         struct btrfs_extent_ref);
+               if (match_extent_ref(path->nodes[0], disk_ref, &ref))
+                       goto out;
+               key.offset++;
+               btrfs_release_path(root, path);
+               ret = btrfs_insert_empty_item(trans, root, path, &key,
+                                             sizeof(ref));
        }
-
+       if (ret)
+               goto out;
+       disk_ref = btrfs_item_ptr(path->nodes[0], path->slots[0],
+                                 struct btrfs_extent_ref);
+       write_extent_buffer(path->nodes[0], &ref, (unsigned long)disk_ref,
+                           sizeof(ref));
+       btrfs_mark_buffer_dirty(path->nodes[0]);
+out:
+       btrfs_release_path(root, path);
+       return ret;
 }
 
 int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
                                struct btrfs_root *root,
                                u64 bytenr, u64 num_bytes,
-                               u64 root_objectid, u64 root_generation,
+                               u64 root_objectid, u64 ref_generation,
                                u64 owner, u64 owner_offset)
 {
        struct btrfs_path *path;
@@ -441,6 +539,11 @@ int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
        btrfs_mark_buffer_dirty(path->nodes[0]);
 
        btrfs_release_path(root->fs_info->extent_root, path);
+
+       ret = btrfs_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);
        del_pending_extents(trans, root->fs_info->extent_root);
 
@@ -489,10 +592,29 @@ out:
 }
 
 int btrfs_inc_root_ref(struct btrfs_trans_handle *trans,
-                      struct btrfs_root *root)
+                      struct btrfs_root *root, u64 owner_objectid)
 {
+       u64 generation;
+       u64 key_objectid;
+       u64 level;
+       u32 nritems;
+       struct btrfs_disk_key disk_key;
+
+       level = btrfs_header_level(root->node);
+       generation = trans->transid;
+       nritems = btrfs_header_nritems(root->node);
+       if (nritems > 0) {
+               if (level == 0)
+                       btrfs_item_key(root->node, &disk_key, 0);
+               else
+                       btrfs_node_key(root->node, &disk_key, 0);
+               key_objectid = btrfs_disk_key_objectid(&disk_key);
+       } else {
+               key_objectid = 0;
+       }
        return btrfs_inc_extent_ref(trans, root, root->node->start,
-                                   root->node->len);
+                                   root->node->len, owner_objectid,
+                                   generation, 0, 0);
 }
 
 int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
@@ -506,7 +628,6 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
        int level;
        int ret;
        int faili;
-       int err;
 
        if (!root->ref_cows)
                return 0;
@@ -528,7 +649,9 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                        if (disk_bytenr == 0)
                                continue;
                        ret = btrfs_inc_extent_ref(trans, root, disk_bytenr,
-                                   btrfs_file_extent_disk_num_bytes(buf, fi));
+                                   btrfs_file_extent_disk_num_bytes(buf, fi),
+                                   root->root_key.objectid, trans->transid,
+                                   key.objectid, key.offset);
                        if (ret) {
                                faili = i;
                                goto fail;
@@ -536,7 +659,9 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                } else {
                        bytenr = btrfs_node_blockptr(buf, i);
                        ret = btrfs_inc_extent_ref(trans, root, bytenr,
-                                          btrfs_level_size(root, level - 1));
+                                          btrfs_level_size(root, level - 1),
+                                          root->root_key.objectid,
+                                          trans->transid, 0, 0);
                        if (ret) {
                                faili = i;
                                goto fail;
@@ -546,6 +671,7 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
        return 0;
 fail:
        WARN_ON(1);
+#if 0
        for (i =0; i < faili; i++) {
                if (level == 0) {
                        u64 disk_bytenr;
@@ -571,6 +697,7 @@ fail:
                        BUG_ON(err);
                }
        }
+#endif
        return ret;
 }
 
@@ -809,18 +936,18 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
 static int finish_current_insert(struct btrfs_trans_handle *trans, struct
                                 btrfs_root *extent_root)
 {
+       u64 start;
+       u64 end;
+       struct btrfs_fs_info *info = extent_root->fs_info;
+       struct btrfs_path *path;
        struct btrfs_key ins;
        struct btrfs_extent_item extent_item;
        int ret;
        int err = 0;
-       u64 start;
-       u64 end;
-       struct btrfs_fs_info *info = extent_root->fs_info;
 
        btrfs_set_stack_extent_refs(&extent_item, 1);
        btrfs_set_key_type(&ins, BTRFS_EXTENT_ITEM_KEY);
-       btrfs_set_stack_extent_owner(&extent_item,
-                                    extent_root->root_key.objectid);
+       path = btrfs_alloc_path();
 
        while(1) {
                ret = find_first_extent_bit(&info->extent_ins, 0, &start,
@@ -834,7 +961,12 @@ static int finish_current_insert(struct btrfs_trans_handle *trans, struct
                                        &extent_item, sizeof(extent_item));
                clear_extent_bits(&info->extent_ins, start, end, EXTENT_LOCKED,
                                  GFP_NOFS);
+               err = btrfs_insert_extent_backref(trans, extent_root, path,
+                                         start, extent_root->root_key.objectid,
+                                         0, 0, 0);
+               BUG_ON(err);
        }
+       btrfs_free_path(path);
        return 0;
 }
 
@@ -871,7 +1003,9 @@ static int pin_down_bytes(struct btrfs_root *root, u64 bytenr, u32 num_bytes,
  * 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,
                         int mark_free)
 {
        struct btrfs_path *path;
@@ -891,6 +1025,24 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
        if (!path)
                return -ENOMEM;
 
+       if (ref_generation && owner_objectid == 0 && root_objectid == 3) {
+//printk("drop backref root %Lu gen %Lu byte %Lu\n", root_objectid, ref_generation, bytenr );
+       }
+       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 {
+               btrfs_print_leaf(extent_root, path->nodes[0]);
+               WARN_ON(1);
+               printk("Unable to find ref byte nr %Lu root %Lu "
+                      " gen %Lu owner %Lu offset %Lu\n", bytenr,
+                      root_objectid, ref_generation, owner_objectid,
+                      owner_offset);
+       }
+       btrfs_release_path(extent_root, path);
        ret = btrfs_search_slot(trans, extent_root, &key, path, -1, 1);
        if (ret < 0)
                return ret;
@@ -965,7 +1117,9 @@ static int del_pending_extents(struct btrfs_trans_handle *trans, struct
                clear_extent_bits(pending_del, start, end, EXTENT_LOCKED,
                                  GFP_NOFS);
                ret = __free_extent(trans, extent_root,
-                                    start, end + 1 - start, 0, 0);
+                                    start, end + 1 - start,
+                                    extent_root->root_key.objectid,
+                                    0, 0, 0, 0, 0);
                if (ret)
                        err = ret;
        }
@@ -976,18 +1130,25 @@ static int del_pending_extents(struct btrfs_trans_handle *trans, struct
  * 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 ref_generation,
+                     u64 owner_objectid, u64 owner_offset, int pin)
 {
        struct btrfs_root *extent_root = root->fs_info->extent_root;
        int pending_ret;
        int ret;
 
        WARN_ON(num_bytes < root->sectorsize);
+       if (!root->ref_cows)
+               ref_generation = 0;
+
        if (root == extent_root) {
                pin_down_bytes(root, bytenr, num_bytes, 1);
                return 0;
        }
-       ret = __free_extent(trans, root, bytenr, num_bytes, pin, pin == 0);
+       ret = __free_extent(trans, root, bytenr, num_bytes, root_objectid,
+                           ref_generation, owner_objectid, owner_offset,
+                           pin, pin == 0);
        pending_ret = del_pending_extents(trans, root->fs_info->extent_root);
        return ret ? ret : pending_ret;
 }
@@ -1080,23 +1241,26 @@ check_failed:
        btrfs_item_key_to_cpu(l, &key, path->slots[0]);
 
        /*
-        * a rare case, go back one key if we hit a block group item
-        * instead of an extent item
+        * walk backwards to find the first extent item key
         */
-       if (btrfs_key_type(&key) != BTRFS_EXTENT_ITEM_KEY &&
-           key.objectid + key.offset >= search_start) {
-               ins->objectid = key.objectid;
-               ins->offset = key.offset - 1;
-               btrfs_release_path(root, path);
-               ret = btrfs_search_slot(trans, root, ins, path, 0, 0);
-               if (ret < 0)
-                       goto error;
-
-               if (path->slots[0] > 0) {
+       while(btrfs_key_type(&key) != BTRFS_EXTENT_ITEM_KEY) {
+               if (path->slots[0] == 0) {
+                       ret = btrfs_prev_leaf(root, path);
+                       if (ret != 0) {
+                               ret = btrfs_search_slot(trans, root, ins,
+                                                       path, 0, 0);
+                               if (ret < 0)
+                                       goto error;
+                               if (path->slots[0] > 0)
+                                       path->slots[0]--;
+                               break;
+                       }
+               } else {
                        path->slots[0]--;
                }
+               l = path->nodes[0];
+               btrfs_item_key_to_cpu(l, &key, path->slots[0]);
        }
-
        while (1) {
                l = path->nodes[0];
                slot = path->slots[0];
@@ -1146,7 +1310,8 @@ check_failed:
                        }
                }
                if (btrfs_key_type(&key) != BTRFS_EXTENT_ITEM_KEY) {
-                       if (!start_found) {
+                       if (!start_found && btrfs_key_type(&key) ==
+                           BTRFS_BLOCK_GROUP_ITEM_KEY) {
                                last_byte = key.objectid;
                                start_found = 1;
                        }
@@ -1244,8 +1409,10 @@ error:
  * returns 0 if everything worked, non-zero otherwise.
  */
 int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
-                      struct btrfs_root *root, u64 owner,
-                      u64 num_bytes, u64 empty_size, u64 hint_byte,
+                      struct btrfs_root *root,
+                      u64 num_bytes, u64 root_objectid, u64 ref_generation,
+                      u64 owner, u64 owner_offset,
+                      u64 empty_size, u64 hint_byte,
                       u64 search_end, struct btrfs_key *ins, int data)
 {
        int ret;
@@ -1255,9 +1422,9 @@ int btrfs_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_set_stack_extent_refs(&extent_item, 1);
-       btrfs_set_stack_extent_owner(&extent_item, owner);
 
        WARN_ON(num_bytes < root->sectorsize);
        ret = find_free_extent(trans, root, num_bytes, empty_size,
@@ -1296,8 +1463,16 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
 
        trans->alloc_exclude_start = 0;
        trans->alloc_exclude_nr = 0;
+       BUG_ON(ret);
+
+       path = btrfs_alloc_path();
+       BUG_ON(!path);
+       ret = btrfs_insert_extent_backref(trans, extent_root, path,
+                                         ins->objectid, root_objectid,
+                                         ref_generation, owner, owner_offset);
 
        BUG_ON(ret);
+       btrfs_free_path(path);
        finish_current_insert(trans, extent_root);
        pending_ret = del_pending_extents(trans, extent_root);
 
@@ -1321,15 +1496,43 @@ update_block:
  */
 struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
                                             struct btrfs_root *root,
-                                            u32 blocksize, u64 hint,
+                                            u32 blocksize,
+                                            u64 root_objectid, u64 hint,
+                                            u64 empty_size)
+{
+       u64 ref_generation;
+
+       if (root->ref_cows)
+               ref_generation = trans->transid;
+       else
+               ref_generation = 0;
+
+
+       return __btrfs_alloc_free_block(trans, root, blocksize, root_objectid,
+                                       ref_generation, 0, 0, hint, empty_size);
+}
+
+/*
+ * helper function to allocate a block for a given tree
+ * returns the tree buffer or NULL.
+ */
+struct extent_buffer *__btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
+                                            struct btrfs_root *root,
+                                            u32 blocksize,
+                                            u64 root_objectid,
+                                            u64 ref_generation,
+                                            u64 first_objectid,
+                                            int level,
+                                            u64 hint,
                                             u64 empty_size)
 {
        struct btrfs_key ins;
        int ret;
        struct extent_buffer *buf;
 
-       ret = btrfs_alloc_extent(trans, root, root->root_key.objectid,
-                                blocksize, empty_size, hint,
+       ret = btrfs_alloc_extent(trans, root, blocksize,
+                                root_objectid, ref_generation,
+                                first_objectid, level, empty_size, hint,
                                 (u64)-1, &ins, 0);
        if (ret) {
                BUG_ON(ret > 0);
@@ -1337,7 +1540,9 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
        }
        buf = btrfs_find_create_tree_block(root, ins.objectid, blocksize);
        if (!buf) {
-               btrfs_free_extent(trans, root, ins.objectid, blocksize, 0);
+               btrfs_free_extent(trans, root, ins.objectid, blocksize,
+                                 root->root_key.objectid, ref_generation,
+                                 0, 0, 0);
                return ERR_PTR(-ENOMEM);
        }
        btrfs_set_buffer_uptodate(buf);
@@ -1355,6 +1560,8 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
 static int drop_leaf_ref(struct btrfs_trans_handle *trans,
                         struct btrfs_root *root, struct extent_buffer *leaf)
 {
+       u64 leaf_owner;
+       u64 leaf_generation;
        struct btrfs_key key;
        struct btrfs_file_extent_item *fi;
        int i;
@@ -1363,6 +1570,9 @@ static int drop_leaf_ref(struct btrfs_trans_handle *trans,
 
        BUG_ON(!btrfs_is_leaf(leaf));
        nritems = btrfs_header_nritems(leaf);
+       leaf_owner = btrfs_header_owner(leaf);
+       leaf_generation = btrfs_header_generation(leaf);
+
        for (i = 0; i < nritems; i++) {
                u64 disk_bytenr;
 
@@ -1381,7 +1591,9 @@ static int drop_leaf_ref(struct btrfs_trans_handle *trans,
                if (disk_bytenr == 0)
                        continue;
                ret = btrfs_free_extent(trans, root, disk_bytenr,
-                               btrfs_file_extent_disk_num_bytes(leaf, fi), 0);
+                               btrfs_file_extent_disk_num_bytes(leaf, fi),
+                               leaf_owner, leaf_generation,
+                               key.objectid, key.offset, 0);
                BUG_ON(ret);
        }
        return 0;
@@ -1423,9 +1635,12 @@ static void reada_walk_down(struct btrfs_root *root,
 static int walk_down_tree(struct btrfs_trans_handle *trans, struct btrfs_root
                          *root, struct btrfs_path *path, int *level)
 {
+       u64 root_owner;
+       u64 root_gen;
+       u64 bytenr;
        struct extent_buffer *next;
        struct extent_buffer *cur;
-       u64 bytenr;
+       struct extent_buffer *parent;
        u32 blocksize;
        int ret;
        u32 refs;
@@ -1466,9 +1681,13 @@ static int walk_down_tree(struct btrfs_trans_handle *trans, struct btrfs_root
                ret = lookup_extent_ref(trans, root, bytenr, blocksize, &refs);
                BUG_ON(ret);
                if (refs != 1) {
+                       parent = path->nodes[*level];
+                       root_owner = btrfs_header_owner(parent);
+                       root_gen = btrfs_header_generation(parent);
                        path->slots[*level]++;
                        ret = btrfs_free_extent(trans, root, bytenr,
-                                               blocksize, 1);
+                                               blocksize, root_owner,
+                                               root_gen, 0, 0, 1);
                        BUG_ON(ret);
                        continue;
                }
@@ -1484,10 +1703,16 @@ static int walk_down_tree(struct btrfs_trans_handle *trans, struct btrfs_root
                                                blocksize, &refs);
                        BUG_ON(ret);
                        if (refs != 1) {
+                               parent = path->nodes[*level];
+                               root_owner = btrfs_header_owner(parent);
+                               root_gen = btrfs_header_generation(parent);
+
                                path->slots[*level]++;
                                free_extent_buffer(next);
-                               ret = btrfs_free_extent(trans, root,
-                                                       bytenr, blocksize, 1);
+                               ret = btrfs_free_extent(trans, root, bytenr,
+                                                       blocksize,
+                                                       root_owner,
+                                                       root_gen, 0, 0, 1);
                                BUG_ON(ret);
                                continue;
                        }
@@ -1502,8 +1727,19 @@ static int walk_down_tree(struct btrfs_trans_handle *trans, struct btrfs_root
 out:
        WARN_ON(*level < 0);
        WARN_ON(*level >= BTRFS_MAX_LEVEL);
+
+       if (path->nodes[*level] == root->node) {
+               root_owner = root->root_key.objectid;
+               parent = path->nodes[*level];
+       } else {
+               parent = path->nodes[*level + 1];
+               root_owner = btrfs_header_owner(parent);
+       }
+
+       root_gen = btrfs_header_generation(parent);
        ret = btrfs_free_extent(trans, root, path->nodes[*level]->start,
-                               path->nodes[*level]->len, 1);
+                               path->nodes[*level]->len,
+                               root_owner, root_gen, 0, 0, 1);
        free_extent_buffer(path->nodes[*level]);
        path->nodes[*level] = NULL;
        *level += 1;
@@ -1519,10 +1755,12 @@ out:
 static int walk_up_tree(struct btrfs_trans_handle *trans, struct btrfs_root
                        *root, struct btrfs_path *path, int *level)
 {
+       u64 root_owner;
+       u64 root_gen;
+       struct btrfs_root_item *root_item = &root->root_item;
        int i;
        int slot;
        int ret;
-       struct btrfs_root_item *root_item = &root->root_item;
 
        for(i = *level; i < BTRFS_MAX_LEVEL - 1 && path->nodes[i]; i++) {
                slot = path->slots[i];
@@ -1539,9 +1777,20 @@ static int walk_up_tree(struct btrfs_trans_handle *trans, struct btrfs_root
                        root_item->drop_level = i;
                        return 0;
                } else {
+                       if (path->nodes[*level] == root->node) {
+                               root_owner = root->root_key.objectid;
+                               root_gen =
+                                  btrfs_header_generation(path->nodes[*level]);
+                       } else {
+                               struct extent_buffer *node;
+                               node = path->nodes[*level + 1];
+                               root_owner = btrfs_header_owner(node);
+                               root_gen = btrfs_header_generation(node);
+                       }
                        ret = btrfs_free_extent(trans, root,
                                                path->nodes[*level]->start,
-                                               path->nodes[*level]->len, 1);
+                                               path->nodes[*level]->len,
+                                               root_owner, root_gen, 0, 0, 1);
                        BUG_ON(ret);
                        free_extent_buffer(path->nodes[*level]);
                        path->nodes[*level] = NULL;