Commit d91bb7c6 authored by Liu Bo's avatar Liu Bo Committed by Greg Kroah-Hartman

Btrfs: fix scrub to repair raid6 corruption


[ Upstream commit 762221f0 ]

The raid6 corruption is that,
suppose that all disks can be read without problems and if the content
that was read out doesn't match its checksum, currently for raid6
btrfs at most retries twice,

- the 1st retry is to rebuild with all other stripes, it'll eventually
  be a raid5 xor rebuild,
- if the 1st fails, the 2nd retry will deliberately fail parity p so
  that it will do raid6 style rebuild,

however, the chances are that another non-parity stripe content also
has something corrupted, so that the above retries are not able to
return correct content.

We've fixed normal reads to rebuild raid6 correctly with more retries
in Patch "Btrfs: make raid6 rebuild retry more"[1], this is to fix
scrub to do the exactly same rebuild process.

[1]: https://patchwork.kernel.org/patch/10091755/Signed-off-by: default avatarLiu Bo <bo.li.liu@oracle.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
Signed-off-by: default avatarSasha Levin <alexander.levin@microsoft.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent db6d651e
...@@ -2159,11 +2159,21 @@ int raid56_parity_recover(struct btrfs_fs_info *fs_info, struct bio *bio, ...@@ -2159,11 +2159,21 @@ int raid56_parity_recover(struct btrfs_fs_info *fs_info, struct bio *bio,
} }
/* /*
* reconstruct from the q stripe if they are * Loop retry:
* asking for mirror 3 * for 'mirror == 2', reconstruct from all other stripes.
* for 'mirror_num > 2', select a stripe to fail on every retry.
*/ */
if (mirror_num == 3) if (mirror_num > 2) {
rbio->failb = rbio->real_stripes - 2; /*
* 'mirror == 3' is to fail the p stripe and
* reconstruct from the q stripe. 'mirror > 3' is to
* fail a data stripe and reconstruct from p+q stripe.
*/
rbio->failb = rbio->real_stripes - (mirror_num - 1);
ASSERT(rbio->failb > 0);
if (rbio->failb <= rbio->faila)
rbio->failb--;
}
ret = lock_stripe_add(rbio); ret = lock_stripe_add(rbio);
......
...@@ -5101,7 +5101,14 @@ int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len) ...@@ -5101,7 +5101,14 @@ int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len)
else if (map->type & BTRFS_BLOCK_GROUP_RAID5) else if (map->type & BTRFS_BLOCK_GROUP_RAID5)
ret = 2; ret = 2;
else if (map->type & BTRFS_BLOCK_GROUP_RAID6) else if (map->type & BTRFS_BLOCK_GROUP_RAID6)
ret = 3; /*
* There could be two corrupted data stripes, we need
* to loop retry in order to rebuild the correct data.
*
* Fail a stripe at a time on every retry except the
* stripe under reconstruction.
*/
ret = map->num_stripes;
else else
ret = 1; ret = 1;
free_extent_map(em); free_extent_map(em);
......
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