diff options
Diffstat (limited to 'fs/btrfs/extent_map.c')
-rw-r--r-- | fs/btrfs/extent_map.c | 55 |
1 files changed, 51 insertions, 4 deletions
diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c index 30c9365861e6..5bc7a0d325e7 100644 --- a/fs/btrfs/extent_map.c +++ b/fs/btrfs/extent_map.c | |||
@@ -36,7 +36,7 @@ void extent_map_exit(void) | |||
36 | void extent_map_tree_init(struct extent_map_tree *tree, gfp_t mask) | 36 | void extent_map_tree_init(struct extent_map_tree *tree, gfp_t mask) |
37 | { | 37 | { |
38 | tree->map.rb_node = NULL; | 38 | tree->map.rb_node = NULL; |
39 | spin_lock_init(&tree->lock); | 39 | rwlock_init(&tree->lock); |
40 | } | 40 | } |
41 | 41 | ||
42 | /** | 42 | /** |
@@ -198,6 +198,56 @@ static int mergable_maps(struct extent_map *prev, struct extent_map *next) | |||
198 | return 0; | 198 | return 0; |
199 | } | 199 | } |
200 | 200 | ||
201 | int unpin_extent_cache(struct extent_map_tree *tree, u64 start, u64 len) | ||
202 | { | ||
203 | int ret = 0; | ||
204 | struct extent_map *merge = NULL; | ||
205 | struct rb_node *rb; | ||
206 | struct extent_map *em; | ||
207 | |||
208 | write_lock(&tree->lock); | ||
209 | em = lookup_extent_mapping(tree, start, len); | ||
210 | |||
211 | WARN_ON(em->start != start || !em); | ||
212 | |||
213 | if (!em) | ||
214 | goto out; | ||
215 | |||
216 | clear_bit(EXTENT_FLAG_PINNED, &em->flags); | ||
217 | |||
218 | if (em->start != 0) { | ||
219 | rb = rb_prev(&em->rb_node); | ||
220 | if (rb) | ||
221 | merge = rb_entry(rb, struct extent_map, rb_node); | ||
222 | if (rb && mergable_maps(merge, em)) { | ||
223 | em->start = merge->start; | ||
224 | em->len += merge->len; | ||
225 | em->block_len += merge->block_len; | ||
226 | em->block_start = merge->block_start; | ||
227 | merge->in_tree = 0; | ||
228 | rb_erase(&merge->rb_node, &tree->map); | ||
229 | free_extent_map(merge); | ||
230 | } | ||
231 | } | ||
232 | |||
233 | rb = rb_next(&em->rb_node); | ||
234 | if (rb) | ||
235 | merge = rb_entry(rb, struct extent_map, rb_node); | ||
236 | if (rb && mergable_maps(em, merge)) { | ||
237 | em->len += merge->len; | ||
238 | em->block_len += merge->len; | ||
239 | rb_erase(&merge->rb_node, &tree->map); | ||
240 | merge->in_tree = 0; | ||
241 | free_extent_map(merge); | ||
242 | } | ||
243 | |||
244 | free_extent_map(em); | ||
245 | out: | ||
246 | write_unlock(&tree->lock); | ||
247 | return ret; | ||
248 | |||
249 | } | ||
250 | |||
201 | /** | 251 | /** |
202 | * add_extent_mapping - add new extent map to the extent tree | 252 | * add_extent_mapping - add new extent map to the extent tree |
203 | * @tree: tree to insert new map in | 253 | * @tree: tree to insert new map in |
@@ -222,7 +272,6 @@ int add_extent_mapping(struct extent_map_tree *tree, | |||
222 | ret = -EEXIST; | 272 | ret = -EEXIST; |
223 | goto out; | 273 | goto out; |
224 | } | 274 | } |
225 | assert_spin_locked(&tree->lock); | ||
226 | rb = tree_insert(&tree->map, em->start, &em->rb_node); | 275 | rb = tree_insert(&tree->map, em->start, &em->rb_node); |
227 | if (rb) { | 276 | if (rb) { |
228 | ret = -EEXIST; | 277 | ret = -EEXIST; |
@@ -285,7 +334,6 @@ struct extent_map *lookup_extent_mapping(struct extent_map_tree *tree, | |||
285 | struct rb_node *next = NULL; | 334 | struct rb_node *next = NULL; |
286 | u64 end = range_end(start, len); | 335 | u64 end = range_end(start, len); |
287 | 336 | ||
288 | assert_spin_locked(&tree->lock); | ||
289 | rb_node = __tree_search(&tree->map, start, &prev, &next); | 337 | rb_node = __tree_search(&tree->map, start, &prev, &next); |
290 | if (!rb_node && prev) { | 338 | if (!rb_node && prev) { |
291 | em = rb_entry(prev, struct extent_map, rb_node); | 339 | em = rb_entry(prev, struct extent_map, rb_node); |
@@ -331,7 +379,6 @@ int remove_extent_mapping(struct extent_map_tree *tree, struct extent_map *em) | |||
331 | int ret = 0; | 379 | int ret = 0; |
332 | 380 | ||
333 | WARN_ON(test_bit(EXTENT_FLAG_PINNED, &em->flags)); | 381 | WARN_ON(test_bit(EXTENT_FLAG_PINNED, &em->flags)); |
334 | assert_spin_locked(&tree->lock); | ||
335 | rb_erase(&em->rb_node, &tree->map); | 382 | rb_erase(&em->rb_node, &tree->map); |
336 | em->in_tree = 0; | 383 | em->in_tree = 0; |
337 | return ret; | 384 | return ret; |