diff options
Diffstat (limited to 'fs/btrfs/extent_io.c')
-rw-r--r-- | fs/btrfs/extent_io.c | 35 |
1 files changed, 26 insertions, 9 deletions
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 1ff438fd5bc2..eeb75281894e 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c | |||
@@ -3628,6 +3628,13 @@ void wait_on_extent_buffer_writeback(struct extent_buffer *eb) | |||
3628 | TASK_UNINTERRUPTIBLE); | 3628 | TASK_UNINTERRUPTIBLE); |
3629 | } | 3629 | } |
3630 | 3630 | ||
3631 | static void end_extent_buffer_writeback(struct extent_buffer *eb) | ||
3632 | { | ||
3633 | clear_bit(EXTENT_BUFFER_WRITEBACK, &eb->bflags); | ||
3634 | smp_mb__after_atomic(); | ||
3635 | wake_up_bit(&eb->bflags, EXTENT_BUFFER_WRITEBACK); | ||
3636 | } | ||
3637 | |||
3631 | /* | 3638 | /* |
3632 | * Lock eb pages and flush the bio if we can't the locks | 3639 | * Lock eb pages and flush the bio if we can't the locks |
3633 | * | 3640 | * |
@@ -3699,8 +3706,11 @@ static noinline_for_stack int lock_extent_buffer_for_io(struct extent_buffer *eb | |||
3699 | 3706 | ||
3700 | if (!trylock_page(p)) { | 3707 | if (!trylock_page(p)) { |
3701 | if (!flush) { | 3708 | if (!flush) { |
3702 | ret = flush_write_bio(epd); | 3709 | int err; |
3703 | if (ret < 0) { | 3710 | |
3711 | err = flush_write_bio(epd); | ||
3712 | if (err < 0) { | ||
3713 | ret = err; | ||
3704 | failed_page_nr = i; | 3714 | failed_page_nr = i; |
3705 | goto err_unlock; | 3715 | goto err_unlock; |
3706 | } | 3716 | } |
@@ -3715,16 +3725,23 @@ err_unlock: | |||
3715 | /* Unlock already locked pages */ | 3725 | /* Unlock already locked pages */ |
3716 | for (i = 0; i < failed_page_nr; i++) | 3726 | for (i = 0; i < failed_page_nr; i++) |
3717 | unlock_page(eb->pages[i]); | 3727 | unlock_page(eb->pages[i]); |
3728 | /* | ||
3729 | * Clear EXTENT_BUFFER_WRITEBACK and wake up anyone waiting on it. | ||
3730 | * Also set back EXTENT_BUFFER_DIRTY so future attempts to this eb can | ||
3731 | * be made and undo everything done before. | ||
3732 | */ | ||
3733 | btrfs_tree_lock(eb); | ||
3734 | spin_lock(&eb->refs_lock); | ||
3735 | set_bit(EXTENT_BUFFER_DIRTY, &eb->bflags); | ||
3736 | end_extent_buffer_writeback(eb); | ||
3737 | spin_unlock(&eb->refs_lock); | ||
3738 | percpu_counter_add_batch(&fs_info->dirty_metadata_bytes, eb->len, | ||
3739 | fs_info->dirty_metadata_batch); | ||
3740 | btrfs_clear_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN); | ||
3741 | btrfs_tree_unlock(eb); | ||
3718 | return ret; | 3742 | return ret; |
3719 | } | 3743 | } |
3720 | 3744 | ||
3721 | static void end_extent_buffer_writeback(struct extent_buffer *eb) | ||
3722 | { | ||
3723 | clear_bit(EXTENT_BUFFER_WRITEBACK, &eb->bflags); | ||
3724 | smp_mb__after_atomic(); | ||
3725 | wake_up_bit(&eb->bflags, EXTENT_BUFFER_WRITEBACK); | ||
3726 | } | ||
3727 | |||
3728 | static void set_btree_ioerr(struct page *page) | 3745 | static void set_btree_ioerr(struct page *page) |
3729 | { | 3746 | { |
3730 | struct extent_buffer *eb = (struct extent_buffer *)page->private; | 3747 | struct extent_buffer *eb = (struct extent_buffer *)page->private; |