diff options
author | Chris Mason <chris.mason@oracle.com> | 2008-07-18 20:42:20 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:04:05 -0400 |
commit | e5a2217ef6ff088d08a27208929a6f9c635d672c (patch) | |
tree | 47dfed451e11357a5e066180eebba8db942af2b3 /fs | |
parent | 7f3c74fb831fa19bafe087e817c0a5ff3883f1ea (diff) |
Fix btrfs_wait_ordered_extent_range to properly wait
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/file-item.c | 3 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 26 | ||||
-rw-r--r-- | fs/btrfs/ordered-data.c | 45 |
3 files changed, 49 insertions, 25 deletions
diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c index d9c69e16d368..45127e4797c8 100644 --- a/fs/btrfs/file-item.c +++ b/fs/btrfs/file-item.c | |||
@@ -161,7 +161,8 @@ int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode, | |||
161 | 161 | ||
162 | while(bio_index < bio->bi_vcnt) { | 162 | while(bio_index < bio->bi_vcnt) { |
163 | offset = page_offset(bvec->bv_page) + bvec->bv_offset; | 163 | offset = page_offset(bvec->bv_page) + bvec->bv_offset; |
164 | if (offset >= ordered->file_offset + ordered->len) { | 164 | if (offset >= ordered->file_offset + ordered->len || |
165 | offset < ordered->file_offset) { | ||
165 | unsigned long bytes_left; | 166 | unsigned long bytes_left; |
166 | sums->len = this_sum_bytes; | 167 | sums->len = this_sum_bytes; |
167 | this_sum_bytes = 0; | 168 | this_sum_bytes = 0; |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 08dbe738b512..50ee4befac8e 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -128,7 +128,9 @@ static int cow_file_range(struct inode *inode, u64 start, u64 end) | |||
128 | goto out; | 128 | goto out; |
129 | 129 | ||
130 | BUG_ON(num_bytes > btrfs_super_total_bytes(&root->fs_info->super_copy)); | 130 | BUG_ON(num_bytes > btrfs_super_total_bytes(&root->fs_info->super_copy)); |
131 | mutex_lock(&BTRFS_I(inode)->extent_mutex); | ||
131 | btrfs_drop_extent_cache(inode, start, start + num_bytes - 1); | 132 | btrfs_drop_extent_cache(inode, start, start + num_bytes - 1); |
133 | mutex_unlock(&BTRFS_I(inode)->extent_mutex); | ||
132 | 134 | ||
133 | while(num_bytes > 0) { | 135 | while(num_bytes > 0) { |
134 | cur_alloc_size = min(num_bytes, root->fs_info->max_extent); | 136 | 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 | em->len = ins.offset; | 146 | em->len = ins.offset; |
145 | em->block_start = ins.objectid; | 147 | em->block_start = ins.objectid; |
146 | em->bdev = root->fs_info->fs_devices->latest_bdev; | 148 | em->bdev = root->fs_info->fs_devices->latest_bdev; |
149 | mutex_lock(&BTRFS_I(inode)->extent_mutex); | ||
147 | set_bit(EXTENT_FLAG_PINNED, &em->flags); | 150 | set_bit(EXTENT_FLAG_PINNED, &em->flags); |
148 | while(1) { | 151 | while(1) { |
149 | spin_lock(&em_tree->lock); | 152 | spin_lock(&em_tree->lock); |
@@ -156,6 +159,7 @@ static int cow_file_range(struct inode *inode, u64 start, u64 end) | |||
156 | btrfs_drop_extent_cache(inode, start, | 159 | btrfs_drop_extent_cache(inode, start, |
157 | start + ins.offset - 1); | 160 | start + ins.offset - 1); |
158 | } | 161 | } |
162 | mutex_unlock(&BTRFS_I(inode)->extent_mutex); | ||
159 | 163 | ||
160 | cur_alloc_size = ins.offset; | 164 | cur_alloc_size = ins.offset; |
161 | ret = btrfs_add_ordered_extent(inode, start, ins.objectid, | 165 | 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 | struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; | 491 | struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; |
488 | struct extent_map *em; | 492 | struct extent_map *em; |
489 | u64 alloc_hint = 0; | 493 | u64 alloc_hint = 0; |
494 | u64 clear_start; | ||
495 | u64 clear_end; | ||
490 | struct list_head list; | 496 | struct list_head list; |
491 | struct btrfs_key ins; | 497 | struct btrfs_key ins; |
492 | int ret; | 498 | int ret; |
@@ -509,12 +515,14 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end) | |||
509 | ins.objectid = ordered_extent->start; | 515 | ins.objectid = ordered_extent->start; |
510 | ins.offset = ordered_extent->len; | 516 | ins.offset = ordered_extent->len; |
511 | ins.type = BTRFS_EXTENT_ITEM_KEY; | 517 | ins.type = BTRFS_EXTENT_ITEM_KEY; |
518 | |||
512 | ret = btrfs_alloc_reserved_extent(trans, root, root->root_key.objectid, | 519 | ret = btrfs_alloc_reserved_extent(trans, root, root->root_key.objectid, |
513 | trans->transid, inode->i_ino, | 520 | trans->transid, inode->i_ino, |
514 | ordered_extent->file_offset, &ins); | 521 | ordered_extent->file_offset, &ins); |
515 | BUG_ON(ret); | 522 | BUG_ON(ret); |
516 | 523 | ||
517 | mutex_lock(&BTRFS_I(inode)->extent_mutex); | 524 | mutex_lock(&BTRFS_I(inode)->extent_mutex); |
525 | |||
518 | ret = btrfs_drop_extents(trans, root, inode, | 526 | ret = btrfs_drop_extents(trans, root, inode, |
519 | ordered_extent->file_offset, | 527 | ordered_extent->file_offset, |
520 | ordered_extent->file_offset + | 528 | ordered_extent->file_offset + |
@@ -528,13 +536,19 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end) | |||
528 | ordered_extent->len, 0); | 536 | ordered_extent->len, 0); |
529 | BUG_ON(ret); | 537 | BUG_ON(ret); |
530 | 538 | ||
531 | |||
532 | spin_lock(&em_tree->lock); | 539 | spin_lock(&em_tree->lock); |
533 | em = lookup_extent_mapping(em_tree, ordered_extent->file_offset, | 540 | clear_start = ordered_extent->file_offset; |
534 | ordered_extent->len); | 541 | clear_end = ordered_extent->file_offset + ordered_extent->len; |
535 | if (em) { | 542 | while(clear_start < clear_end) { |
536 | clear_bit(EXTENT_FLAG_PINNED, &em->flags); | 543 | em = lookup_extent_mapping(em_tree, clear_start, |
537 | free_extent_map(em); | 544 | clear_end - clear_start); |
545 | if (em) { | ||
546 | clear_bit(EXTENT_FLAG_PINNED, &em->flags); | ||
547 | clear_start = em->start + em->len; | ||
548 | free_extent_map(em); | ||
549 | } else { | ||
550 | break; | ||
551 | } | ||
538 | } | 552 | } |
539 | spin_unlock(&em_tree->lock); | 553 | spin_unlock(&em_tree->lock); |
540 | 554 | ||
diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c index 1ddb7bceea99..c2b4a9c4ddb6 100644 --- a/fs/btrfs/ordered-data.c +++ b/fs/btrfs/ordered-data.c | |||
@@ -324,22 +324,37 @@ void btrfs_start_ordered_extent(struct inode *inode, | |||
324 | void btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len) | 324 | void btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len) |
325 | { | 325 | { |
326 | u64 end; | 326 | u64 end; |
327 | u64 orig_end; | ||
328 | u64 wait_end; | ||
327 | struct btrfs_ordered_extent *ordered; | 329 | struct btrfs_ordered_extent *ordered; |
328 | int found; | 330 | u64 mask = BTRFS_I(inode)->root->sectorsize - 1; |
329 | int should_wait = 0; | 331 | |
330 | 332 | if (start + len < start) { | |
331 | again: | 333 | wait_end = (inode->i_size + mask) & ~mask; |
332 | if (start + len < start) | 334 | orig_end = (u64)-1; |
333 | end = (u64)-1; | 335 | } else { |
334 | else | 336 | orig_end = start + len - 1; |
335 | end = start + len - 1; | 337 | wait_end = orig_end; |
336 | found = 0; | 338 | } |
339 | |||
340 | /* start IO across the range first to instantiate any delalloc | ||
341 | * extents | ||
342 | */ | ||
343 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) | ||
344 | do_sync_file_range(file, start, wait_end, SYNC_FILE_RANGE_WRITE); | ||
345 | #else | ||
346 | do_sync_mapping_range(inode->i_mapping, start, wait_end, | ||
347 | SYNC_FILE_RANGE_WRITE); | ||
348 | #endif | ||
349 | end = orig_end; | ||
350 | wait_on_extent_writeback(&BTRFS_I(inode)->io_tree, start, orig_end); | ||
351 | |||
337 | while(1) { | 352 | while(1) { |
338 | ordered = btrfs_lookup_first_ordered_extent(inode, end); | 353 | ordered = btrfs_lookup_first_ordered_extent(inode, end); |
339 | if (!ordered) { | 354 | if (!ordered) { |
340 | break; | 355 | break; |
341 | } | 356 | } |
342 | if (ordered->file_offset >= start + len) { | 357 | if (ordered->file_offset > orig_end) { |
343 | btrfs_put_ordered_extent(ordered); | 358 | btrfs_put_ordered_extent(ordered); |
344 | break; | 359 | break; |
345 | } | 360 | } |
@@ -347,21 +362,15 @@ again: | |||
347 | btrfs_put_ordered_extent(ordered); | 362 | btrfs_put_ordered_extent(ordered); |
348 | break; | 363 | break; |
349 | } | 364 | } |
350 | btrfs_start_ordered_extent(inode, ordered, should_wait); | 365 | btrfs_start_ordered_extent(inode, ordered, 1); |
351 | found++; | ||
352 | end = ordered->file_offset; | 366 | end = ordered->file_offset; |
353 | btrfs_put_ordered_extent(ordered); | 367 | btrfs_put_ordered_extent(ordered); |
354 | if (end == 0) | 368 | if (end == 0 || end == start) |
355 | break; | 369 | break; |
356 | end--; | 370 | end--; |
357 | } | 371 | } |
358 | if (should_wait && found) { | ||
359 | should_wait = 0; | ||
360 | goto again; | ||
361 | } | ||
362 | } | 372 | } |
363 | 373 | ||
364 | |||
365 | /* | 374 | /* |
366 | * find an ordered extent corresponding to file_offset. return NULL if | 375 | * find an ordered extent corresponding to file_offset. return NULL if |
367 | * nothing is found, otherwise take a reference on the extent and return it | 376 | * nothing is found, otherwise take a reference on the extent and return it |