Commit e5a2217e authored by Chris Mason's avatar Chris Mason

Fix btrfs_wait_ordered_extent_range to properly wait

Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent 7f3c74fb
...@@ -161,7 +161,8 @@ int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode, ...@@ -161,7 +161,8 @@ int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode,
while(bio_index < bio->bi_vcnt) { while(bio_index < bio->bi_vcnt) {
offset = page_offset(bvec->bv_page) + bvec->bv_offset; offset = page_offset(bvec->bv_page) + bvec->bv_offset;
if (offset >= ordered->file_offset + ordered->len) { if (offset >= ordered->file_offset + ordered->len ||
offset < ordered->file_offset) {
unsigned long bytes_left; unsigned long bytes_left;
sums->len = this_sum_bytes; sums->len = this_sum_bytes;
this_sum_bytes = 0; this_sum_bytes = 0;
......
...@@ -128,7 +128,9 @@ static int cow_file_range(struct inode *inode, u64 start, u64 end) ...@@ -128,7 +128,9 @@ static int cow_file_range(struct inode *inode, u64 start, u64 end)
goto out; goto out;
BUG_ON(num_bytes > btrfs_super_total_bytes(&root->fs_info->super_copy)); BUG_ON(num_bytes > btrfs_super_total_bytes(&root->fs_info->super_copy));
mutex_lock(&BTRFS_I(inode)->extent_mutex);
btrfs_drop_extent_cache(inode, start, start + num_bytes - 1); btrfs_drop_extent_cache(inode, start, start + num_bytes - 1);
mutex_unlock(&BTRFS_I(inode)->extent_mutex);
while(num_bytes > 0) { while(num_bytes > 0) {
cur_alloc_size = min(num_bytes, root->fs_info->max_extent); cur_alloc_size = min(num_bytes, root->fs_info->max_extent);
...@@ -144,6 +146,7 @@ static int cow_file_range(struct inode *inode, u64 start, u64 end) ...@@ -144,6 +146,7 @@ static int cow_file_range(struct inode *inode, u64 start, u64 end)
em->len = ins.offset; em->len = ins.offset;
em->block_start = ins.objectid; em->block_start = ins.objectid;
em->bdev = root->fs_info->fs_devices->latest_bdev; em->bdev = root->fs_info->fs_devices->latest_bdev;
mutex_lock(&BTRFS_I(inode)->extent_mutex);
set_bit(EXTENT_FLAG_PINNED, &em->flags); set_bit(EXTENT_FLAG_PINNED, &em->flags);
while(1) { while(1) {
spin_lock(&em_tree->lock); spin_lock(&em_tree->lock);
...@@ -156,6 +159,7 @@ static int cow_file_range(struct inode *inode, u64 start, u64 end) ...@@ -156,6 +159,7 @@ static int cow_file_range(struct inode *inode, u64 start, u64 end)
btrfs_drop_extent_cache(inode, start, btrfs_drop_extent_cache(inode, start,
start + ins.offset - 1); start + ins.offset - 1);
} }
mutex_unlock(&BTRFS_I(inode)->extent_mutex);
cur_alloc_size = ins.offset; cur_alloc_size = ins.offset;
ret = btrfs_add_ordered_extent(inode, start, ins.objectid, ret = btrfs_add_ordered_extent(inode, start, ins.objectid,
...@@ -487,6 +491,8 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end) ...@@ -487,6 +491,8 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
struct extent_map *em; struct extent_map *em;
u64 alloc_hint = 0; u64 alloc_hint = 0;
u64 clear_start;
u64 clear_end;
struct list_head list; struct list_head list;
struct btrfs_key ins; struct btrfs_key ins;
int ret; int ret;
...@@ -509,12 +515,14 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end) ...@@ -509,12 +515,14 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
ins.objectid = ordered_extent->start; ins.objectid = ordered_extent->start;
ins.offset = ordered_extent->len; ins.offset = ordered_extent->len;
ins.type = BTRFS_EXTENT_ITEM_KEY; ins.type = BTRFS_EXTENT_ITEM_KEY;
ret = btrfs_alloc_reserved_extent(trans, root, root->root_key.objectid, ret = btrfs_alloc_reserved_extent(trans, root, root->root_key.objectid,
trans->transid, inode->i_ino, trans->transid, inode->i_ino,
ordered_extent->file_offset, &ins); ordered_extent->file_offset, &ins);
BUG_ON(ret); BUG_ON(ret);
mutex_lock(&BTRFS_I(inode)->extent_mutex); mutex_lock(&BTRFS_I(inode)->extent_mutex);
ret = btrfs_drop_extents(trans, root, inode, ret = btrfs_drop_extents(trans, root, inode,
ordered_extent->file_offset, ordered_extent->file_offset,
ordered_extent->file_offset + ordered_extent->file_offset +
...@@ -528,13 +536,19 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end) ...@@ -528,13 +536,19 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
ordered_extent->len, 0); ordered_extent->len, 0);
BUG_ON(ret); BUG_ON(ret);
spin_lock(&em_tree->lock); spin_lock(&em_tree->lock);
em = lookup_extent_mapping(em_tree, ordered_extent->file_offset, clear_start = ordered_extent->file_offset;
ordered_extent->len); clear_end = ordered_extent->file_offset + ordered_extent->len;
while(clear_start < clear_end) {
em = lookup_extent_mapping(em_tree, clear_start,
clear_end - clear_start);
if (em) { if (em) {
clear_bit(EXTENT_FLAG_PINNED, &em->flags); clear_bit(EXTENT_FLAG_PINNED, &em->flags);
clear_start = em->start + em->len;
free_extent_map(em); free_extent_map(em);
} else {
break;
}
} }
spin_unlock(&em_tree->lock); spin_unlock(&em_tree->lock);
......
...@@ -324,22 +324,37 @@ void btrfs_start_ordered_extent(struct inode *inode, ...@@ -324,22 +324,37 @@ void btrfs_start_ordered_extent(struct inode *inode,
void btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len) void btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len)
{ {
u64 end; u64 end;
u64 orig_end;
u64 wait_end;
struct btrfs_ordered_extent *ordered; struct btrfs_ordered_extent *ordered;
int found; u64 mask = BTRFS_I(inode)->root->sectorsize - 1;
int should_wait = 0;
if (start + len < start) {
wait_end = (inode->i_size + mask) & ~mask;
orig_end = (u64)-1;
} else {
orig_end = start + len - 1;
wait_end = orig_end;
}
/* start IO across the range first to instantiate any delalloc
* extents
*/
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
do_sync_file_range(file, start, wait_end, SYNC_FILE_RANGE_WRITE);
#else
do_sync_mapping_range(inode->i_mapping, start, wait_end,
SYNC_FILE_RANGE_WRITE);
#endif
end = orig_end;
wait_on_extent_writeback(&BTRFS_I(inode)->io_tree, start, orig_end);
again:
if (start + len < start)
end = (u64)-1;
else
end = start + len - 1;
found = 0;
while(1) { while(1) {
ordered = btrfs_lookup_first_ordered_extent(inode, end); ordered = btrfs_lookup_first_ordered_extent(inode, end);
if (!ordered) { if (!ordered) {
break; break;
} }
if (ordered->file_offset >= start + len) { if (ordered->file_offset > orig_end) {
btrfs_put_ordered_extent(ordered); btrfs_put_ordered_extent(ordered);
break; break;
} }
...@@ -347,21 +362,15 @@ void btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len) ...@@ -347,21 +362,15 @@ void btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len)
btrfs_put_ordered_extent(ordered); btrfs_put_ordered_extent(ordered);
break; break;
} }
btrfs_start_ordered_extent(inode, ordered, should_wait); btrfs_start_ordered_extent(inode, ordered, 1);
found++;
end = ordered->file_offset; end = ordered->file_offset;
btrfs_put_ordered_extent(ordered); btrfs_put_ordered_extent(ordered);
if (end == 0) if (end == 0 || end == start)
break; break;
end--; end--;
} }
if (should_wait && found) {
should_wait = 0;
goto again;
}
} }
/* /*
* find an ordered extent corresponding to file_offset. return NULL if * find an ordered extent corresponding to file_offset. return NULL if
* nothing is found, otherwise take a reference on the extent and return it * nothing is found, otherwise take a reference on the extent and return it
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment