aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/extent-tree.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/extent-tree.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/extent-tree.c')
-rw-r--r--fs/btrfs/extent-tree.c28
1 files changed, 13 insertions, 15 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index fada9c22a021..535cee47fcfb 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -3379,11 +3379,13 @@ static int noinline relocate_data_extent(struct inode *reloc_inode,
3379 struct btrfs_root *root = BTRFS_I(reloc_inode)->root; 3379 struct btrfs_root *root = BTRFS_I(reloc_inode)->root;
3380 struct extent_map_tree *em_tree = &BTRFS_I(reloc_inode)->extent_tree; 3380 struct extent_map_tree *em_tree = &BTRFS_I(reloc_inode)->extent_tree;
3381 struct extent_map *em; 3381 struct extent_map *em;
3382 u64 start = extent_key->objectid - offset;
3383 u64 end = start + extent_key->offset - 1;
3382 3384
3383 em = alloc_extent_map(GFP_NOFS); 3385 em = alloc_extent_map(GFP_NOFS);
3384 BUG_ON(!em || IS_ERR(em)); 3386 BUG_ON(!em || IS_ERR(em));
3385 3387
3386 em->start = extent_key->objectid - offset; 3388 em->start = start;
3387 em->len = extent_key->offset; 3389 em->len = extent_key->offset;
3388 em->block_len = extent_key->offset; 3390 em->block_len = extent_key->offset;
3389 em->block_start = extent_key->objectid; 3391 em->block_start = extent_key->objectid;
@@ -3391,7 +3393,7 @@ static int noinline relocate_data_extent(struct inode *reloc_inode,
3391 set_bit(EXTENT_FLAG_PINNED, &em->flags); 3393 set_bit(EXTENT_FLAG_PINNED, &em->flags);
3392 3394
3393 /* setup extent map to cheat btrfs_readpage */ 3395 /* setup extent map to cheat btrfs_readpage */
3394 mutex_lock(&BTRFS_I(reloc_inode)->extent_mutex); 3396 lock_extent(&BTRFS_I(reloc_inode)->io_tree, start, end, GFP_NOFS);
3395 while (1) { 3397 while (1) {
3396 int ret; 3398 int ret;
3397 spin_lock(&em_tree->lock); 3399 spin_lock(&em_tree->lock);
@@ -3401,13 +3403,11 @@ static int noinline relocate_data_extent(struct inode *reloc_inode,
3401 free_extent_map(em); 3403 free_extent_map(em);
3402 break; 3404 break;
3403 } 3405 }
3404 btrfs_drop_extent_cache(reloc_inode, em->start, 3406 btrfs_drop_extent_cache(reloc_inode, start, end, 0);
3405 em->start + em->len - 1, 0);
3406 } 3407 }
3407 mutex_unlock(&BTRFS_I(reloc_inode)->extent_mutex); 3408 unlock_extent(&BTRFS_I(reloc_inode)->io_tree, start, end, GFP_NOFS);
3408 3409
3409 return relocate_inode_pages(reloc_inode, extent_key->objectid - offset, 3410 return relocate_inode_pages(reloc_inode, start, extent_key->offset);
3410 extent_key->offset);
3411} 3411}
3412 3412
3413struct btrfs_ref_path { 3413struct btrfs_ref_path {
@@ -3831,7 +3831,6 @@ next:
3831 * the file extent item was modified by someone 3831 * the file extent item was modified by someone
3832 * before the extent got locked. 3832 * before the extent got locked.
3833 */ 3833 */
3834 mutex_unlock(&BTRFS_I(inode)->extent_mutex);
3835 unlock_extent(&BTRFS_I(inode)->io_tree, lock_start, 3834 unlock_extent(&BTRFS_I(inode)->io_tree, lock_start,
3836 lock_end, GFP_NOFS); 3835 lock_end, GFP_NOFS);
3837 extent_locked = 0; 3836 extent_locked = 0;
@@ -3896,8 +3895,12 @@ next:
3896 lock_start = key.offset; 3895 lock_start = key.offset;
3897 lock_end = lock_start + num_bytes - 1; 3896 lock_end = lock_start + num_bytes - 1;
3898 } else { 3897 } else {
3899 BUG_ON(lock_start != key.offset); 3898 if (lock_start > key.offset ||
3900 BUG_ON(lock_end - lock_start + 1 < num_bytes); 3899 lock_end + 1 < key.offset + num_bytes) {
3900 unlock_extent(&BTRFS_I(inode)->io_tree,
3901 lock_start, lock_end, GFP_NOFS);
3902 extent_locked = 0;
3903 }
3901 } 3904 }
3902 3905
3903 if (!inode) { 3906 if (!inode) {
@@ -3951,7 +3954,6 @@ next:
3951 if (ordered) 3954 if (ordered)
3952 btrfs_put_ordered_extent(ordered); 3955 btrfs_put_ordered_extent(ordered);
3953 3956
3954 mutex_lock(&BTRFS_I(inode)->extent_mutex);
3955 extent_locked = 1; 3957 extent_locked = 1;
3956 continue; 3958 continue;
3957 } 3959 }
@@ -4073,7 +4075,6 @@ next:
4073 } 4075 }
4074 4076
4075 if (extent_locked) { 4077 if (extent_locked) {
4076 mutex_unlock(&BTRFS_I(inode)->extent_mutex);
4077 unlock_extent(&BTRFS_I(inode)->io_tree, lock_start, 4078 unlock_extent(&BTRFS_I(inode)->io_tree, lock_start,
4078 lock_end, GFP_NOFS); 4079 lock_end, GFP_NOFS);
4079 extent_locked = 0; 4080 extent_locked = 0;
@@ -4091,7 +4092,6 @@ out:
4091 if (inode) { 4092 if (inode) {
4092 mutex_unlock(&inode->i_mutex); 4093 mutex_unlock(&inode->i_mutex);
4093 if (extent_locked) { 4094 if (extent_locked) {
4094 mutex_unlock(&BTRFS_I(inode)->extent_mutex);
4095 unlock_extent(&BTRFS_I(inode)->io_tree, lock_start, 4095 unlock_extent(&BTRFS_I(inode)->io_tree, lock_start,
4096 lock_end, GFP_NOFS); 4096 lock_end, GFP_NOFS);
4097 } 4097 }
@@ -4180,10 +4180,8 @@ static int noinline invalidate_extent_cache(struct btrfs_root *root,
4180 4180
4181 lock_extent(&BTRFS_I(inode)->io_tree, key.offset, 4181 lock_extent(&BTRFS_I(inode)->io_tree, key.offset,
4182 key.offset + num_bytes - 1, GFP_NOFS); 4182 key.offset + num_bytes - 1, GFP_NOFS);
4183 mutex_lock(&BTRFS_I(inode)->extent_mutex);
4184 btrfs_drop_extent_cache(inode, key.offset, 4183 btrfs_drop_extent_cache(inode, key.offset,
4185 key.offset + num_bytes - 1, 1); 4184 key.offset + num_bytes - 1, 1);
4186 mutex_unlock(&BTRFS_I(inode)->extent_mutex);
4187 unlock_extent(&BTRFS_I(inode)->io_tree, key.offset, 4185 unlock_extent(&BTRFS_I(inode)->io_tree, key.offset,
4188 key.offset + num_bytes - 1, GFP_NOFS); 4186 key.offset + num_bytes - 1, GFP_NOFS);
4189 cond_resched(); 4187 cond_resched();