Commit 3065976b authored by Qu Wenruo's avatar Qu Wenruo Committed by David Sterba

btrfs: extent_io: Handle errors better in extent_write_full_page()

Since now flush_write_bio() could return error, kill the BUG_ON() first.
Then don't call flush_write_bio() unconditionally, instead we check the
return value from __extent_writepage() first.

If __extent_writepage() fails, we do cleanup, and return error without
submitting the possible corrupted or half-baked bio.

If __extent_writepage() successes, then we call flush_write_bio() and
return the result.
Signed-off-by: default avatarQu Wenruo <wqu@suse.com>
Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent f4340622
...@@ -170,6 +170,16 @@ static int __must_check submit_one_bio(struct bio *bio, int mirror_num, ...@@ -170,6 +170,16 @@ static int __must_check submit_one_bio(struct bio *bio, int mirror_num,
return blk_status_to_errno(ret); return blk_status_to_errno(ret);
} }
/* Cleanup unsubmitted bios */
static void end_write_bio(struct extent_page_data *epd, int ret)
{
if (epd->bio) {
epd->bio->bi_status = errno_to_blk_status(ret);
bio_endio(epd->bio);
epd->bio = NULL;
}
}
/* /*
* Submit bio from extent page data via submit_one_bio * Submit bio from extent page data via submit_one_bio
* *
...@@ -3397,6 +3407,9 @@ static noinline_for_stack int __extent_writepage_io(struct inode *inode, ...@@ -3397,6 +3407,9 @@ static noinline_for_stack int __extent_writepage_io(struct inode *inode,
* records are inserted to lock ranges in the tree, and as dirty areas * records are inserted to lock ranges in the tree, and as dirty areas
* are found, they are marked writeback. Then the lock bits are removed * are found, they are marked writeback. Then the lock bits are removed
* and the end_io handler clears the writeback ranges * and the end_io handler clears the writeback ranges
*
* Return 0 if everything goes well.
* Return <0 for error.
*/ */
static int __extent_writepage(struct page *page, struct writeback_control *wbc, static int __extent_writepage(struct page *page, struct writeback_control *wbc,
struct extent_page_data *epd) struct extent_page_data *epd)
...@@ -3466,6 +3479,7 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc, ...@@ -3466,6 +3479,7 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
end_extent_writepage(page, ret, start, page_end); end_extent_writepage(page, ret, start, page_end);
} }
unlock_page(page); unlock_page(page);
ASSERT(ret <= 0);
return ret; return ret;
done_unlocked: done_unlocked:
...@@ -4007,7 +4021,6 @@ static int extent_write_cache_pages(struct address_space *mapping, ...@@ -4007,7 +4021,6 @@ static int extent_write_cache_pages(struct address_space *mapping,
int extent_write_full_page(struct page *page, struct writeback_control *wbc) int extent_write_full_page(struct page *page, struct writeback_control *wbc)
{ {
int ret; int ret;
int flush_ret;
struct extent_page_data epd = { struct extent_page_data epd = {
.bio = NULL, .bio = NULL,
.tree = &BTRFS_I(page->mapping->host)->io_tree, .tree = &BTRFS_I(page->mapping->host)->io_tree,
...@@ -4016,9 +4029,14 @@ int extent_write_full_page(struct page *page, struct writeback_control *wbc) ...@@ -4016,9 +4029,14 @@ int extent_write_full_page(struct page *page, struct writeback_control *wbc)
}; };
ret = __extent_writepage(page, wbc, &epd); ret = __extent_writepage(page, wbc, &epd);
ASSERT(ret <= 0);
if (ret < 0) {
end_write_bio(&epd, ret);
return ret;
}
flush_ret = flush_write_bio(&epd); ret = flush_write_bio(&epd);
BUG_ON(flush_ret < 0); ASSERT(ret <= 0);
return ret; return ret;
} }
......
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