Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
recov.c
Go to the documentation of this file.
1 /* -*- linux-c -*- ------------------------------------------------------- *
2  *
3  * Copyright 2002 H. Peter Anvin - All Rights Reserved
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
8  * Boston MA 02111-1307, USA; either version 2 of the License, or
9  * (at your option) any later version; incorporated herein by reference.
10  *
11  * ----------------------------------------------------------------------- */
12 
13 /*
14  * raid6/recov.c
15  *
16  * RAID-6 data recovery in dual failure mode. In single failure mode,
17  * use the RAID-5 algorithm (or, in the case of Q failure, just reconstruct
18  * the syndrome.)
19  */
20 
21 #include <linux/export.h>
22 #include <linux/raid/pq.h>
23 
24 /* Recover two failed data blocks. */
25 static void raid6_2data_recov_intx1(int disks, size_t bytes, int faila,
26  int failb, void **ptrs)
27 {
28  u8 *p, *q, *dp, *dq;
29  u8 px, qx, db;
30  const u8 *pbmul; /* P multiplier table for B data */
31  const u8 *qmul; /* Q multiplier table (for both) */
32 
33  p = (u8 *)ptrs[disks-2];
34  q = (u8 *)ptrs[disks-1];
35 
36  /* Compute syndrome with zero for the missing data pages
37  Use the dead data pages as temporary storage for
38  delta p and delta q */
39  dp = (u8 *)ptrs[faila];
40  ptrs[faila] = (void *)raid6_empty_zero_page;
41  ptrs[disks-2] = dp;
42  dq = (u8 *)ptrs[failb];
43  ptrs[failb] = (void *)raid6_empty_zero_page;
44  ptrs[disks-1] = dq;
45 
46  raid6_call.gen_syndrome(disks, bytes, ptrs);
47 
48  /* Restore pointer table */
49  ptrs[faila] = dp;
50  ptrs[failb] = dq;
51  ptrs[disks-2] = p;
52  ptrs[disks-1] = q;
53 
54  /* Now, pick the proper data tables */
55  pbmul = raid6_gfmul[raid6_gfexi[failb-faila]];
56  qmul = raid6_gfmul[raid6_gfinv[raid6_gfexp[faila]^raid6_gfexp[failb]]];
57 
58  /* Now do it... */
59  while ( bytes-- ) {
60  px = *p ^ *dp;
61  qx = qmul[*q ^ *dq];
62  *dq++ = db = pbmul[px] ^ qx; /* Reconstructed B */
63  *dp++ = db ^ px; /* Reconstructed A */
64  p++; q++;
65  }
66 }
67 
68 /* Recover failure of one data block plus the P block */
69 static void raid6_datap_recov_intx1(int disks, size_t bytes, int faila,
70  void **ptrs)
71 {
72  u8 *p, *q, *dq;
73  const u8 *qmul; /* Q multiplier table */
74 
75  p = (u8 *)ptrs[disks-2];
76  q = (u8 *)ptrs[disks-1];
77 
78  /* Compute syndrome with zero for the missing data page
79  Use the dead data page as temporary storage for delta q */
80  dq = (u8 *)ptrs[faila];
81  ptrs[faila] = (void *)raid6_empty_zero_page;
82  ptrs[disks-1] = dq;
83 
84  raid6_call.gen_syndrome(disks, bytes, ptrs);
85 
86  /* Restore pointer table */
87  ptrs[faila] = dq;
88  ptrs[disks-1] = q;
89 
90  /* Now, pick the proper data tables */
91  qmul = raid6_gfmul[raid6_gfinv[raid6_gfexp[faila]]];
92 
93  /* Now do it... */
94  while ( bytes-- ) {
95  *p++ ^= *dq = qmul[*q ^ *dq];
96  q++; dq++;
97  }
98 }
99 
100 
102  .data2 = raid6_2data_recov_intx1,
103  .datap = raid6_datap_recov_intx1,
104  .valid = NULL,
105  .name = "intx1",
106  .priority = 0,
107 };
108 
109 #ifndef __KERNEL__
110 /* Testing only */
111 
112 /* Recover two failed blocks. */
113 void raid6_dual_recov(int disks, size_t bytes, int faila, int failb, void **ptrs)
114 {
115  if ( faila > failb ) {
116  int tmp = faila;
117  faila = failb;
118  failb = tmp;
119  }
120 
121  if ( failb == disks-1 ) {
122  if ( faila == disks-2 ) {
123  /* P+Q failure. Just rebuild the syndrome. */
124  raid6_call.gen_syndrome(disks, bytes, ptrs);
125  } else {
126  /* data+Q failure. Reconstruct data from P,
127  then rebuild syndrome. */
128  /* NOT IMPLEMENTED - equivalent to RAID-5 */
129  }
130  } else {
131  if ( failb == disks-2 ) {
132  /* data+P failure. */
133  raid6_datap_recov(disks, bytes, faila, ptrs);
134  } else {
135  /* data+data failure. */
136  raid6_2data_recov(disks, bytes, faila, failb, ptrs);
137  }
138  }
139 }
140 
141 #endif