aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/extent_map.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/extent_map.c')
-rw-r--r--fs/btrfs/extent_map.c55
1 files changed, 53 insertions, 2 deletions
diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c
index 7c97b3301459..b8cbc8d5c7f7 100644
--- a/fs/btrfs/extent_map.c
+++ b/fs/btrfs/extent_map.c
@@ -11,7 +11,7 @@ static struct kmem_cache *extent_map_cache;
11 11
12int __init extent_map_init(void) 12int __init extent_map_init(void)
13{ 13{
14 extent_map_cache = kmem_cache_create("extent_map", 14 extent_map_cache = kmem_cache_create("btrfs_extent_map",
15 sizeof(struct extent_map), 0, 15 sizeof(struct extent_map), 0,
16 SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD, NULL); 16 SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD, NULL);
17 if (!extent_map_cache) 17 if (!extent_map_cache)
@@ -35,6 +35,7 @@ void extent_map_exit(void)
35void extent_map_tree_init(struct extent_map_tree *tree) 35void extent_map_tree_init(struct extent_map_tree *tree)
36{ 36{
37 tree->map = RB_ROOT; 37 tree->map = RB_ROOT;
38 INIT_LIST_HEAD(&tree->modified_extents);
38 rwlock_init(&tree->lock); 39 rwlock_init(&tree->lock);
39} 40}
40 41
@@ -54,7 +55,9 @@ struct extent_map *alloc_extent_map(void)
54 em->in_tree = 0; 55 em->in_tree = 0;
55 em->flags = 0; 56 em->flags = 0;
56 em->compress_type = BTRFS_COMPRESS_NONE; 57 em->compress_type = BTRFS_COMPRESS_NONE;
58 em->generation = 0;
57 atomic_set(&em->refs, 1); 59 atomic_set(&em->refs, 1);
60 INIT_LIST_HEAD(&em->list);
58 return em; 61 return em;
59} 62}
60 63
@@ -72,6 +75,7 @@ void free_extent_map(struct extent_map *em)
72 WARN_ON(atomic_read(&em->refs) == 0); 75 WARN_ON(atomic_read(&em->refs) == 0);
73 if (atomic_dec_and_test(&em->refs)) { 76 if (atomic_dec_and_test(&em->refs)) {
74 WARN_ON(em->in_tree); 77 WARN_ON(em->in_tree);
78 WARN_ON(!list_empty(&em->list));
75 kmem_cache_free(extent_map_cache, em); 79 kmem_cache_free(extent_map_cache, em);
76 } 80 }
77} 81}
@@ -198,6 +202,14 @@ static void try_merge_map(struct extent_map_tree *tree, struct extent_map *em)
198 em->block_len += merge->block_len; 202 em->block_len += merge->block_len;
199 em->block_start = merge->block_start; 203 em->block_start = merge->block_start;
200 merge->in_tree = 0; 204 merge->in_tree = 0;
205 if (merge->generation > em->generation) {
206 em->mod_start = em->start;
207 em->mod_len = em->len;
208 em->generation = merge->generation;
209 list_move(&em->list, &tree->modified_extents);
210 }
211
212 list_del_init(&merge->list);
201 rb_erase(&merge->rb_node, &tree->map); 213 rb_erase(&merge->rb_node, &tree->map);
202 free_extent_map(merge); 214 free_extent_map(merge);
203 } 215 }
@@ -211,14 +223,34 @@ static void try_merge_map(struct extent_map_tree *tree, struct extent_map *em)
211 em->block_len += merge->len; 223 em->block_len += merge->len;
212 rb_erase(&merge->rb_node, &tree->map); 224 rb_erase(&merge->rb_node, &tree->map);
213 merge->in_tree = 0; 225 merge->in_tree = 0;
226 if (merge->generation > em->generation) {
227 em->mod_len = em->len;
228 em->generation = merge->generation;
229 list_move(&em->list, &tree->modified_extents);
230 }
231 list_del_init(&merge->list);
214 free_extent_map(merge); 232 free_extent_map(merge);
215 } 233 }
216} 234}
217 235
218int unpin_extent_cache(struct extent_map_tree *tree, u64 start, u64 len) 236/**
237 * unpint_extent_cache - unpin an extent from the cache
238 * @tree: tree to unpin the extent in
239 * @start: logical offset in the file
240 * @len: length of the extent
241 * @gen: generation that this extent has been modified in
242 * @prealloc: if this is set we need to clear the prealloc flag
243 *
244 * Called after an extent has been written to disk properly. Set the generation
245 * to the generation that actually added the file item to the inode so we know
246 * we need to sync this extent when we call fsync().
247 */
248int unpin_extent_cache(struct extent_map_tree *tree, u64 start, u64 len,
249 u64 gen)
219{ 250{
220 int ret = 0; 251 int ret = 0;
221 struct extent_map *em; 252 struct extent_map *em;
253 bool prealloc = false;
222 254
223 write_lock(&tree->lock); 255 write_lock(&tree->lock);
224 em = lookup_extent_mapping(tree, start, len); 256 em = lookup_extent_mapping(tree, start, len);
@@ -228,10 +260,24 @@ int unpin_extent_cache(struct extent_map_tree *tree, u64 start, u64 len)
228 if (!em) 260 if (!em)
229 goto out; 261 goto out;
230 262
263 list_move(&em->list, &tree->modified_extents);
264 em->generation = gen;
231 clear_bit(EXTENT_FLAG_PINNED, &em->flags); 265 clear_bit(EXTENT_FLAG_PINNED, &em->flags);
266 em->mod_start = em->start;
267 em->mod_len = em->len;
268
269 if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags)) {
270 prealloc = true;
271 clear_bit(EXTENT_FLAG_PREALLOC, &em->flags);
272 }
232 273
233 try_merge_map(tree, em); 274 try_merge_map(tree, em);
234 275
276 if (prealloc) {
277 em->mod_start = em->start;
278 em->mod_len = em->len;
279 }
280
235 free_extent_map(em); 281 free_extent_map(em);
236out: 282out:
237 write_unlock(&tree->lock); 283 write_unlock(&tree->lock);
@@ -269,6 +315,9 @@ int add_extent_mapping(struct extent_map_tree *tree,
269 } 315 }
270 atomic_inc(&em->refs); 316 atomic_inc(&em->refs);
271 317
318 em->mod_start = em->start;
319 em->mod_len = em->len;
320
272 try_merge_map(tree, em); 321 try_merge_map(tree, em);
273out: 322out:
274 return ret; 323 return ret;
@@ -358,6 +407,8 @@ int remove_extent_mapping(struct extent_map_tree *tree, struct extent_map *em)
358 407
359 WARN_ON(test_bit(EXTENT_FLAG_PINNED, &em->flags)); 408 WARN_ON(test_bit(EXTENT_FLAG_PINNED, &em->flags));
360 rb_erase(&em->rb_node, &tree->map); 409 rb_erase(&em->rb_node, &tree->map);
410 if (!test_bit(EXTENT_FLAG_LOGGING, &em->flags))
411 list_del_init(&em->list);
361 em->in_tree = 0; 412 em->in_tree = 0;
362 return ret; 413 return ret;
363} 414}