diff options
-rw-r--r-- | fs/btrfs/ctree.h | 19 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 2 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 17 | ||||
-rw-r--r-- | fs/btrfs/ref-cache.c | 58 | ||||
-rw-r--r-- | fs/btrfs/ref-cache.h | 7 | ||||
-rw-r--r-- | fs/btrfs/transaction.c | 2 |
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 | ||
546 | struct btrfs_leaf_ref_tree { | ||
547 | struct rb_root root; | ||
548 | struct list_head list; | ||
549 | spinlock_t lock; | ||
550 | }; | ||
551 | |||
542 | struct btrfs_device; | 552 | struct btrfs_device; |
543 | struct btrfs_fs_devices; | 553 | struct btrfs_fs_devices; |
544 | struct btrfs_fs_info { | 554 | struct 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 | ||
673 | struct 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: | |||
1091 | int btrfs_cache_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, | 1091 | int 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 | ||
106 | int btrfs_remove_leaf_refs(struct btrfs_root *root, u64 max_root_gen) | 105 | int 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 | 145 | again: | |
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 | ||
154 | int btrfs_add_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref) | 164 | int 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 | ||
172 | int btrfs_remove_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref) | 188 | int 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 | ||
28 | struct btrfs_leaf_ref { | 28 | struct 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, | |||
64 | void btrfs_free_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref); | 65 | void btrfs_free_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref); |
65 | struct btrfs_leaf_ref *btrfs_lookup_leaf_ref(struct btrfs_root *root, | 66 | struct btrfs_leaf_ref *btrfs_lookup_leaf_ref(struct btrfs_root *root, |
66 | u64 bytenr); | 67 | u64 bytenr); |
67 | int btrfs_add_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref); | 68 | int btrfs_add_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref, |
68 | int btrfs_remove_leaf_refs(struct btrfs_root *root, u64 max_root_gen); | 69 | int shared); |
70 | int btrfs_remove_leaf_refs(struct btrfs_root *root, u64 max_root_gen, | ||
71 | int shared); | ||
69 | int btrfs_remove_leaf_ref(struct btrfs_root *root, struct btrfs_leaf_ref *ref); | 72 | int 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); |