2 * raid6check - extended consistency check for RAID-6
4 * Copyright (C) 2011 Piergiorgio Sartor
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * Author: Piergiorgio Sartor
22 * Based on "restripe.c" from "mdadm" codebase
28 int geo_map(int block, unsigned long long stripe, int raid_disks,
29 int level, int layout);
30 void qsyndrome(uint8_t *p, uint8_t *q, uint8_t **sources, int disks, int size);
31 void make_tables(void);
33 /* Collect per stripe consistency information */
34 void raid6_collect(int chunk_size, uint8_t *p, uint8_t *q,
35 char *chunkP, char *chunkQ, int *results)
40 extern uint8_t raid6_gflog[];
42 for(i = 0; i < chunk_size; i++) {
43 Px = (uint8_t)chunkP[i] ^ (uint8_t)p[i];
44 Qx = (uint8_t)chunkQ[i] ^ (uint8_t)q[i];
46 if((Px != 0) && (Qx == 0))
49 if((Px == 0) && (Qx != 0))
52 if((Px != 0) && (Qx != 0)) {
53 data_id = (raid6_gflog[Qx] - raid6_gflog[Px]);
54 if(data_id < 0) data_id += 255;
58 if((Px == 0) && (Qx == 0))
63 /* Try to find out if a specific disk has problems */
64 int raid6_stats(int *results, int raid_disks, int chunk_size)
67 int curr_broken_disk = -255;
68 int prev_broken_disk = -255;
69 int broken_status = 0;
71 for(i = 0; i < chunk_size; i++) {
73 if(results[i] != -255)
74 curr_broken_disk = results[i];
76 if(curr_broken_disk >= raid_disks)
79 switch(broken_status) {
81 if(curr_broken_disk != -255) {
82 prev_broken_disk = curr_broken_disk;
88 if(curr_broken_disk != prev_broken_disk)
94 curr_broken_disk = prev_broken_disk = -65535;
99 return curr_broken_disk;
102 int check_stripes(int *source, unsigned long long *offsets,
103 int raid_disks, int chunk_size, int level, int layout,
104 unsigned long long start, unsigned long long length, char *name[])
106 /* read the data and p and q blocks, and check we got them right */
107 char *stripe_buf = malloc(raid_disks * chunk_size);
108 char **stripes = malloc(raid_disks * sizeof(char*));
109 char **blocks = malloc(raid_disks * sizeof(char*));
110 uint8_t *p = malloc(chunk_size);
111 uint8_t *q = malloc(chunk_size);
112 int *results = malloc(chunk_size * sizeof(int));
116 int data_disks = raid_disks - 2;
118 extern int tables_ready;
123 for ( i = 0 ; i < raid_disks ; i++)
124 stripes[i] = stripe_buf + i * chunk_size;
129 for (i = 0 ; i < raid_disks ; i++) {
130 lseek64(source[i], offsets[i]+start, 0);
131 read(source[i], stripes[i], chunk_size);
133 for (i = 0 ; i < data_disks ; i++) {
134 int disk = geo_map(i, start/chunk_size, raid_disks,
136 blocks[i] = stripes[disk];
137 printf("%d->%d\n", i, disk);
140 qsyndrome(p, q, (uint8_t**)blocks, data_disks, chunk_size);
141 diskP = geo_map(-1, start/chunk_size, raid_disks,
143 if (memcmp(p, stripes[diskP], chunk_size) != 0) {
144 printf("P(%d) wrong at %llu\n", diskP,
147 diskQ = geo_map(-2, start/chunk_size, raid_disks,
149 if (memcmp(q, stripes[diskQ], chunk_size) != 0) {
150 printf("Q(%d) wrong at %llu\n", diskQ,
153 raid6_collect(chunk_size, p, q,
154 stripes[diskP], stripes[diskQ], results);
155 disk = raid6_stats(results, raid_disks, chunk_size);
158 disk = geo_map(disk, start/chunk_size, raid_disks,
162 printf("Possible failed disk: %d --> %s\n", disk, name[disk]);
165 printf("Failure detected, but disk unknown\n");
168 length -= chunk_size;
182 unsigned long long getnum(char *str, char **err)
185 unsigned long long rv = strtoull(str, &e, 10);
193 int main(int argc, char *argv[])
195 /* raid_disks chunk_size layout start length devices...
199 unsigned long long *offsets;
200 int raid_disks, chunk_size, layout;
202 unsigned long long start, length;
207 fprintf(stderr, "Usage: raid6check raid_disks"
208 " chunk_size layout start length devices...\n");
212 raid_disks = getnum(argv[1], &err);
213 chunk_size = getnum(argv[2], &err);
214 layout = getnum(argv[3], &err);
215 start = getnum(argv[4], &err);
216 length = getnum(argv[5], &err);
218 fprintf(stderr, "test_stripe: Bad number: %s\n", err);
221 if (argc != raid_disks + 6) {
222 fprintf(stderr, "test_stripe: wrong number of devices: want %d found %d\n",
226 fds = malloc(raid_disks * sizeof(*fds));
227 offsets = malloc(raid_disks * sizeof(*offsets));
228 memset(offsets, 0, raid_disks * sizeof(*offsets));
230 for (i=0; i<raid_disks; i++) {
232 p = strchr(argv[6+i], ':');
236 offsets[i] = atoll(p) * 512;
238 fds[i] = open(argv[6+i], O_RDWR);
241 fprintf(stderr,"test_stripe: cannot open %s.\n", argv[6+i]);
246 buf = malloc(raid_disks * chunk_size);
248 int rv = check_stripes(fds, offsets,
249 raid_disks, chunk_size, level, layout,
250 start, length, &argv[6]);
253 "test_stripe: test_stripes returned %d\n", rv);