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)  		       TASK_UNINTERRUPTIBLE);  } +static void end_extent_buffer_writeback(struct extent_buffer *eb) +{ +	clear_bit(EXTENT_BUFFER_WRITEBACK, &eb->bflags); +	smp_mb__after_atomic(); +	wake_up_bit(&eb->bflags, EXTENT_BUFFER_WRITEBACK); +} +  /*   * Lock eb pages and flush the bio if we can't the locks   * @@ -3699,8 +3706,11 @@ static noinline_for_stack int lock_extent_buffer_for_io(struct extent_buffer *eb  		if (!trylock_page(p)) {  			if (!flush) { -				ret = flush_write_bio(epd); -				if (ret < 0) { +				int err; + +				err = flush_write_bio(epd); +				if (err < 0) { +					ret = err;  					failed_page_nr = i;  					goto err_unlock;  				} @@ -3715,16 +3725,23 @@ err_unlock:  	/* Unlock already locked pages */  	for (i = 0; i < failed_page_nr; i++)  		unlock_page(eb->pages[i]); +	/* +	 * Clear EXTENT_BUFFER_WRITEBACK and wake up anyone waiting on it. +	 * Also set back EXTENT_BUFFER_DIRTY so future attempts to this eb can +	 * be made and undo everything done before. +	 */ +	btrfs_tree_lock(eb); +	spin_lock(&eb->refs_lock); +	set_bit(EXTENT_BUFFER_DIRTY, &eb->bflags); +	end_extent_buffer_writeback(eb); +	spin_unlock(&eb->refs_lock); +	percpu_counter_add_batch(&fs_info->dirty_metadata_bytes, eb->len, +				 fs_info->dirty_metadata_batch); +	btrfs_clear_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN); +	btrfs_tree_unlock(eb);  	return ret;  } -static void end_extent_buffer_writeback(struct extent_buffer *eb) -{ -	clear_bit(EXTENT_BUFFER_WRITEBACK, &eb->bflags); -	smp_mb__after_atomic(); -	wake_up_bit(&eb->bflags, EXTENT_BUFFER_WRITEBACK); -} -  static void set_btree_ioerr(struct page *page)  {  	struct extent_buffer *eb = (struct extent_buffer *)page->private;  | 
