diff options
Diffstat (limited to 'fs/btrfs/ordered-data.c')
-rw-r--r-- | fs/btrfs/ordered-data.c | 49 |
1 files changed, 22 insertions, 27 deletions
diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c index ac734ec4cc20..534544e08f76 100644 --- a/fs/btrfs/ordered-data.c +++ b/fs/btrfs/ordered-data.c | |||
@@ -220,6 +220,7 @@ static int __btrfs_add_ordered_extent(struct inode *inode, u64 file_offset, | |||
220 | INIT_LIST_HEAD(&entry->work_list); | 220 | INIT_LIST_HEAD(&entry->work_list); |
221 | init_completion(&entry->completion); | 221 | init_completion(&entry->completion); |
222 | INIT_LIST_HEAD(&entry->log_list); | 222 | INIT_LIST_HEAD(&entry->log_list); |
223 | INIT_LIST_HEAD(&entry->trans_list); | ||
223 | 224 | ||
224 | trace_btrfs_ordered_extent_add(inode, entry); | 225 | trace_btrfs_ordered_extent_add(inode, entry); |
225 | 226 | ||
@@ -431,19 +432,31 @@ out: | |||
431 | 432 | ||
432 | /* Needs to either be called under a log transaction or the log_mutex */ | 433 | /* Needs to either be called under a log transaction or the log_mutex */ |
433 | void btrfs_get_logged_extents(struct inode *inode, | 434 | void btrfs_get_logged_extents(struct inode *inode, |
434 | struct list_head *logged_list) | 435 | struct list_head *logged_list, |
436 | const loff_t start, | ||
437 | const loff_t end) | ||
435 | { | 438 | { |
436 | struct btrfs_ordered_inode_tree *tree; | 439 | struct btrfs_ordered_inode_tree *tree; |
437 | struct btrfs_ordered_extent *ordered; | 440 | struct btrfs_ordered_extent *ordered; |
438 | struct rb_node *n; | 441 | struct rb_node *n; |
442 | struct rb_node *prev; | ||
439 | 443 | ||
440 | tree = &BTRFS_I(inode)->ordered_tree; | 444 | tree = &BTRFS_I(inode)->ordered_tree; |
441 | spin_lock_irq(&tree->lock); | 445 | spin_lock_irq(&tree->lock); |
442 | for (n = rb_first(&tree->tree); n; n = rb_next(n)) { | 446 | n = __tree_search(&tree->tree, end, &prev); |
447 | if (!n) | ||
448 | n = prev; | ||
449 | for (; n; n = rb_prev(n)) { | ||
443 | ordered = rb_entry(n, struct btrfs_ordered_extent, rb_node); | 450 | ordered = rb_entry(n, struct btrfs_ordered_extent, rb_node); |
451 | if (ordered->file_offset > end) | ||
452 | continue; | ||
453 | if (entry_end(ordered) <= start) | ||
454 | break; | ||
444 | if (!list_empty(&ordered->log_list)) | 455 | if (!list_empty(&ordered->log_list)) |
445 | continue; | 456 | continue; |
446 | list_add_tail(&ordered->log_list, logged_list); | 457 | if (test_bit(BTRFS_ORDERED_LOGGED, &ordered->flags)) |
458 | continue; | ||
459 | list_add(&ordered->log_list, logged_list); | ||
447 | atomic_inc(&ordered->refs); | 460 | atomic_inc(&ordered->refs); |
448 | } | 461 | } |
449 | spin_unlock_irq(&tree->lock); | 462 | spin_unlock_irq(&tree->lock); |
@@ -472,7 +485,8 @@ void btrfs_submit_logged_extents(struct list_head *logged_list, | |||
472 | spin_unlock_irq(&log->log_extents_lock[index]); | 485 | spin_unlock_irq(&log->log_extents_lock[index]); |
473 | } | 486 | } |
474 | 487 | ||
475 | void btrfs_wait_logged_extents(struct btrfs_root *log, u64 transid) | 488 | void btrfs_wait_logged_extents(struct btrfs_trans_handle *trans, |
489 | struct btrfs_root *log, u64 transid) | ||
476 | { | 490 | { |
477 | struct btrfs_ordered_extent *ordered; | 491 | struct btrfs_ordered_extent *ordered; |
478 | int index = transid % 2; | 492 | int index = transid % 2; |
@@ -497,7 +511,8 @@ void btrfs_wait_logged_extents(struct btrfs_root *log, u64 transid) | |||
497 | wait_event(ordered->wait, test_bit(BTRFS_ORDERED_IO_DONE, | 511 | wait_event(ordered->wait, test_bit(BTRFS_ORDERED_IO_DONE, |
498 | &ordered->flags)); | 512 | &ordered->flags)); |
499 | 513 | ||
500 | btrfs_put_ordered_extent(ordered); | 514 | if (!test_and_set_bit(BTRFS_ORDERED_LOGGED, &ordered->flags)) |
515 | list_add_tail(&ordered->trans_list, &trans->ordered); | ||
501 | spin_lock_irq(&log->log_extents_lock[index]); | 516 | spin_lock_irq(&log->log_extents_lock[index]); |
502 | } | 517 | } |
503 | spin_unlock_irq(&log->log_extents_lock[index]); | 518 | spin_unlock_irq(&log->log_extents_lock[index]); |
@@ -725,30 +740,10 @@ int btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len) | |||
725 | /* start IO across the range first to instantiate any delalloc | 740 | /* start IO across the range first to instantiate any delalloc |
726 | * extents | 741 | * extents |
727 | */ | 742 | */ |
728 | ret = filemap_fdatawrite_range(inode->i_mapping, start, orig_end); | 743 | ret = btrfs_fdatawrite_range(inode, start, orig_end); |
729 | if (ret) | 744 | if (ret) |
730 | return ret; | 745 | return ret; |
731 | /* | 746 | |
732 | * So with compression we will find and lock a dirty page and clear the | ||
733 | * first one as dirty, setup an async extent, and immediately return | ||
734 | * with the entire range locked but with nobody actually marked with | ||
735 | * writeback. So we can't just filemap_write_and_wait_range() and | ||
736 | * expect it to work since it will just kick off a thread to do the | ||
737 | * actual work. So we need to call filemap_fdatawrite_range _again_ | ||
738 | * since it will wait on the page lock, which won't be unlocked until | ||
739 | * after the pages have been marked as writeback and so we're good to go | ||
740 | * from there. We have to do this otherwise we'll miss the ordered | ||
741 | * extents and that results in badness. Please Josef, do not think you | ||
742 | * know better and pull this out at some point in the future, it is | ||
743 | * right and you are wrong. | ||
744 | */ | ||
745 | if (test_bit(BTRFS_INODE_HAS_ASYNC_EXTENT, | ||
746 | &BTRFS_I(inode)->runtime_flags)) { | ||
747 | ret = filemap_fdatawrite_range(inode->i_mapping, start, | ||
748 | orig_end); | ||
749 | if (ret) | ||
750 | return ret; | ||
751 | } | ||
752 | ret = filemap_fdatawait_range(inode->i_mapping, start, orig_end); | 747 | ret = filemap_fdatawait_range(inode->i_mapping, start, orig_end); |
753 | if (ret) | 748 | if (ret) |
754 | return ret; | 749 | return ret; |