aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorYan <zheng.yan@oracle.com>2008-07-30 16:29:20 -0400
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:04:05 -0400
commitbcc63abbf3e9bf948a1b0129b3e6120ec7d7f698 (patch)
tree1c66dc210f948f79c86786368d2c75b57482875d /fs
parent33958dc6d38fb4ca7e62273855fcb2db7e616263 (diff)
Btrfs: implement memory reclaim for leaf reference cache
The memory reclaiming issue happens when snapshot exists. In that case, some cache entries may not be used during old snapshot dropping, so they will remain in the cache until umount. The patch adds a field to struct btrfs_leaf_ref to record create time. Besides, the patch makes all dead roots of a given snapshot linked together in order of create time. After a old snapshot was completely dropped, we check the dead root list and remove all cache entries created before the oldest dead root in the list. Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/ctree.c1
-rw-r--r--fs/btrfs/ctree.h3
-rw-r--r--fs/btrfs/dir-item.c1
-rw-r--r--fs/btrfs/disk-io.c5
-rw-r--r--fs/btrfs/extent-tree.c18
-rw-r--r--fs/btrfs/extent_io.c1
-rw-r--r--fs/btrfs/file-item.c1
-rw-r--r--fs/btrfs/file.c1
-rw-r--r--fs/btrfs/inode.c22
-rw-r--r--fs/btrfs/locking.c1
-rw-r--r--fs/btrfs/print-tree.c1
-rw-r--r--fs/btrfs/ref-cache.c48
-rw-r--r--fs/btrfs/ref-cache.h11
-rw-r--r--fs/btrfs/transaction.c40
-rw-r--r--fs/btrfs/volumes.c1
15 files changed, 86 insertions, 69 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 245eb00435dd..c4792062dd53 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -3275,4 +3275,3 @@ int btrfs_previous_item(struct btrfs_root *root,
3275 } 3275 }
3276 return 1; 3276 return 1;
3277} 3277}
3278
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 83422088c629..be16cd49ef69 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -666,7 +666,8 @@ struct btrfs_root {
666 /* the dirty list is only used by non-reference counted roots */ 666 /* the dirty list is only used by non-reference counted roots */
667 struct list_head dirty_list; 667 struct list_head dirty_list;
668 668
669 spinlock_t orphan_lock; 669 spinlock_t list_lock;
670 struct list_head dead_list;
670 struct list_head orphan_list; 671 struct list_head orphan_list;
671}; 672};
672 673
diff --git a/fs/btrfs/dir-item.c b/fs/btrfs/dir-item.c
index eb4dd3d75cf9..125094617fe8 100644
--- a/fs/btrfs/dir-item.c
+++ b/fs/btrfs/dir-item.c
@@ -340,4 +340,3 @@ int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans,
340 } 340 }
341 return 0; 341 return 0;
342} 342}
343
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index ec1ba8ddb35f..e826730d750f 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -735,8 +735,9 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
735 735
736 INIT_LIST_HEAD(&root->dirty_list); 736 INIT_LIST_HEAD(&root->dirty_list);
737 INIT_LIST_HEAD(&root->orphan_list); 737 INIT_LIST_HEAD(&root->orphan_list);
738 INIT_LIST_HEAD(&root->dead_list);
738 spin_lock_init(&root->node_lock); 739 spin_lock_init(&root->node_lock);
739 spin_lock_init(&root->orphan_lock); 740 spin_lock_init(&root->list_lock);
740 mutex_init(&root->objectid_mutex); 741 mutex_init(&root->objectid_mutex);
741 742
742 btrfs_leaf_ref_tree_init(&root->ref_tree_struct); 743 btrfs_leaf_ref_tree_init(&root->ref_tree_struct);
@@ -1717,7 +1718,7 @@ int close_ctree(struct btrfs_root *root)
1717 printk("btrfs: at umount reference cache size %Lu\n", 1718 printk("btrfs: at umount reference cache size %Lu\n",
1718 fs_info->total_ref_cache_size); 1719 fs_info->total_ref_cache_size);
1719 } 1720 }
1720 1721
1721 if (fs_info->extent_root->node) 1722 if (fs_info->extent_root->node)
1722 free_extent_buffer(fs_info->extent_root->node); 1723 free_extent_buffer(fs_info->extent_root->node);
1723 1724
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index fe1ddbd2bfd6..37ca8df30c30 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -867,8 +867,8 @@ static int get_reference_status(struct btrfs_root *root, u64 bytenr,
867 /* 867 /*
868 * For (parent_gen > 0 && parent_gen > ref_gen): 868 * For (parent_gen > 0 && parent_gen > ref_gen):
869 * 869 *
870 * we reach here through the oldest root, therefore 870 * we reach here through the oldest root, therefore
871 * all other reference from same snapshot should have 871 * all other reference from same snapshot should have
872 * a larger generation. 872 * a larger generation.
873 */ 873 */
874 if ((root_objectid != btrfs_ref_root(leaf, ref_item)) || 874 if ((root_objectid != btrfs_ref_root(leaf, ref_item)) ||
@@ -954,7 +954,7 @@ int btrfs_cross_ref_exists(struct btrfs_root *root,
954 if (!eb) 954 if (!eb)
955 continue; 955 continue;
956 extent_start = eb->start; 956 extent_start = eb->start;
957 } else 957 } else
958 extent_start = bytenr; 958 extent_start = bytenr;
959 959
960 ret = get_reference_status(root, extent_start, ref_generation, 960 ret = get_reference_status(root, extent_start, ref_generation,
@@ -1048,7 +1048,7 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
1048 struct btrfs_leaf_ref *ref; 1048 struct btrfs_leaf_ref *ref;
1049 struct btrfs_extent_info *info; 1049 struct btrfs_extent_info *info;
1050 1050
1051 ref = btrfs_alloc_leaf_ref(nr_file_extents); 1051 ref = btrfs_alloc_leaf_ref(root, nr_file_extents);
1052 if (!ref) { 1052 if (!ref) {
1053 WARN_ON(1); 1053 WARN_ON(1);
1054 goto out; 1054 goto out;
@@ -1059,7 +1059,7 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
1059 ref->generation = btrfs_header_generation(buf); 1059 ref->generation = btrfs_header_generation(buf);
1060 ref->nritems = nr_file_extents; 1060 ref->nritems = nr_file_extents;
1061 info = ref->extents; 1061 info = ref->extents;
1062 1062
1063 for (i = 0; nr_file_extents > 0 && i < nritems; i++) { 1063 for (i = 0; nr_file_extents > 0 && i < nritems; i++) {
1064 u64 disk_bytenr; 1064 u64 disk_bytenr;
1065 btrfs_item_key_to_cpu(buf, &key, i); 1065 btrfs_item_key_to_cpu(buf, &key, i);
@@ -1085,7 +1085,7 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
1085 BUG_ON(!root->ref_tree); 1085 BUG_ON(!root->ref_tree);
1086 ret = btrfs_add_leaf_ref(root, ref); 1086 ret = btrfs_add_leaf_ref(root, ref);
1087 WARN_ON(ret); 1087 WARN_ON(ret);
1088 btrfs_free_leaf_ref(ref); 1088 btrfs_free_leaf_ref(root, ref);
1089 } 1089 }
1090out: 1090out:
1091 return 0; 1091 return 0;
@@ -2316,7 +2316,7 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
2316} 2316}
2317 2317
2318static int noinline drop_leaf_ref_no_cache(struct btrfs_trans_handle *trans, 2318static int noinline drop_leaf_ref_no_cache(struct btrfs_trans_handle *trans,
2319 struct btrfs_root *root, 2319 struct btrfs_root *root,
2320 struct extent_buffer *leaf) 2320 struct extent_buffer *leaf)
2321{ 2321{
2322 u64 leaf_owner; 2322 u64 leaf_owner;
@@ -2367,7 +2367,7 @@ static int noinline drop_leaf_ref_no_cache(struct btrfs_trans_handle *trans,
2367} 2367}
2368 2368
2369static int noinline drop_leaf_ref(struct btrfs_trans_handle *trans, 2369static int noinline drop_leaf_ref(struct btrfs_trans_handle *trans,
2370 struct btrfs_root *root, 2370 struct btrfs_root *root,
2371 struct btrfs_leaf_ref *ref) 2371 struct btrfs_leaf_ref *ref)
2372{ 2372{
2373 int i; 2373 int i;
@@ -2521,7 +2521,7 @@ static int noinline walk_down_tree(struct btrfs_trans_handle *trans,
2521 ret = drop_leaf_ref(trans, root, ref); 2521 ret = drop_leaf_ref(trans, root, ref);
2522 BUG_ON(ret); 2522 BUG_ON(ret);
2523 btrfs_remove_leaf_ref(root, ref); 2523 btrfs_remove_leaf_ref(root, ref);
2524 btrfs_free_leaf_ref(ref); 2524 btrfs_free_leaf_ref(root, ref);
2525 *level = 0; 2525 *level = 0;
2526 break; 2526 break;
2527 } 2527 }
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index 964ec1622d66..5368e3b6eb96 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -3497,4 +3497,3 @@ out:
3497 return ret; 3497 return ret;
3498} 3498}
3499EXPORT_SYMBOL(try_release_extent_buffer); 3499EXPORT_SYMBOL(try_release_extent_buffer);
3500
diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c
index afe42d00b5a6..2311061f070e 100644
--- a/fs/btrfs/file-item.c
+++ b/fs/btrfs/file-item.c
@@ -422,4 +422,3 @@ int btrfs_csum_truncate(struct btrfs_trans_handle *trans,
422 BUG_ON(ret); 422 BUG_ON(ret);
423 return ret; 423 return ret;
424} 424}
425
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index ded5281f8463..412ab4a26382 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -1095,4 +1095,3 @@ struct file_operations btrfs_file_operations = {
1095 .compat_ioctl = btrfs_ioctl, 1095 .compat_ioctl = btrfs_ioctl,
1096#endif 1096#endif
1097}; 1097};
1098
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 3aa82cec6bf7..7af8be076ee5 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -835,17 +835,17 @@ int btrfs_orphan_add(struct btrfs_trans_handle *trans, struct inode *inode)
835 struct btrfs_root *root = BTRFS_I(inode)->root; 835 struct btrfs_root *root = BTRFS_I(inode)->root;
836 int ret = 0; 836 int ret = 0;
837 837
838 spin_lock(&root->orphan_lock); 838 spin_lock(&root->list_lock);
839 839
840 /* already on the orphan list, we're good */ 840 /* already on the orphan list, we're good */
841 if (!list_empty(&BTRFS_I(inode)->i_orphan)) { 841 if (!list_empty(&BTRFS_I(inode)->i_orphan)) {
842 spin_unlock(&root->orphan_lock); 842 spin_unlock(&root->list_lock);
843 return 0; 843 return 0;
844 } 844 }
845 845
846 list_add(&BTRFS_I(inode)->i_orphan, &root->orphan_list); 846 list_add(&BTRFS_I(inode)->i_orphan, &root->orphan_list);
847 847
848 spin_unlock(&root->orphan_lock); 848 spin_unlock(&root->list_lock);
849 849
850 /* 850 /*
851 * insert an orphan item to track this unlinked/truncated file 851 * insert an orphan item to track this unlinked/truncated file
@@ -864,20 +864,20 @@ int btrfs_orphan_del(struct btrfs_trans_handle *trans, struct inode *inode)
864 struct btrfs_root *root = BTRFS_I(inode)->root; 864 struct btrfs_root *root = BTRFS_I(inode)->root;
865 int ret = 0; 865 int ret = 0;
866 866
867 spin_lock(&root->orphan_lock); 867 spin_lock(&root->list_lock);
868 868
869 if (list_empty(&BTRFS_I(inode)->i_orphan)) { 869 if (list_empty(&BTRFS_I(inode)->i_orphan)) {
870 spin_unlock(&root->orphan_lock); 870 spin_unlock(&root->list_lock);
871 return 0; 871 return 0;
872 } 872 }
873 873
874 list_del_init(&BTRFS_I(inode)->i_orphan); 874 list_del_init(&BTRFS_I(inode)->i_orphan);
875 if (!trans) { 875 if (!trans) {
876 spin_unlock(&root->orphan_lock); 876 spin_unlock(&root->list_lock);
877 return 0; 877 return 0;
878 } 878 }
879 879
880 spin_unlock(&root->orphan_lock); 880 spin_unlock(&root->list_lock);
881 881
882 ret = btrfs_del_orphan_item(trans, root, inode->i_ino); 882 ret = btrfs_del_orphan_item(trans, root, inode->i_ino);
883 883
@@ -973,9 +973,9 @@ void btrfs_orphan_cleanup(struct btrfs_root *root)
973 * add this inode to the orphan list so btrfs_orphan_del does 973 * add this inode to the orphan list so btrfs_orphan_del does
974 * the proper thing when we hit it 974 * the proper thing when we hit it
975 */ 975 */
976 spin_lock(&root->orphan_lock); 976 spin_lock(&root->list_lock);
977 list_add(&BTRFS_I(inode)->i_orphan, &root->orphan_list); 977 list_add(&BTRFS_I(inode)->i_orphan, &root->orphan_list);
978 spin_unlock(&root->orphan_lock); 978 spin_unlock(&root->list_lock);
979 979
980 /* 980 /*
981 * if this is a bad inode, means we actually succeeded in 981 * if this is a bad inode, means we actually succeeded in
@@ -3269,13 +3269,13 @@ void btrfs_destroy_inode(struct inode *inode)
3269 BTRFS_I(inode)->i_default_acl != BTRFS_ACL_NOT_CACHED) 3269 BTRFS_I(inode)->i_default_acl != BTRFS_ACL_NOT_CACHED)
3270 posix_acl_release(BTRFS_I(inode)->i_default_acl); 3270 posix_acl_release(BTRFS_I(inode)->i_default_acl);
3271 3271
3272 spin_lock(&BTRFS_I(inode)->root->orphan_lock); 3272 spin_lock(&BTRFS_I(inode)->root->list_lock);
3273 if (!list_empty(&BTRFS_I(inode)->i_orphan)) { 3273 if (!list_empty(&BTRFS_I(inode)->i_orphan)) {
3274 printk(KERN_ERR "BTRFS: inode %lu: inode still on the orphan" 3274 printk(KERN_ERR "BTRFS: inode %lu: inode still on the orphan"
3275 " list\n", inode->i_ino); 3275 " list\n", inode->i_ino);
3276 dump_stack(); 3276 dump_stack();
3277 } 3277 }
3278 spin_unlock(&BTRFS_I(inode)->root->orphan_lock); 3278 spin_unlock(&BTRFS_I(inode)->root->list_lock);
3279 3279
3280 while(1) { 3280 while(1) {
3281 ordered = btrfs_lookup_first_ordered_extent(inode, (u64)-1); 3281 ordered = btrfs_lookup_first_ordered_extent(inode, (u64)-1);
diff --git a/fs/btrfs/locking.c b/fs/btrfs/locking.c
index d617c29787fa..d43e14c7471a 100644
--- a/fs/btrfs/locking.c
+++ b/fs/btrfs/locking.c
@@ -56,4 +56,3 @@ int btrfs_tree_locked(struct extent_buffer *eb)
56{ 56{
57 return mutex_is_locked(&eb->mutex); 57 return mutex_is_locked(&eb->mutex);
58} 58}
59
diff --git a/fs/btrfs/print-tree.c b/fs/btrfs/print-tree.c
index 14d863720302..f1374d597a17 100644
--- a/fs/btrfs/print-tree.c
+++ b/fs/btrfs/print-tree.c
@@ -198,4 +198,3 @@ void btrfs_print_tree(struct btrfs_root *root, struct extent_buffer *c)
198 free_extent_buffer(next); 198 free_extent_buffer(next);
199 } 199 }
200} 200}
201
diff --git a/fs/btrfs/ref-cache.c b/fs/btrfs/ref-cache.c
index ec9587784a3d..272b9890c982 100644
--- a/fs/btrfs/ref-cache.c
+++ b/fs/btrfs/ref-cache.c
@@ -21,12 +21,18 @@
21#include "ref-cache.h" 21#include "ref-cache.h"
22#include "transaction.h" 22#include "transaction.h"
23 23
24struct btrfs_leaf_ref *btrfs_alloc_leaf_ref(int nr_extents) 24struct btrfs_leaf_ref *btrfs_alloc_leaf_ref(struct btrfs_root *root,
25 int nr_extents)
25{ 26{
26 struct btrfs_leaf_ref *ref; 27 struct btrfs_leaf_ref *ref;
28 size_t size = btrfs_leaf_ref_size(nr_extents);
27 29
28 ref = kmalloc(btrfs_leaf_ref_size(nr_extents), GFP_NOFS); 30 ref = kmalloc(size, GFP_NOFS);
29 if (ref) { 31 if (ref) {
32 spin_lock(&root->fs_info->ref_cache_lock);
33 root->fs_info->total_ref_cache_size += size;
34 spin_unlock(&root->fs_info->ref_cache_lock);
35
30 memset(ref, 0, sizeof(*ref)); 36 memset(ref, 0, sizeof(*ref));
31 atomic_set(&ref->usage, 1); 37 atomic_set(&ref->usage, 1);
32 INIT_LIST_HEAD(&ref->list); 38 INIT_LIST_HEAD(&ref->list);
@@ -34,14 +40,20 @@ struct btrfs_leaf_ref *btrfs_alloc_leaf_ref(int nr_extents)
34 return ref; 40 return ref;
35} 41}
36 42
37void btrfs_free_leaf_ref(struct btrfs_leaf_ref *ref) 43void btrfs_free_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref)
38{ 44{
39 if (!ref) 45 if (!ref)
40 return; 46 return;
41 WARN_ON(atomic_read(&ref->usage) == 0); 47 WARN_ON(atomic_read(&ref->usage) == 0);
42 if (atomic_dec_and_test(&ref->usage)) { 48 if (atomic_dec_and_test(&ref->usage)) {
49 size_t size = btrfs_leaf_ref_size(ref->nritems);
50
43 BUG_ON(ref->in_tree); 51 BUG_ON(ref->in_tree);
44 kfree(ref); 52 kfree(ref);
53
54 spin_lock(&root->fs_info->ref_cache_lock);
55 root->fs_info->total_ref_cache_size -= size;
56 spin_unlock(&root->fs_info->ref_cache_lock);
45 } 57 }
46} 58}
47 59
@@ -64,7 +76,7 @@ static struct rb_node *tree_insert(struct rb_root *root, u64 bytenr,
64 else 76 else
65 return parent; 77 return parent;
66 } 78 }
67 79
68 entry = rb_entry(node, struct btrfs_leaf_ref, rb_node); 80 entry = rb_entry(node, struct btrfs_leaf_ref, rb_node);
69 entry->in_tree = 1; 81 entry->in_tree = 1;
70 rb_link_node(node, parent, p); 82 rb_link_node(node, parent, p);
@@ -91,9 +103,8 @@ static struct rb_node *tree_search(struct rb_root *root, u64 bytenr)
91 return NULL; 103 return NULL;
92} 104}
93 105
94int btrfs_remove_leaf_refs(struct btrfs_root *root) 106int btrfs_remove_leaf_refs(struct btrfs_root *root, u64 max_root_gen)
95{ 107{
96 struct rb_node *rb;
97 struct btrfs_leaf_ref *ref = NULL; 108 struct btrfs_leaf_ref *ref = NULL;
98 struct btrfs_leaf_ref_tree *tree = root->ref_tree; 109 struct btrfs_leaf_ref_tree *tree = root->ref_tree;
99 110
@@ -101,17 +112,18 @@ int btrfs_remove_leaf_refs(struct btrfs_root *root)
101 return 0; 112 return 0;
102 113
103 spin_lock(&tree->lock); 114 spin_lock(&tree->lock);
104 while(!btrfs_leaf_ref_tree_empty(tree)) { 115 while(!list_empty(&tree->list)) {
105 rb = rb_first(&tree->root); 116 ref = list_entry(tree->list.next, struct btrfs_leaf_ref, list);
106 ref = rb_entry(rb, struct btrfs_leaf_ref, rb_node); 117 BUG_ON(!ref->in_tree);
118 if (ref->root_gen > max_root_gen)
119 break;
120
107 rb_erase(&ref->rb_node, &tree->root); 121 rb_erase(&ref->rb_node, &tree->root);
108 ref->in_tree = 0; 122 ref->in_tree = 0;
109 list_del_init(&ref->list); 123 list_del_init(&ref->list);
110 124
111 spin_unlock(&tree->lock); 125 spin_unlock(&tree->lock);
112 126 btrfs_free_leaf_ref(root, ref);
113 btrfs_free_leaf_ref(ref);
114
115 cond_resched(); 127 cond_resched();
116 spin_lock(&tree->lock); 128 spin_lock(&tree->lock);
117 } 129 }
@@ -143,7 +155,6 @@ int btrfs_add_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref)
143{ 155{
144 int ret = 0; 156 int ret = 0;
145 struct rb_node *rb; 157 struct rb_node *rb;
146 size_t size = btrfs_leaf_ref_size(ref->nritems);
147 struct btrfs_leaf_ref_tree *tree = root->ref_tree; 158 struct btrfs_leaf_ref_tree *tree = root->ref_tree;
148 159
149 spin_lock(&tree->lock); 160 spin_lock(&tree->lock);
@@ -151,9 +162,6 @@ int btrfs_add_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref)
151 if (rb) { 162 if (rb) {
152 ret = -EEXIST; 163 ret = -EEXIST;
153 } else { 164 } else {
154 spin_lock(&root->fs_info->ref_cache_lock);
155 root->fs_info->total_ref_cache_size += size;
156 spin_unlock(&root->fs_info->ref_cache_lock);
157 atomic_inc(&ref->usage); 165 atomic_inc(&ref->usage);
158 list_add_tail(&ref->list, &tree->list); 166 list_add_tail(&ref->list, &tree->list);
159 } 167 }
@@ -163,15 +171,10 @@ int btrfs_add_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref)
163 171
164int btrfs_remove_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref) 172int btrfs_remove_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref)
165{ 173{
166 size_t size = btrfs_leaf_ref_size(ref->nritems);
167 struct btrfs_leaf_ref_tree *tree = root->ref_tree; 174 struct btrfs_leaf_ref_tree *tree = root->ref_tree;
168 175
169 BUG_ON(!ref->in_tree); 176 BUG_ON(!ref->in_tree);
170 spin_lock(&tree->lock); 177 spin_lock(&tree->lock);
171
172 spin_lock(&root->fs_info->ref_cache_lock);
173 root->fs_info->total_ref_cache_size -= size;
174 spin_unlock(&root->fs_info->ref_cache_lock);
175 178
176 rb_erase(&ref->rb_node, &tree->root); 179 rb_erase(&ref->rb_node, &tree->root);
177 ref->in_tree = 0; 180 ref->in_tree = 0;
@@ -179,7 +182,6 @@ int btrfs_remove_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref)
179 182
180 spin_unlock(&tree->lock); 183 spin_unlock(&tree->lock);
181 184
182 btrfs_free_leaf_ref(ref); 185 btrfs_free_leaf_ref(root, ref);
183 return 0; 186 return 0;
184} 187}
185
diff --git a/fs/btrfs/ref-cache.h b/fs/btrfs/ref-cache.h
index 823c049f72f1..c361b321c0c3 100644
--- a/fs/btrfs/ref-cache.h
+++ b/fs/btrfs/ref-cache.h
@@ -30,6 +30,7 @@ struct btrfs_leaf_ref {
30 int in_tree; 30 int in_tree;
31 atomic_t usage; 31 atomic_t usage;
32 32
33 u64 root_gen;
33 u64 bytenr; 34 u64 bytenr;
34 u64 owner; 35 u64 owner;
35 u64 generation; 36 u64 generation;
@@ -41,14 +42,13 @@ struct btrfs_leaf_ref {
41 42
42static inline size_t btrfs_leaf_ref_size(int nr_extents) 43static inline size_t btrfs_leaf_ref_size(int nr_extents)
43{ 44{
44 return sizeof(struct btrfs_leaf_ref) + 45 return sizeof(struct btrfs_leaf_ref) +
45 sizeof(struct btrfs_extent_info) * nr_extents; 46 sizeof(struct btrfs_extent_info) * nr_extents;
46} 47}
47 48
48static inline void btrfs_leaf_ref_tree_init(struct btrfs_leaf_ref_tree *tree) 49static inline void btrfs_leaf_ref_tree_init(struct btrfs_leaf_ref_tree *tree)
49{ 50{
50 tree->root.rb_node = NULL; 51 tree->root.rb_node = NULL;
51 tree->last = NULL;
52 INIT_LIST_HEAD(&tree->list); 52 INIT_LIST_HEAD(&tree->list);
53 spin_lock_init(&tree->lock); 53 spin_lock_init(&tree->lock);
54} 54}
@@ -59,12 +59,13 @@ static inline int btrfs_leaf_ref_tree_empty(struct btrfs_leaf_ref_tree *tree)
59} 59}
60 60
61void btrfs_leaf_ref_tree_init(struct btrfs_leaf_ref_tree *tree); 61void btrfs_leaf_ref_tree_init(struct btrfs_leaf_ref_tree *tree);
62struct btrfs_leaf_ref *btrfs_alloc_leaf_ref(int nr_extents); 62struct btrfs_leaf_ref *btrfs_alloc_leaf_ref(struct btrfs_root *root,
63void btrfs_free_leaf_ref(struct btrfs_leaf_ref *ref); 63 int nr_extents);
64void btrfs_free_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref);
64struct btrfs_leaf_ref *btrfs_lookup_leaf_ref(struct btrfs_root *root, 65struct btrfs_leaf_ref *btrfs_lookup_leaf_ref(struct btrfs_root *root,
65 u64 bytenr); 66 u64 bytenr);
66int btrfs_add_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref); 67int btrfs_add_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref);
67int btrfs_remove_leaf_refs(struct btrfs_root *root); 68int btrfs_remove_leaf_refs(struct btrfs_root *root, u64 max_root_gen);
68int btrfs_remove_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref); 69int btrfs_remove_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref);
69 70
70#endif 71#endif
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 216f31571620..52c5524896a3 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -98,20 +98,24 @@ static noinline int record_root_in_trans(struct btrfs_root *root)
98 BUG_ON(!dirty); 98 BUG_ON(!dirty);
99 dirty->root = kmalloc(sizeof(*dirty->root), GFP_NOFS); 99 dirty->root = kmalloc(sizeof(*dirty->root), GFP_NOFS);
100 BUG_ON(!dirty->root); 100 BUG_ON(!dirty->root);
101
102 dirty->latest_root = root; 101 dirty->latest_root = root;
103 INIT_LIST_HEAD(&dirty->list); 102 INIT_LIST_HEAD(&dirty->list);
104 103
105 root->commit_root = btrfs_root_node(root); 104 root->commit_root = btrfs_root_node(root);
106 root->dirty_root = dirty;
107 105
108 memcpy(dirty->root, root, sizeof(*root)); 106 memcpy(dirty->root, root, sizeof(*root));
109 dirty->root->ref_tree = &root->ref_tree_struct;
110
111 spin_lock_init(&dirty->root->node_lock); 107 spin_lock_init(&dirty->root->node_lock);
108 spin_lock_init(&dirty->root->list_lock);
112 mutex_init(&dirty->root->objectid_mutex); 109 mutex_init(&dirty->root->objectid_mutex);
110 INIT_LIST_HEAD(&dirty->root->dead_list);
113 dirty->root->node = root->commit_root; 111 dirty->root->node = root->commit_root;
114 dirty->root->commit_root = NULL; 112 dirty->root->commit_root = NULL;
113
114 spin_lock(&root->list_lock);
115 list_add(&dirty->root->dead_list, &root->dead_list);
116 spin_unlock(&root->list_lock);
117
118 root->dirty_root = dirty;
115 } else { 119 } else {
116 WARN_ON(1); 120 WARN_ON(1);
117 } 121 }
@@ -356,8 +360,6 @@ int btrfs_commit_tree_roots(struct btrfs_trans_handle *trans,
356 list_del_init(next); 360 list_del_init(next);
357 root = list_entry(next, struct btrfs_root, dirty_list); 361 root = list_entry(next, struct btrfs_root, dirty_list);
358 update_cowonly_root(trans, root); 362 update_cowonly_root(trans, root);
359 if (root->fs_info->closing)
360 btrfs_remove_leaf_refs(root);
361 } 363 }
362 return 0; 364 return 0;
363} 365}
@@ -410,7 +412,11 @@ static noinline int add_dirty_roots(struct btrfs_trans_handle *trans,
410 412
411 free_extent_buffer(root->commit_root); 413 free_extent_buffer(root->commit_root);
412 root->commit_root = NULL; 414 root->commit_root = NULL;
413 415
416 spin_lock(&root->list_lock);
417 list_del_init(&dirty->root->dead_list);
418 spin_unlock(&root->list_lock);
419
414 kfree(dirty->root); 420 kfree(dirty->root);
415 kfree(dirty); 421 kfree(dirty);
416 422
@@ -497,6 +503,7 @@ static noinline int drop_dirty_roots(struct btrfs_root *tree_root,
497 unsigned long nr; 503 unsigned long nr;
498 u64 num_bytes; 504 u64 num_bytes;
499 u64 bytes_used; 505 u64 bytes_used;
506 u64 max_useless;
500 int ret = 0; 507 int ret = 0;
501 int err; 508 int err;
502 509
@@ -554,10 +561,25 @@ static noinline int drop_dirty_roots(struct btrfs_root *tree_root,
554 } 561 }
555 mutex_unlock(&root->fs_info->drop_mutex); 562 mutex_unlock(&root->fs_info->drop_mutex);
556 563
564 spin_lock(&root->list_lock);
565 list_del_init(&dirty->root->dead_list);
566 if (!list_empty(&root->dead_list)) {
567 struct btrfs_root *oldest;
568 oldest = list_entry(root->dead_list.prev,
569 struct btrfs_root, dead_list);
570 max_useless = oldest->root_key.offset - 1;
571 } else {
572 max_useless = root->root_key.offset - 1;
573 }
574 spin_unlock(&root->list_lock);
575
557 nr = trans->blocks_used; 576 nr = trans->blocks_used;
558 ret = btrfs_end_transaction(trans, tree_root); 577 ret = btrfs_end_transaction(trans, tree_root);
559 BUG_ON(ret); 578 BUG_ON(ret);
560 579
580 ret = btrfs_remove_leaf_refs(root, max_useless);
581 BUG_ON(ret);
582
561 free_extent_buffer(dirty->root->node); 583 free_extent_buffer(dirty->root->node);
562 kfree(dirty->root); 584 kfree(dirty->root);
563 kfree(dirty); 585 kfree(dirty);
@@ -785,10 +807,9 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
785 put_transaction(cur_trans); 807 put_transaction(cur_trans);
786 put_transaction(cur_trans); 808 put_transaction(cur_trans);
787 809
810 list_splice_init(&dirty_fs_roots, &root->fs_info->dead_roots);
788 if (root->fs_info->closing) 811 if (root->fs_info->closing)
789 list_splice_init(&root->fs_info->dead_roots, &dirty_fs_roots); 812 list_splice_init(&root->fs_info->dead_roots, &dirty_fs_roots);
790 else
791 list_splice_init(&dirty_fs_roots, &root->fs_info->dead_roots);
792 813
793 mutex_unlock(&root->fs_info->trans_mutex); 814 mutex_unlock(&root->fs_info->trans_mutex);
794 kmem_cache_free(btrfs_trans_handle_cachep, trans); 815 kmem_cache_free(btrfs_trans_handle_cachep, trans);
@@ -814,4 +835,3 @@ again:
814 } 835 }
815 return 0; 836 return 0;
816} 837}
817
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 5e6ee7a6f738..18db4cbe2794 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -2527,4 +2527,3 @@ again:
2527error: 2527error:
2528 return ret; 2528 return ret;
2529} 2529}
2530