--- /dev/null
+From Alexander.Levin@microsoft.com Mon Jun 18 06:20:01 2018
+From: Sasha Levin <Alexander.Levin@microsoft.com>
+Date: Fri, 15 Jun 2018 02:39:23 +0000
+Subject: Btrfs: make raid6 rebuild retry more
+To: "gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org>
+Cc: "ben.hutchings@codethink.co.uk" <ben.hutchings@codethink.co.uk>, "stable@vger.kernel.org" <stable@vger.kernel.org>, Liu Bo <bo.li.liu@oracle.com>, David Sterba <dsterba@suse.com>, Sasha Levin <Alexander.Levin@microsoft.com>
+Message-ID: <20180615023918.99280-2-alexander.levin@microsoft.com>
+
+From: Liu Bo <bo.li.liu@oracle.com>
+
+[ Upstream commit 8810f7517a3bc4ca2d41d022446d3f5fd6b77c09 ]
+
+There is a scenario that can end up with rebuild process failing to
+return good content, i.e.
+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, and users will think of this as data loss.
+More seriouly, if the loss happens on some important internal btree
+roots, it could refuse to mount.
+
+This extends btrfs to do more retries and each retry fails only one
+stripe. Since raid6 can tolerate 2 disk failures, if there is one
+more failure besides the failure on which we're recovering, this can
+always work.
+
+The worst case is to retry as many times as the number of raid6 disks,
+but given the fact that such a scenario is really rare in practice,
+it's still acceptable.
+
+Signed-off-by: Liu Bo <bo.li.liu@oracle.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <alexander.levin@microsoft.com>
+---
+ fs/btrfs/raid56.c | 18 ++++++++++++++----
+ fs/btrfs/volumes.c | 9 ++++++++-
+ 2 files changed, 22 insertions(+), 5 deletions(-)
+
+--- a/fs/btrfs/raid56.c
++++ b/fs/btrfs/raid56.c
+@@ -2160,11 +2160,21 @@ int raid56_parity_recover(struct btrfs_r
+ }
+
+ /*
+- * reconstruct from the q stripe if they are
+- * asking for mirror 3
++ * Loop retry:
++ * for 'mirror == 2', reconstruct from all other stripes.
++ * for 'mirror_num > 2', select a stripe to fail on every retry.
+ */
+- if (mirror_num == 3)
+- rbio->failb = rbio->real_stripes - 2;
++ if (mirror_num > 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);
+
+--- a/fs/btrfs/volumes.c
++++ b/fs/btrfs/volumes.c
+@@ -5056,7 +5056,14 @@ int btrfs_num_copies(struct btrfs_fs_inf
+ else if (map->type & BTRFS_BLOCK_GROUP_RAID5)
+ ret = 2;
+ 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
+ ret = 1;
+ free_extent_map(em);
--- /dev/null
+From Alexander.Levin@microsoft.com Mon Jun 18 06:19:07 2018
+From: Sasha Levin <Alexander.Levin@microsoft.com>
+Date: Fri, 15 Jun 2018 02:39:22 +0000
+Subject: Revert "Btrfs: fix scrub to repair raid6 corruption"
+To: "gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org>
+Cc: "ben.hutchings@codethink.co.uk" <ben.hutchings@codethink.co.uk>, "stable@vger.kernel.org" <stable@vger.kernel.org>, Sasha Levin <Alexander.Levin@microsoft.com>
+Message-ID: <20180615023918.99280-1-alexander.levin@microsoft.com>
+
+From: Sasha Levin <Alexander.Levin@microsoft.com>
+
+This reverts commit 95b286daf7ba784191023ad110122703eb2ebabc.
+
+This commit used an incorrect log message.
+
+Reported-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Sasha Levin <alexander.levin@microsoft.com>
+---
+ fs/btrfs/raid56.c | 18 ++++--------------
+ fs/btrfs/volumes.c | 9 +--------
+ 2 files changed, 5 insertions(+), 22 deletions(-)
+
+--- a/fs/btrfs/raid56.c
++++ b/fs/btrfs/raid56.c
+@@ -2160,21 +2160,11 @@ int raid56_parity_recover(struct btrfs_r
+ }
+
+ /*
+- * Loop retry:
+- * for 'mirror == 2', reconstruct from all other stripes.
+- * for 'mirror_num > 2', select a stripe to fail on every retry.
++ * reconstruct from the q stripe if they are
++ * asking for mirror 3
+ */
+- if (mirror_num > 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--;
+- }
++ if (mirror_num == 3)
++ rbio->failb = rbio->real_stripes - 2;
+
+ ret = lock_stripe_add(rbio);
+
+--- a/fs/btrfs/volumes.c
++++ b/fs/btrfs/volumes.c
+@@ -5056,14 +5056,7 @@ int btrfs_num_copies(struct btrfs_fs_inf
+ else if (map->type & BTRFS_BLOCK_GROUP_RAID5)
+ ret = 2;
+ else if (map->type & BTRFS_BLOCK_GROUP_RAID6)
+- /*
+- * 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;
++ ret = 3;
+ else
+ ret = 1;
+ free_extent_map(em);