@@ -269,3 +269,79 @@ int raid6_recov_datap(int nr_devs, size_t stripe_len, int dest1, void **data)
}
return 0;
}
+
+int raid56_recov(int nr_devs, size_t stripe_len, u64 profile, int dest1,
+ int dest2, void **data)
+{
+ int min_devs;
+ int ret;
+
+ if (profile & BTRFS_BLOCK_GROUP_RAID5)
+ min_devs = 2;
+ else if (profile & BTRFS_BLOCK_GROUP_RAID6)
+ min_devs = 3;
+ else
+ return -EINVAL;
+ if (nr_devs < min_devs)
+ return -EINVAL;
+
+ /* Nothing to recover */
+ if (dest1 == -1 && dest2 == -1)
+ return 0;
+
+ /* Reorder dest1/2, so only dest2 can be -1 */
+ if (dest1 == -1) {
+ dest1 = dest2;
+ dest2 = -1;
+ } else if (dest2 != -1 && dest1 != -1) {
+ /* Reorder dest1/2, ensure dest2 > dest1 */
+ if (dest1 > dest2) {
+ int tmp;
+
+ tmp = dest2;
+ dest2 = dest1;
+ dest1 = tmp;
+ }
+ }
+
+ if (profile & BTRFS_BLOCK_GROUP_RAID5) {
+ if (dest2 != -1)
+ return 1;
+ return raid5_gen_result(nr_devs, stripe_len, dest1, data);
+ }
+
+ /* RAID6 one dev corrupted case*/
+ if (dest2 == -1) {
+ /* Regenerate P/Q */
+ if (dest1 == nr_devs - 1 || dest1 == nr_devs - 2) {
+ raid6_gen_syndrome(nr_devs, stripe_len, data);
+ return 0;
+ }
+
+ /* Regerneate data from P */
+ return raid5_gen_result(nr_devs - 1, stripe_len, dest1, data);
+ }
+
+ /* P/Q bot corrupted */
+ if (dest1 == nr_devs - 2 && dest2 == nr_devs - 1) {
+ raid6_gen_syndrome(nr_devs, stripe_len, data);
+ return 0;
+ }
+
+ /* 2 Data corrupted */
+ if (dest2 < nr_devs - 2)
+ return raid6_recov_data2(nr_devs, stripe_len, dest1, dest2,
+ data);
+ /* Data and P*/
+ if (dest2 == nr_devs - 1)
+ return raid6_recov_datap(nr_devs, stripe_len, dest1, data);
+
+ /*
+ * Final case, Data and Q, recover data first then regenerate Q
+ */
+ ret = raid5_gen_result(nr_devs - 1, stripe_len, dest1, data);
+ if (ret < 0)
+ return ret;
+ raid6_gen_syndrome(nr_devs, stripe_len, data);
+ return 0;
+}
@@ -16,6 +16,8 @@
* Boston, MA 021110-1307, USA.
*/
+#include "kerncompat.h"
+
void raid6_gen_syndrome(int disks, size_t bytes, void **ptrs);
int raid5_gen_result(int nr_devs, size_t stripe_len, int dest, void **data);
@@ -26,6 +28,17 @@ int raid6_recov_datap(int nr_devs, size_t stripe_len, int dest1, void **data);
int raid6_recov_data2(int nr_devs, size_t stripe_len, int dest1, int dest2,
void **data);
+/*
+ * Recover raid56 data
+ * @dest1/2 can be -1 to indicate non-corrupted case
+ *
+ * Return >0 for unrecoverable case.
+ * Return 0 for recoverable case. And recovered data will be stored into @data
+ * Return <0 for fatal error
+ */
+int raid56_recov(int nr_devs, size_t stripe_len, u64 profile, int dest1,
+ int dest2, void **data);
+
/* Galois field tables */
extern const u8 raid6_gfmul[256][256] __attribute__((aligned(256)));
extern const u8 raid6_vgfmul[256][32] __attribute__((aligned(256)));
Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com> --- raid56.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ raid56.h | 13 +++++++++++ 2 files changed, 89 insertions(+)