diff options
Diffstat (limited to 'fs/btrfs/extent_map.c')
| -rw-r--r-- | fs/btrfs/extent_map.c | 55 |
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 | ||
| 12 | int __init extent_map_init(void) | 12 | int __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) | |||
| 35 | void extent_map_tree_init(struct extent_map_tree *tree) | 35 | void 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 | ||
| 218 | int 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 | */ | ||
| 248 | int 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); |
| 236 | out: | 282 | out: |
| 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); |
| 273 | out: | 322 | out: |
| 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 | } |
