1 /* raid6_recover.c - module to recover from faulty RAID6 arrays. */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2006,2007,2008 Free Software Foundation, Inc.
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
21 #include <grub/disk.h>
24 #include <grub/misc.h>
25 #include <grub/raid.h>
27 static grub_uint8_t raid6_table1
[256][256];
28 static grub_uint8_t raid6_table2
[256][256];
31 grub_raid_block_mul (grub_uint8_t mul
, char *buf
, int size
)
36 p
= (grub_uint8_t
*) buf
;
37 for (i
= 0; i
< size
; i
++, p
++)
38 *p
= raid6_table1
[mul
][*p
];
42 grub_raid6_init_table (void)
46 for (i
= 0; i
< 256; i
++)
47 raid6_table1
[i
][1] = raid6_table1
[1][i
] = i
;
49 for (i
= 2; i
< 256; i
++)
50 for (j
= i
; j
< 256; j
++)
57 c
= raid6_table1
[n
][j
];
58 c
= (c
<< 1) ^ ((c
& 0x80) ? 0x1d : 0);
62 raid6_table1
[j
][i
] = raid6_table1
[i
][j
] = c
;
65 raid6_table2
[0][0] = 1;
66 for (i
= 1; i
< 256; i
++)
67 raid6_table2
[i
][i
] = raid6_table1
[raid6_table2
[i
- 1][i
- 1]][2];
69 for (i
= 0; i
< 254; i
++)
70 for (j
= 0; j
< 254; j
++)
82 c
= n
= raid6_table2
[k
][k
] ^ 1;
83 for (k
= 0; k
< 253; k
++)
84 c
= raid6_table1
[c
][n
];
86 raid6_table2
[i
][j
] = raid6_table1
[raid6_table2
[255 - j
][255 - j
]][c
];
91 grub_raid6_recover (struct grub_raid_array
*array
, int disknr
, int p
,
92 char *buf
, grub_disk_addr_t sector
, int size
)
95 int bad1
= -1, bad2
= -1;
96 char *pbuf
= 0, *qbuf
= 0;
98 size
<<= GRUB_DISK_SECTOR_BITS
;
99 pbuf
= grub_malloc (size
);
103 qbuf
= grub_malloc (size
);
108 if (q
== (int) array
->total_devs
)
111 grub_memset (pbuf
, 0, size
);
112 grub_memset (qbuf
, 0, size
);
115 if (pos
== (int) array
->total_devs
)
118 for (i
= 0; i
< (int) array
->total_devs
- 2; i
++)
124 if ((array
->device
[pos
]) &&
125 (! grub_disk_read (array
->device
[pos
], sector
, 0, size
, buf
)))
127 grub_raid_block_xor (pbuf
, buf
, size
);
128 grub_raid_block_mul (raid6_table2
[i
][i
], buf
, size
);
129 grub_raid_block_xor (qbuf
, buf
, size
);
133 /* Too many bad devices */
138 grub_errno
= GRUB_ERR_NONE
;
143 if (pos
== (int) array
->total_devs
)
147 /* Invalid disknr or p */
154 if ((array
->device
[p
]) &&
155 (! grub_disk_read (array
->device
[p
], sector
, 0, size
, buf
)))
157 grub_raid_block_xor (buf
, pbuf
, size
);
161 if (! array
->device
[q
])
163 grub_error (GRUB_ERR_READ_ERROR
, "Not enough disk to restore");
167 grub_errno
= GRUB_ERR_NONE
;
168 if (grub_disk_read (array
->device
[q
], sector
, 0, size
, buf
))
171 grub_raid_block_xor (buf
, qbuf
, size
);
172 grub_raid_block_mul (raid6_table2
[255 - bad1
][255 - bad1
], buf
,
177 /* Two bad devices */
180 if ((! array
->device
[p
]) || (! array
->device
[q
]))
182 grub_error (GRUB_ERR_READ_ERROR
, "Not enough disk to restore");
186 if (grub_disk_read (array
->device
[p
], sector
, 0, size
, buf
))
189 grub_raid_block_xor (pbuf
, buf
, size
);
191 if (grub_disk_read (array
->device
[q
], sector
, 0, size
, buf
))
194 grub_raid_block_xor (qbuf
, buf
, size
);
196 c
= raid6_table2
[bad2
][bad1
];
197 grub_raid_block_mul (c
, qbuf
, size
);
199 c
= raid6_table1
[raid6_table2
[bad2
][bad2
]][c
];
200 grub_raid_block_mul (c
, pbuf
, size
);
202 grub_raid_block_xor (pbuf
, qbuf
, size
);
203 grub_memcpy (buf
, pbuf
, size
);
213 GRUB_MOD_INIT(raid6rec
)
215 grub_raid6_init_table ();
216 grub_raid6_recover_func
= grub_raid6_recover
;
219 GRUB_MOD_FINI(raid6rec
)
221 grub_raid6_recover_func
= 0;