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
)
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
)
119 for (i
= 0; i
< (int) array
->total_devs
- 2; i
++)
125 if ((array
->device
[pos
]) &&
126 (! grub_disk_read (array
->device
[pos
], sector
, 0, size
, buf
)))
128 grub_raid_block_xor (pbuf
, buf
, size
);
129 grub_raid_block_mul (raid6_table2
[i
][i
], buf
, size
);
130 grub_raid_block_xor (qbuf
, buf
, size
);
138 grub_errno
= GRUB_ERR_NONE
;
143 if (pos
== (int) array
->total_devs
)
149 if ((array
->device
[p
]) &&
150 (! grub_disk_read (array
->device
[p
], sector
, 0, size
, buf
)))
152 grub_raid_block_xor (buf
, pbuf
, size
);
156 if (! array
->device
[q
])
158 grub_error (GRUB_ERR_READ_ERROR
, "Not enough disk to restore");
162 grub_errno
= GRUB_ERR_NONE
;
163 if (grub_disk_read (array
->device
[q
], sector
, 0, size
, buf
))
166 grub_raid_block_xor (buf
, qbuf
, size
);
167 grub_raid_block_mul (raid6_table2
[255 - err
[0]][255 - err
[0]], buf
,
174 if ((! array
->device
[p
]) || (! array
->device
[q
]))
176 grub_error (GRUB_ERR_READ_ERROR
, "Not enough disk to restore");
180 if (grub_disk_read (array
->device
[p
], sector
, 0, size
, buf
))
183 grub_raid_block_xor (pbuf
, buf
, size
);
185 if (grub_disk_read (array
->device
[q
], sector
, 0, size
, buf
))
188 grub_raid_block_xor (qbuf
, buf
, size
);
190 c
= raid6_table2
[err
[1]][err
[0]];
191 grub_raid_block_mul (c
, qbuf
, size
);
193 c
= raid6_table1
[raid6_table2
[err
[1]][err
[1]]][c
];
194 grub_raid_block_mul (c
, pbuf
, size
);
196 grub_raid_block_xor (pbuf
, qbuf
, size
);
197 grub_memcpy (buf
, pbuf
, size
);
207 GRUB_MOD_INIT(raid6rec
)
209 grub_raid6_init_table ();
210 grub_raid6_recover_func
= grub_raid6_recover
;
213 GRUB_MOD_FINI(raid6rec
)
215 grub_raid6_recover_func
= 0;