diff options
Diffstat (limited to 'fs/btrfs/file.c')
-rw-r--r-- | fs/btrfs/file.c | 47 |
1 files changed, 46 insertions, 1 deletions
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 9fbda6552069..3f5525f0834c 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c | |||
@@ -356,12 +356,23 @@ out_unlock: | |||
356 | int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end) | 356 | int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end) |
357 | { | 357 | { |
358 | struct extent_map *em; | 358 | struct extent_map *em; |
359 | struct extent_map *split = NULL; | ||
360 | struct extent_map *split2 = NULL; | ||
359 | struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; | 361 | struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; |
360 | u64 len = end - start + 1; | 362 | u64 len = end - start + 1; |
363 | int ret; | ||
364 | int testend = 1; | ||
361 | 365 | ||
362 | if (end == (u64)-1) | 366 | if (end == (u64)-1) { |
363 | len = (u64)-1; | 367 | len = (u64)-1; |
368 | testend = 0; | ||
369 | } | ||
364 | while(1) { | 370 | while(1) { |
371 | if (!split) | ||
372 | split = alloc_extent_map(GFP_NOFS); | ||
373 | if (!split2) | ||
374 | split2 = alloc_extent_map(GFP_NOFS); | ||
375 | |||
365 | spin_lock(&em_tree->lock); | 376 | spin_lock(&em_tree->lock); |
366 | em = lookup_extent_mapping(em_tree, start, len); | 377 | em = lookup_extent_mapping(em_tree, start, len); |
367 | if (!em) { | 378 | if (!em) { |
@@ -369,6 +380,36 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end) | |||
369 | break; | 380 | break; |
370 | } | 381 | } |
371 | remove_extent_mapping(em_tree, em); | 382 | remove_extent_mapping(em_tree, em); |
383 | |||
384 | if (em->block_start < EXTENT_MAP_LAST_BYTE && | ||
385 | em->start < start) { | ||
386 | split->start = em->start; | ||
387 | split->len = start - em->start; | ||
388 | split->block_start = em->block_start; | ||
389 | split->bdev = em->bdev; | ||
390 | split->flags = em->flags; | ||
391 | ret = add_extent_mapping(em_tree, split); | ||
392 | BUG_ON(ret); | ||
393 | free_extent_map(split); | ||
394 | split = split2; | ||
395 | split2 = NULL; | ||
396 | } | ||
397 | if (em->block_start < EXTENT_MAP_LAST_BYTE && | ||
398 | testend && em->start + em->len > start + len) { | ||
399 | u64 diff = start + len - em->start; | ||
400 | |||
401 | split->start = start + len; | ||
402 | split->len = em->start + em->len - (start + len); | ||
403 | split->bdev = em->bdev; | ||
404 | split->flags = em->flags; | ||
405 | |||
406 | split->block_start = em->block_start + diff; | ||
407 | |||
408 | ret = add_extent_mapping(em_tree, split); | ||
409 | BUG_ON(ret); | ||
410 | free_extent_map(split); | ||
411 | split = NULL; | ||
412 | } | ||
372 | spin_unlock(&em_tree->lock); | 413 | spin_unlock(&em_tree->lock); |
373 | 414 | ||
374 | /* once for us */ | 415 | /* once for us */ |
@@ -376,6 +417,10 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end) | |||
376 | /* once for the tree*/ | 417 | /* once for the tree*/ |
377 | free_extent_map(em); | 418 | free_extent_map(em); |
378 | } | 419 | } |
420 | if (split) | ||
421 | free_extent_map(split); | ||
422 | if (split2) | ||
423 | free_extent_map(split2); | ||
379 | return 0; | 424 | return 0; |
380 | } | 425 | } |
381 | 426 | ||