Btrfs: tolerate errors if we have retried successfully
authorLiu Bo <bo.li.liu@oracle.com>
Wed, 17 May 2017 21:42:00 +0000 (15:42 -0600)
committerDavid Sterba <dsterba@suse.com>
Mon, 19 Jun 2017 16:26:03 +0000 (18:26 +0200)
With raid1 profile, dio read isn't tolerating IO errors if read length is
less than the stripe length (64K).

Our bio didn't get split in btrfs_submit_direct_hook() if (dip->flags &
BTRFS_DIO_ORIG_BIO_SUBMITTED) is true and that happens when the read
length is less than 64k.  In this case, if the underlying device returns
error somehow, bio->bi_error has recorded that error.

If we could recover the correct data from another copy in profile raid1/10/5/6,
with btrfs_subio_endio_read() returning 0, bio would have the correct data in
its vector, but bio->bi_error is not updated accordingly so that the following
dio_end_io(dio_bio, bio->bi_error) makes directIO think this read has failed.

This fixes the problem by setting bio's error to 0 if a good copy has been
found.

Signed-off-by: Liu Bo <bo.li.liu@oracle.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/inode.c

index 96bbc836d0710b61325657892fd3165bc6e4073d..147bafdb862896d7c91404f22926221d8dcb8aa3 100644 (file)
@@ -8261,8 +8261,11 @@ static void btrfs_endio_direct_read(struct bio *bio)
        struct btrfs_io_bio *io_bio = btrfs_io_bio(bio);
        int err = bio->bi_error;
 
-       if (dip->flags & BTRFS_DIO_ORIG_BIO_SUBMITTED)
+       if (dip->flags & BTRFS_DIO_ORIG_BIO_SUBMITTED) {
                err = btrfs_subio_endio_read(inode, io_bio, err);
+               if (!err)
+                       bio->bi_error = 0;
+       }
 
        unlock_extent(&BTRFS_I(inode)->io_tree, dip->logical_offset,
                      dip->logical_offset + dip->bytes - 1);