diff -r c038dde2ad20 extent-tree.c --- a/extent-tree.c Fri Jul 25 15:58:39 2008 -0400 +++ b/extent-tree.c Sun Jul 27 06:39:00 2008 -0400 @@ -994,7 +994,7 @@ int btrfs_inc_ref(struct btrfs_trans_han } } /* cache orignal leaf block's references */ - if (cache_ref && nr_file_extents > 0) { + if (level == 0 && cache_ref && buf != root->commit_root) { struct btrfs_leaf_ref *ref; struct btrfs_extent_info *info; @@ -1012,7 +1012,7 @@ int btrfs_inc_ref(struct btrfs_trans_han ref->nritems = nr_file_extents; info = ref->extents; - for (i = 0; i < nritems; i++) { + for (i = 0; nr_file_extents > 0 && i < nritems; i++) { u64 disk_bytenr; btrfs_item_key_to_cpu(buf, &key, i); if (btrfs_key_type(&key) != BTRFS_EXTENT_DATA_KEY) @@ -2490,7 +2490,6 @@ static int noinline walk_down_tree(struc if (path->slots[*level] == 0) reada_walk_down(root, cur, path->slots[*level]); - next = read_tree_block(root, bytenr, blocksize, ptr_gen); cond_resched(); diff -r c038dde2ad20 ref-cache.c --- a/ref-cache.c Fri Jul 25 15:58:39 2008 -0400 +++ b/ref-cache.c Sun Jul 27 06:39:00 2008 -0400 @@ -16,6 +16,7 @@ * Boston, MA 021110-1307, USA. */ +#include #include "ctree.h" #include "ref-cache.h" #include "transaction.h" @@ -110,6 +111,34 @@ static struct rb_node *tree_search(struc return NULL; } +int btrfs_remove_leaf_refs(struct btrfs_root *root) +{ + struct rb_node *rb; + struct btrfs_leaf_ref *ref = NULL; + struct btrfs_leaf_ref_tree *tree = root->ref_tree; + + if (!tree) + return 0; + + spin_lock(&tree->lock); + while(!btrfs_leaf_ref_tree_empty(tree)) { + tree->last = NULL; + rb = rb_first(&tree->root); + ref = rb_entry(rb, struct btrfs_leaf_ref, rb_node); + rb_erase(&ref->rb_node, &tree->root); + ref->in_tree = 0; + + spin_unlock(&tree->lock); + + btrfs_free_leaf_ref(ref); + + cond_resched(); + spin_lock(&tree->lock); + } + spin_unlock(&tree->lock); + return 0; +} + struct btrfs_leaf_ref *btrfs_lookup_leaf_ref(struct btrfs_root *root, struct btrfs_key *key) { @@ -170,8 +199,6 @@ int btrfs_remove_leaf_ref(struct btrfs_r BUG_ON(!ref->in_tree); spin_lock(&tree->lock); - rb_erase(&ref->rb_node, &tree->root); - ref->in_tree = 0; spin_lock(&root->fs_info->ref_cache_lock); root->fs_info->total_ref_cache_size -= size; @@ -187,6 +214,10 @@ int btrfs_remove_leaf_ref(struct btrfs_r } else tree->last = NULL; } + + rb_erase(&ref->rb_node, &tree->root); + ref->in_tree = 0; + spin_unlock(&tree->lock); btrfs_free_leaf_ref(ref); diff -r c038dde2ad20 ref-cache.h --- a/ref-cache.h Fri Jul 25 15:58:39 2008 -0400 +++ b/ref-cache.h Sun Jul 27 06:39:00 2008 -0400 @@ -68,4 +68,5 @@ struct btrfs_leaf_ref *btrfs_lookup_leaf struct btrfs_leaf_ref *btrfs_lookup_leaf_ref(struct btrfs_root *root, struct btrfs_key *key); int btrfs_add_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref); +int btrfs_remove_leaf_refs(struct btrfs_root *root); int btrfs_remove_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref); diff -r c038dde2ad20 transaction.c --- a/transaction.c Fri Jul 25 15:58:39 2008 -0400 +++ b/transaction.c Sun Jul 27 06:39:00 2008 -0400 @@ -539,9 +539,8 @@ static noinline int drop_dirty_roots(str ret = btrfs_end_transaction(trans, tree_root); BUG_ON(ret); - if (dirty->root->ref_tree) - WARN_ON(!btrfs_leaf_ref_tree_empty(dirty->root->ref_tree)); - + btrfs_remove_leaf_refs(dirty->root); + free_extent_buffer(dirty->root->node); kfree(dirty->root); kfree(dirty);