On 9.03.20 г. 23:32 ч., Omar Sandoval wrote:
> From: Omar Sandoval <osandov@xxxxxx>
>
> Read repair does two things: it finds a good copy of data to return to
> the reader, and it corrects the bad copy on disk. If a read of multiple
> sectors has an I/O error, repair does an extra "validation" step that
> issues a separate read for each sector. This allows us to find the exact
> failing sectors and only rewrite those.
>
> This heuristic is implemented in
> bio_readpage_error()/btrfs_check_repairable() as:
>
> failed_bio_pages = failed_bio->bi_iter.bi_size >> PAGE_SHIFT;
> if (failed_bio_pages > 1)
> do validation
>
> However, at this point, bi_iter may have already been advanced. This
> means that we'll skip the validation step and rewrite the entire failed
> read.
>
> Fix it by getting the actual size from the biovec (which we can do
> because this is only called for non-cloned bios, although that will
> change in a later commit).
>
> Fixes: 8a2ee44a371c ("btrfs: look at bi_size for repair decisions")
> Signed-off-by: Omar Sandoval <osandov@xxxxxx>
> ---
> fs/btrfs/extent_io.c | 28 ++++++++++++++++++++++------
> fs/btrfs/extent_io.h | 5 +++--
> 2 files changed, 25 insertions(+), 8 deletions(-)
>
> diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
> index 837262d54e28..279731bff0a8 100644
> --- a/fs/btrfs/extent_io.c
> +++ b/fs/btrfs/extent_io.c
> @@ -2528,8 +2528,9 @@ int btrfs_get_io_failure_record(struct inode *inode, u64 start, u64 end,
> return 0;
> }
>
> -bool btrfs_check_repairable(struct inode *inode, unsigned failed_bio_pages,
> - struct io_failure_record *failrec, int failed_mirror)
> +bool btrfs_check_repairable(struct inode *inode, bool need_validation,
nit: While at it this function can be made static. It's only used in
extent_io.c and it's defined before its sole caller - bio_readpage_error.