OSDN Git Service

btrfs: extent_io: Handle errors better in extent_write_full_page()
authorQu Wenruo <wqu@suse.com>
Wed, 20 Mar 2019 06:27:42 +0000 (14:27 +0800)
committerDavid Sterba <dsterba@suse.com>
Mon, 29 Apr 2019 17:02:23 +0000 (19:02 +0200)
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: Qu Wenruo <wqu@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/extent_io.c

index 43091b2..9d52f3b 100644 (file)
@@ -170,6 +170,16 @@ static int __must_check submit_one_bio(struct bio *bio, int mirror_num,
        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
  *
@@ -3397,6 +3407,9 @@ done:
  * 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
  * 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,
                              struct extent_page_data *epd)
@@ -3466,6 +3479,7 @@ done:
                end_extent_writepage(page, ret, start, page_end);
        }
        unlock_page(page);
+       ASSERT(ret <= 0);
        return ret;
 
 done_unlocked:
@@ -4007,7 +4021,6 @@ retry:
 int extent_write_full_page(struct page *page, struct writeback_control *wbc)
 {
        int ret;
-       int flush_ret;
        struct extent_page_data epd = {
                .bio = NULL,
                .tree = &BTRFS_I(page->mapping->host)->io_tree,
@@ -4016,9 +4029,14 @@ int extent_write_full_page(struct page *page, struct writeback_control *wbc)
        };
 
        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);
-       BUG_ON(flush_ret < 0);
+       ret = flush_write_bio(&epd);
+       ASSERT(ret <= 0);
        return ret;
 }