aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/ctree.h19
-rw-r--r--fs/btrfs/disk-io.c2
-rw-r--r--fs/btrfs/extent-tree.c17
-rw-r--r--fs/btrfs/ref-cache.c58
-rw-r--r--fs/btrfs/ref-cache.h7
-rw-r--r--fs/btrfs/transaction.c2
6 files changed, 71 insertions, 34 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index c683aaa925fa..b9f9f815ed09 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -81,6 +81,10 @@ struct btrfs_ordered_sum;
81#define BTRFS_TREE_LOG_OBJECTID -6ULL 81#define BTRFS_TREE_LOG_OBJECTID -6ULL
82#define BTRFS_TREE_LOG_FIXUP_OBJECTID -7ULL 82#define BTRFS_TREE_LOG_FIXUP_OBJECTID -7ULL
83 83
84/* for space balancing */
85#define BTRFS_TREE_RELOC_OBJECTID -8ULL
86#define BTRFS_DATA_RELOC_TREE_OBJECTID -9ULL
87
84/* dummy objectid represents multiple objectids */ 88/* dummy objectid represents multiple objectids */
85#define BTRFS_MULTIPLE_OBJECTIDS -255ULL 89#define BTRFS_MULTIPLE_OBJECTIDS -255ULL
86 90
@@ -539,6 +543,12 @@ struct btrfs_block_group_cache {
539 struct list_head list; 543 struct list_head list;
540}; 544};
541 545
546struct btrfs_leaf_ref_tree {
547 struct rb_root root;
548 struct list_head list;
549 spinlock_t lock;
550};
551
542struct btrfs_device; 552struct btrfs_device;
543struct btrfs_fs_devices; 553struct btrfs_fs_devices;
544struct btrfs_fs_info { 554struct btrfs_fs_info {
@@ -637,6 +647,8 @@ struct btrfs_fs_info {
637 struct task_struct *cleaner_kthread; 647 struct task_struct *cleaner_kthread;
638 int thread_pool_size; 648 int thread_pool_size;
639 649
650 struct btrfs_leaf_ref_tree shared_ref_tree;
651
640 struct kobject super_kobj; 652 struct kobject super_kobj;
641 struct completion kobj_unregister; 653 struct completion kobj_unregister;
642 int do_barriers; 654 int do_barriers;
@@ -670,13 +682,6 @@ struct btrfs_fs_info {
670 void *bdev_holder; 682 void *bdev_holder;
671}; 683};
672 684
673struct btrfs_leaf_ref_tree {
674 struct rb_root root;
675 struct btrfs_leaf_ref *last;
676 struct list_head list;
677 spinlock_t lock;
678};
679
680/* 685/*
681 * in ram representation of the tree. extent_root is used for all allocations 686 * in ram representation of the tree. extent_root is used for all allocations
682 * and for the extent tree extent_root root. 687 * and for the extent tree extent_root root.
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 71e81f3a765b..8969fee23318 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -1406,6 +1406,8 @@ struct btrfs_root *open_ctree(struct super_block *sb,
1406 fs_info->btree_inode->i_mapping, GFP_NOFS); 1406 fs_info->btree_inode->i_mapping, GFP_NOFS);
1407 fs_info->do_barriers = 1; 1407 fs_info->do_barriers = 1;
1408 1408
1409 btrfs_leaf_ref_tree_init(&fs_info->shared_ref_tree);
1410
1409 BTRFS_I(fs_info->btree_inode)->root = tree_root; 1411 BTRFS_I(fs_info->btree_inode)->root = tree_root;
1410 memset(&BTRFS_I(fs_info->btree_inode)->location, 0, 1412 memset(&BTRFS_I(fs_info->btree_inode)->location, 0,
1411 sizeof(struct btrfs_key)); 1413 sizeof(struct btrfs_key));
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 3e2f969de42d..9ab099bc01a4 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -1091,16 +1091,26 @@ out:
1091int btrfs_cache_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, 1091int btrfs_cache_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
1092 struct extent_buffer *buf, u32 nr_extents) 1092 struct extent_buffer *buf, u32 nr_extents)
1093{ 1093{
1094 u32 nritems;
1095 struct btrfs_key key; 1094 struct btrfs_key key;
1096 struct btrfs_file_extent_item *fi; 1095 struct btrfs_file_extent_item *fi;
1096 u64 root_gen;
1097 u32 nritems;
1097 int i; 1098 int i;
1098 int level; 1099 int level;
1099 int ret = 0; 1100 int ret = 0;
1101 int shared = 0;
1100 1102
1101 if (!root->ref_cows) 1103 if (!root->ref_cows)
1102 return 0; 1104 return 0;
1103 1105
1106 if (root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID) {
1107 shared = 0;
1108 root_gen = root->root_key.offset;
1109 } else {
1110 shared = 1;
1111 root_gen = trans->transid - 1;
1112 }
1113
1104 level = btrfs_header_level(buf); 1114 level = btrfs_header_level(buf);
1105 nritems = btrfs_header_nritems(buf); 1115 nritems = btrfs_header_nritems(buf);
1106 1116
@@ -1114,7 +1124,7 @@ int btrfs_cache_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
1114 goto out; 1124 goto out;
1115 } 1125 }
1116 1126
1117 ref->root_gen = root->root_key.offset; 1127 ref->root_gen = root_gen;
1118 ref->bytenr = buf->start; 1128 ref->bytenr = buf->start;
1119 ref->owner = btrfs_header_owner(buf); 1129 ref->owner = btrfs_header_owner(buf);
1120 ref->generation = btrfs_header_generation(buf); 1130 ref->generation = btrfs_header_generation(buf);
@@ -1143,8 +1153,7 @@ int btrfs_cache_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
1143 info++; 1153 info++;
1144 } 1154 }
1145 1155
1146 BUG_ON(!root->ref_tree); 1156 ret = btrfs_add_leaf_ref(root, ref, shared);
1147 ret = btrfs_add_leaf_ref(root, ref);
1148 WARN_ON(ret); 1157 WARN_ON(ret);
1149 btrfs_free_leaf_ref(root, ref); 1158 btrfs_free_leaf_ref(root, ref);
1150 } 1159 }
diff --git a/fs/btrfs/ref-cache.c b/fs/btrfs/ref-cache.c
index 272b9890c982..c5809988c875 100644
--- a/fs/btrfs/ref-cache.c
+++ b/fs/btrfs/ref-cache.c
@@ -78,7 +78,6 @@ static struct rb_node *tree_insert(struct rb_root *root, u64 bytenr,
78 } 78 }
79 79
80 entry = rb_entry(node, struct btrfs_leaf_ref, rb_node); 80 entry = rb_entry(node, struct btrfs_leaf_ref, rb_node);
81 entry->in_tree = 1;
82 rb_link_node(node, parent, p); 81 rb_link_node(node, parent, p);
83 rb_insert_color(node, root); 82 rb_insert_color(node, root);
84 return NULL; 83 return NULL;
@@ -103,23 +102,29 @@ static struct rb_node *tree_search(struct rb_root *root, u64 bytenr)
103 return NULL; 102 return NULL;
104} 103}
105 104
106int btrfs_remove_leaf_refs(struct btrfs_root *root, u64 max_root_gen) 105int btrfs_remove_leaf_refs(struct btrfs_root *root, u64 max_root_gen,
106 int shared)
107{ 107{
108 struct btrfs_leaf_ref *ref = NULL; 108 struct btrfs_leaf_ref *ref = NULL;
109 struct btrfs_leaf_ref_tree *tree = root->ref_tree; 109 struct btrfs_leaf_ref_tree *tree = root->ref_tree;
110 110
111 if (shared)
112 tree = &root->fs_info->shared_ref_tree;
111 if (!tree) 113 if (!tree)
112 return 0; 114 return 0;
113 115
114 spin_lock(&tree->lock); 116 spin_lock(&tree->lock);
115 while(!list_empty(&tree->list)) { 117 while(!list_empty(&tree->list)) {
116 ref = list_entry(tree->list.next, struct btrfs_leaf_ref, list); 118 ref = list_entry(tree->list.next, struct btrfs_leaf_ref, list);
117 BUG_ON(!ref->in_tree); 119 BUG_ON(ref->tree != tree);
118 if (ref->root_gen > max_root_gen) 120 if (ref->root_gen > max_root_gen)
119 break; 121 break;
122 if (!xchg(&ref->in_tree, 0)) {
123 cond_resched_lock(&tree->lock);
124 continue;
125 }
120 126
121 rb_erase(&ref->rb_node, &tree->root); 127 rb_erase(&ref->rb_node, &tree->root);
122 ref->in_tree = 0;
123 list_del_init(&ref->list); 128 list_del_init(&ref->list);
124 129
125 spin_unlock(&tree->lock); 130 spin_unlock(&tree->lock);
@@ -137,32 +142,43 @@ struct btrfs_leaf_ref *btrfs_lookup_leaf_ref(struct btrfs_root *root,
137 struct rb_node *rb; 142 struct rb_node *rb;
138 struct btrfs_leaf_ref *ref = NULL; 143 struct btrfs_leaf_ref *ref = NULL;
139 struct btrfs_leaf_ref_tree *tree = root->ref_tree; 144 struct btrfs_leaf_ref_tree *tree = root->ref_tree;
140 145again:
141 if (!tree) 146 if (tree) {
142 return NULL; 147 spin_lock(&tree->lock);
143 148 rb = tree_search(&tree->root, bytenr);
144 spin_lock(&tree->lock); 149 if (rb)
145 rb = tree_search(&tree->root, bytenr); 150 ref = rb_entry(rb, struct btrfs_leaf_ref, rb_node);
146 if (rb) 151 if (ref)
147 ref = rb_entry(rb, struct btrfs_leaf_ref, rb_node); 152 atomic_inc(&ref->usage);
148 if (ref) 153 spin_unlock(&tree->lock);
149 atomic_inc(&ref->usage); 154 if (ref)
150 spin_unlock(&tree->lock); 155 return ref;
151 return ref; 156 }
157 if (tree != &root->fs_info->shared_ref_tree) {
158 tree = &root->fs_info->shared_ref_tree;
159 goto again;
160 }
161 return NULL;
152} 162}
153 163
154int btrfs_add_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref) 164int btrfs_add_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref,
165 int shared)
155{ 166{
156 int ret = 0; 167 int ret = 0;
157 struct rb_node *rb; 168 struct rb_node *rb;
158 struct btrfs_leaf_ref_tree *tree = root->ref_tree; 169 struct btrfs_leaf_ref_tree *tree = root->ref_tree;
159 170
171 if (shared)
172 tree = &root->fs_info->shared_ref_tree;
173
160 spin_lock(&tree->lock); 174 spin_lock(&tree->lock);
161 rb = tree_insert(&tree->root, ref->bytenr, &ref->rb_node); 175 rb = tree_insert(&tree->root, ref->bytenr, &ref->rb_node);
162 if (rb) { 176 if (rb) {
163 ret = -EEXIST; 177 ret = -EEXIST;
164 } else { 178 } else {
165 atomic_inc(&ref->usage); 179 atomic_inc(&ref->usage);
180 ref->tree = tree;
181 ref->in_tree = 1;
166 list_add_tail(&ref->list, &tree->list); 182 list_add_tail(&ref->list, &tree->list);
167 } 183 }
168 spin_unlock(&tree->lock); 184 spin_unlock(&tree->lock);
@@ -171,13 +187,15 @@ int btrfs_add_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref)
171 187
172int btrfs_remove_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref) 188int btrfs_remove_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref)
173{ 189{
174 struct btrfs_leaf_ref_tree *tree = root->ref_tree; 190 struct btrfs_leaf_ref_tree *tree;
191
192 if (!xchg(&ref->in_tree, 0))
193 return 0;
175 194
176 BUG_ON(!ref->in_tree); 195 tree = ref->tree;
177 spin_lock(&tree->lock); 196 spin_lock(&tree->lock);
178 197
179 rb_erase(&ref->rb_node, &tree->root); 198 rb_erase(&ref->rb_node, &tree->root);
180 ref->in_tree = 0;
181 list_del_init(&ref->list); 199 list_del_init(&ref->list);
182 200
183 spin_unlock(&tree->lock); 201 spin_unlock(&tree->lock);
diff --git a/fs/btrfs/ref-cache.h b/fs/btrfs/ref-cache.h
index c361b321c0c3..617564787f52 100644
--- a/fs/btrfs/ref-cache.h
+++ b/fs/btrfs/ref-cache.h
@@ -27,6 +27,7 @@ struct btrfs_extent_info {
27 27
28struct btrfs_leaf_ref { 28struct btrfs_leaf_ref {
29 struct rb_node rb_node; 29 struct rb_node rb_node;
30 struct btrfs_leaf_ref_tree *tree;
30 int in_tree; 31 int in_tree;
31 atomic_t usage; 32 atomic_t usage;
32 33
@@ -64,8 +65,10 @@ struct btrfs_leaf_ref *btrfs_alloc_leaf_ref(struct btrfs_root *root,
64void btrfs_free_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref); 65void btrfs_free_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref);
65struct btrfs_leaf_ref *btrfs_lookup_leaf_ref(struct btrfs_root *root, 66struct btrfs_leaf_ref *btrfs_lookup_leaf_ref(struct btrfs_root *root,
66 u64 bytenr); 67 u64 bytenr);
67int btrfs_add_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref); 68int btrfs_add_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref,
68int btrfs_remove_leaf_refs(struct btrfs_root *root, u64 max_root_gen); 69 int shared);
70int btrfs_remove_leaf_refs(struct btrfs_root *root, u64 max_root_gen,
71 int shared);
69int btrfs_remove_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref); 72int btrfs_remove_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref);
70 73
71#endif 74#endif
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 151b00d52593..656baefa5255 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -650,7 +650,7 @@ static noinline int drop_dirty_roots(struct btrfs_root *tree_root,
650 ret = btrfs_end_transaction(trans, tree_root); 650 ret = btrfs_end_transaction(trans, tree_root);
651 BUG_ON(ret); 651 BUG_ON(ret);
652 652
653 ret = btrfs_remove_leaf_refs(root, max_useless); 653 ret = btrfs_remove_leaf_refs(root, max_useless, 0);
654 BUG_ON(ret); 654 BUG_ON(ret);
655 655
656 free_extent_buffer(dirty->root->node); 656 free_extent_buffer(dirty->root->node);