io_uring: don't assume mm is constant across submits
[linux-2.6-microblaze.git] / lib / raid6 / recov.c
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/export.h>
17 #include <linux/raid/pq.h>
18
19 /* Recover two failed data blocks. */
20 static void raid6_2data_recov_intx1(int disks, size_t bytes, int faila,
21                 int failb, void **ptrs)
22 {
23         u8 *p, *q, *dp, *dq;
24         u8 px, qx, db;
25         const u8 *pbmul;        /* P multiplier table for B data */
26         const u8 *qmul;         /* Q multiplier table (for both) */
27
28         p = (u8 *)ptrs[disks-2];
29         q = (u8 *)ptrs[disks-1];
30
31         /* Compute syndrome with zero for the missing data pages
32            Use the dead data pages as temporary storage for
33            delta p and delta q */
34         dp = (u8 *)ptrs[faila];
35         ptrs[faila] = (void *)raid6_empty_zero_page;
36         ptrs[disks-2] = dp;
37         dq = (u8 *)ptrs[failb];
38         ptrs[failb] = (void *)raid6_empty_zero_page;
39         ptrs[disks-1] = dq;
40
41         raid6_call.gen_syndrome(disks, bytes, ptrs);
42
43         /* Restore pointer table */
44         ptrs[faila]   = dp;
45         ptrs[failb]   = dq;
46         ptrs[disks-2] = p;
47         ptrs[disks-1] = q;
48
49         /* Now, pick the proper data tables */
50         pbmul = raid6_gfmul[raid6_gfexi[failb-faila]];
51         qmul  = raid6_gfmul[raid6_gfinv[raid6_gfexp[faila]^raid6_gfexp[failb]]];
52
53         /* Now do it... */
54         while ( bytes-- ) {
55                 px    = *p ^ *dp;
56                 qx    = qmul[*q ^ *dq];
57                 *dq++ = db = pbmul[px] ^ qx; /* Reconstructed B */
58                 *dp++ = db ^ px; /* Reconstructed A */
59                 p++; q++;
60         }
61 }
62
63 /* Recover failure of one data block plus the P block */
64 static void raid6_datap_recov_intx1(int disks, size_t bytes, int faila,
65                 void **ptrs)
66 {
67         u8 *p, *q, *dq;
68         const u8 *qmul;         /* Q multiplier table */
69
70         p = (u8 *)ptrs[disks-2];
71         q = (u8 *)ptrs[disks-1];
72
73         /* Compute syndrome with zero for the missing data page
74            Use the dead data page as temporary storage for delta q */
75         dq = (u8 *)ptrs[faila];
76         ptrs[faila] = (void *)raid6_empty_zero_page;
77         ptrs[disks-1] = dq;
78
79         raid6_call.gen_syndrome(disks, bytes, ptrs);
80
81         /* Restore pointer table */
82         ptrs[faila]   = dq;
83         ptrs[disks-1] = q;
84
85         /* Now, pick the proper data tables */
86         qmul  = raid6_gfmul[raid6_gfinv[raid6_gfexp[faila]]];
87
88         /* Now do it... */
89         while ( bytes-- ) {
90                 *p++ ^= *dq = qmul[*q ^ *dq];
91                 q++; dq++;
92         }
93 }
94
95
96 const struct raid6_recov_calls raid6_recov_intx1 = {
97         .data2 = raid6_2data_recov_intx1,
98         .datap = raid6_datap_recov_intx1,
99         .valid = NULL,
100         .name = "intx1",
101         .priority = 0,
102 };
103
104 #ifndef __KERNEL__
105 /* Testing only */
106
107 /* Recover two failed blocks. */
108 void raid6_dual_recov(int disks, size_t bytes, int faila, int failb, void **ptrs)
109 {
110         if ( faila > failb ) {
111                 int tmp = faila;
112                 faila = failb;
113                 failb = tmp;
114         }
115
116         if ( failb == disks-1 ) {
117                 if ( faila == disks-2 ) {
118                         /* P+Q failure.  Just rebuild the syndrome. */
119                         raid6_call.gen_syndrome(disks, bytes, ptrs);
120                 } else {
121                         /* data+Q failure.  Reconstruct data from P,
122                            then rebuild syndrome. */
123                         /* NOT IMPLEMENTED - equivalent to RAID-5 */
124                 }
125         } else {
126                 if ( failb == disks-2 ) {
127                         /* data+P failure. */
128                         raid6_datap_recov(disks, bytes, faila, ptrs);
129                 } else {
130                         /* data+data failure. */
131                         raid6_2data_recov(disks, bytes, faila, failb, ptrs);
132                 }
133         }
134 }
135
136 #endif