aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/file.c
diff options
context:
space:
mode:
authorYan Zheng <zheng.yan@oracle.com>2008-10-30 14:19:50 -0400
committerChris Mason <chris.mason@oracle.com>2008-10-30 14:19:50 -0400
commit6643558db29006825dbb10012b3f8890aca4bcd5 (patch)
tree0c0f4f7a0011749cda998431828cb9161747b51a /fs/btrfs/file.c
parent9036c10208e1fc496cef7692ba66a78699b360dc (diff)
Btrfs: Fix bookend extent race v2
When dropping middle part of an extent, btrfs_drop_extents truncates the extent at first, then inserts a bookend extent. Since truncation and insertion can't be done atomically, there is a small period that the bookend extent isn't in the tree. This causes problem for functions that search the tree for file extent item. The way to fix this is lock the range of the bookend extent before truncation. Signed-off-by: Yan Zheng <zheng.yan@oracle.com>
Diffstat (limited to 'fs/btrfs/file.c')
-rw-r--r--fs/btrfs/file.c31
1 files changed, 25 insertions, 6 deletions
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index b8a7637e14a1..1a0510ad030c 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -364,6 +364,7 @@ int noinline btrfs_drop_extents(struct btrfs_trans_handle *trans,
364 u64 start, u64 end, u64 inline_limit, u64 *hint_byte) 364 u64 start, u64 end, u64 inline_limit, u64 *hint_byte)
365{ 365{
366 u64 extent_end = 0; 366 u64 extent_end = 0;
367 u64 locked_end = end;
367 u64 search_start = start; 368 u64 search_start = start;
368 u64 leaf_start; 369 u64 leaf_start;
369 u64 ram_bytes = 0; 370 u64 ram_bytes = 0;
@@ -479,12 +480,6 @@ next_slot:
479 goto next_slot; 480 goto next_slot;
480 } 481 }
481 482
482 if (found_inline) {
483 u64 mask = root->sectorsize - 1;
484 search_start = (extent_end + mask) & ~mask;
485 } else
486 search_start = extent_end;
487
488 if (end <= extent_end && start >= key.offset && found_inline) 483 if (end <= extent_end && start >= key.offset && found_inline)
489 *hint_byte = EXTENT_MAP_INLINE; 484 *hint_byte = EXTENT_MAP_INLINE;
490 485
@@ -501,6 +496,26 @@ next_slot:
501 if (found_inline && start <= key.offset) 496 if (found_inline && start <= key.offset)
502 keep = 1; 497 keep = 1;
503 } 498 }
499
500 if (bookend && found_extent && locked_end < extent_end) {
501 ret = try_lock_extent(&BTRFS_I(inode)->io_tree,
502 locked_end, extent_end - 1, GFP_NOFS);
503 if (!ret) {
504 btrfs_release_path(root, path);
505 lock_extent(&BTRFS_I(inode)->io_tree,
506 locked_end, extent_end - 1, GFP_NOFS);
507 locked_end = extent_end;
508 continue;
509 }
510 locked_end = extent_end;
511 }
512
513 if (found_inline) {
514 u64 mask = root->sectorsize - 1;
515 search_start = (extent_end + mask) & ~mask;
516 } else
517 search_start = extent_end;
518
504 /* truncate existing extent */ 519 /* truncate existing extent */
505 if (start > key.offset) { 520 if (start > key.offset) {
506 u64 new_num; 521 u64 new_num;
@@ -638,6 +653,10 @@ next_slot:
638 } 653 }
639out: 654out:
640 btrfs_free_path(path); 655 btrfs_free_path(path);
656 if (locked_end > end) {
657 unlock_extent(&BTRFS_I(inode)->io_tree, end, locked_end - 1,
658 GFP_NOFS);
659 }
641 btrfs_check_file(root, inode); 660 btrfs_check_file(root, inode);
642 return ret; 661 return ret;
643} 662}