1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* -*- linux-c -*- ------------------------------------------------------- * 3 * 4 * Copyright 2002 H. Peter Anvin - All Rights Reserved 5 * 6 * ----------------------------------------------------------------------- */ 7 8 /* 9 * raid6/recov.c 10 * 11 * RAID-6 data recovery in dual failure mode. In single failure mode, 12 * use the RAID-5 algorithm (or, in the case of Q failure, just reconstruct 13 * the syndrome.) 14 */ 15 16 #include <linux/mm.h> 17 #include <linux/raid/pq.h> 18 #include "algos.h" 19 20 /* Recover two failed data blocks. */ 21 static void raid6_2data_recov_intx1(int disks, size_t bytes, int faila, 22 int failb, void **ptrs) 23 { 24 u8 *p, *q, *dp, *dq; 25 u8 px, qx, db; 26 const u8 *pbmul; /* P multiplier table for B data */ 27 const u8 *qmul; /* Q multiplier table (for both) */ 28 29 p = (u8 *)ptrs[disks-2]; 30 q = (u8 *)ptrs[disks-1]; 31 32 /* Compute syndrome with zero for the missing data pages 33 Use the dead data pages as temporary storage for 34 delta p and delta q */ 35 dp = (u8 *)ptrs[faila]; 36 ptrs[faila] = page_address(ZERO_PAGE(0)); 37 ptrs[disks-2] = dp; 38 dq = (u8 *)ptrs[failb]; 39 ptrs[failb] = page_address(ZERO_PAGE(0)); 40 ptrs[disks-1] = dq; 41 42 raid6_gen_syndrome(disks, bytes, ptrs); 43 44 /* Restore pointer table */ 45 ptrs[faila] = dp; 46 ptrs[failb] = dq; 47 ptrs[disks-2] = p; 48 ptrs[disks-1] = q; 49 50 /* Now, pick the proper data tables */ 51 pbmul = raid6_gfmul[raid6_gfexi[failb-faila]]; 52 qmul = raid6_gfmul[raid6_gfinv[raid6_gfexp[faila]^raid6_gfexp[failb]]]; 53 54 /* Now do it... */ 55 while ( bytes-- ) { 56 px = *p ^ *dp; 57 qx = qmul[*q ^ *dq]; 58 *dq++ = db = pbmul[px] ^ qx; /* Reconstructed B */ 59 *dp++ = db ^ px; /* Reconstructed A */ 60 p++; q++; 61 } 62 } 63 64 /* Recover failure of one data block plus the P block */ 65 static void raid6_datap_recov_intx1(int disks, size_t bytes, int faila, 66 void **ptrs) 67 { 68 u8 *p, *q, *dq; 69 const u8 *qmul; /* Q multiplier table */ 70 71 p = (u8 *)ptrs[disks-2]; 72 q = (u8 *)ptrs[disks-1]; 73 74 /* Compute syndrome with zero for the missing data page 75 Use the dead data page as temporary storage for delta q */ 76 dq = (u8 *)ptrs[faila]; 77 ptrs[faila] = page_address(ZERO_PAGE(0)); 78 ptrs[disks-1] = dq; 79 80 raid6_gen_syndrome(disks, bytes, ptrs); 81 82 /* Restore pointer table */ 83 ptrs[faila] = dq; 84 ptrs[disks-1] = q; 85 86 /* Now, pick the proper data tables */ 87 qmul = raid6_gfmul[raid6_gfinv[raid6_gfexp[faila]]]; 88 89 /* Now do it... */ 90 while ( bytes-- ) { 91 *p++ ^= *dq = qmul[*q ^ *dq]; 92 q++; dq++; 93 } 94 } 95 96 97 const struct raid6_recov_calls raid6_recov_intx1 = { 98 .data2 = raid6_2data_recov_intx1, 99 .datap = raid6_datap_recov_intx1, 100 .valid = NULL, 101 .name = "intx1", 102 .priority = 0, 103 }; 104