]> git.ipfire.org Git - thirdparty/mdadm.git/blame - restripe.c
Add gpt pseudo-metadata
[thirdparty/mdadm.git] / restripe.c
CommitLineData
e86c9dd6
NB
1/*
2 * mdadm - manage Linux "md" devices aka RAID arrays.
3 *
e736b623 4 * Copyright (C) 2006-2009 Neil Brown <neilb@suse.de>
e86c9dd6
NB
5 *
6 *
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.
11 *
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.
16 *
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
20 *
21 * Author: Neil Brown
22 * Email: <neilb@suse.de>
23 */
24
25#include "mdadm.h"
a6288483 26#include <stdint.h>
e86c9dd6
NB
27
28/* To restripe, we read from old geometry to a buffer, and
29 * read from buffer to new geometry.
a6288483
N
30 * When reading, we might have missing devices and so could need
31 * to reconstruct.
32 * When writing, we need to create correct parity and Q.
e86c9dd6
NB
33 *
34 */
35
e0d95aac
N
36static int geo_map(int block, unsigned long long stripe, int raid_disks,
37 int level, int layout)
e86c9dd6 38{
48327135 39 /* On the given stripe, find which disk in the array will have
e86c9dd6 40 * block numbered 'block'.
48327135
NB
41 * '-1' means the parity block.
42 * '-2' means the Q syndrome.
e86c9dd6
NB
43 */
44 int pd;
45
46 switch(level*100 + layout) {
47 case 000:
48 case 400:
e0d95aac 49 case 500 + ALGORITHM_PARITY_N:
e86c9dd6
NB
50 /* raid 4 isn't messed around by parity blocks */
51 if (block == -1)
52 return raid_disks-1; /* parity block */
53 return block;
54 case 500 + ALGORITHM_LEFT_ASYMMETRIC:
55 pd = (raid_disks-1) - stripe % raid_disks;
56 if (block == -1) return pd;
57 if (block >= pd)
58 block++;
59 return block;
60
61 case 500 + ALGORITHM_RIGHT_ASYMMETRIC:
62 pd = stripe % raid_disks;
63 if (block == -1) return pd;
64 if (block >= pd)
65 block++;
66 return block;
67
68 case 500 + ALGORITHM_LEFT_SYMMETRIC:
69 pd = (raid_disks - 1) - stripe % raid_disks;
70 if (block == -1) return pd;
71 return (pd + 1 + block) % raid_disks;
72
73 case 500 + ALGORITHM_RIGHT_SYMMETRIC:
74 pd = stripe % raid_disks;
75 if (block == -1) return pd;
76 return (pd + 1 + block) % raid_disks;
77
e0d95aac
N
78 case 500 + ALGORITHM_PARITY_0:
79 return block + 1;
80
81
82 case 600 + ALGORITHM_PARITY_N_6:
83 if (block == -2)
84 return raid_disks - 1;
85 if (block == -1)
86 return raid_disks - 2; /* parity block */
87 return block;
88 case 600 + ALGORITHM_LEFT_ASYMMETRIC_6:
89 if (block == -2)
90 return raid_disks - 1;
91 raid_disks--;
92 pd = (raid_disks-1) - stripe % raid_disks;
93 if (block == -1) return pd;
94 if (block >= pd)
95 block++;
96 return block;
97
98 case 600 + ALGORITHM_RIGHT_ASYMMETRIC_6:
99 if (block == -2)
100 return raid_disks - 1;
101 raid_disks--;
102 pd = stripe % raid_disks;
103 if (block == -1) return pd;
104 if (block >= pd)
105 block++;
106 return block;
107
108 case 600 + ALGORITHM_LEFT_SYMMETRIC_6:
109 if (block == -2)
110 return raid_disks - 1;
111 raid_disks--;
112 pd = (raid_disks - 1) - stripe % raid_disks;
113 if (block == -1) return pd;
114 return (pd + 1 + block) % raid_disks;
115
116 case 600 + ALGORITHM_RIGHT_SYMMETRIC_6:
117 if (block == -2)
118 return raid_disks - 1;
119 raid_disks--;
120 pd = stripe % raid_disks;
121 if (block == -1) return pd;
122 return (pd + 1 + block) % raid_disks;
123
124 case 600 + ALGORITHM_PARITY_0_6:
125 if (block == -2)
126 return raid_disks - 1;
127 return block + 1;
128
129
130 case 600 + ALGORITHM_PARITY_0:
131 if (block == -1)
132 return 0;
133 if (block == -2)
134 return 1;
135 return block + 2;
136
e86c9dd6
NB
137 case 600 + ALGORITHM_LEFT_ASYMMETRIC:
138 pd = raid_disks - 1 - (stripe % raid_disks);
139 if (block == -1) return pd;
48327135 140 if (block == -2) return (pd+1) % raid_disks;
e86c9dd6
NB
141 if (pd == raid_disks - 1)
142 return block+1;
143 if (block >= pd)
144 return block+2;
145 return block;
146
e0d95aac
N
147 case 600 + ALGORITHM_ROTATING_ZERO_RESTART:
148 /* Different order for calculating Q, otherwize same as ... */
e86c9dd6
NB
149 case 600 + ALGORITHM_RIGHT_ASYMMETRIC:
150 pd = stripe % raid_disks;
151 if (block == -1) return pd;
48327135 152 if (block == -2) return (pd+1) % raid_disks;
e86c9dd6
NB
153 if (pd == raid_disks - 1)
154 return block+1;
155 if (block >= pd)
156 return block+2;
157 return block;
158
159 case 600 + ALGORITHM_LEFT_SYMMETRIC:
160 pd = raid_disks - 1 - (stripe % raid_disks);
161 if (block == -1) return pd;
48327135 162 if (block == -2) return (pd+1) % raid_disks;
e86c9dd6
NB
163 return (pd + 2 + block) % raid_disks;
164
165 case 600 + ALGORITHM_RIGHT_SYMMETRIC:
166 pd = stripe % raid_disks;
167 if (block == -1) return pd;
48327135 168 if (block == -2) return (pd+1) % raid_disks;
e86c9dd6 169 return (pd + 2 + block) % raid_disks;
e0d95aac
N
170
171
172 case 600 + ALGORITHM_ROTATING_N_RESTART:
173 /* Same a left_asymmetric, by first stripe is
174 * D D D P Q rather than
175 * Q D D D P
176 */
177 pd = raid_disks - 1 - ((stripe + 1) % raid_disks);
178 if (block == -1) return pd;
179 if (block == -2) return (pd+1) % raid_disks;
180 if (pd == raid_disks - 1)
181 return block+1;
182 if (block >= pd)
183 return block+2;
184 return block;
185
186 case 600 + ALGORITHM_ROTATING_N_CONTINUE:
187 /* Same as left_symmetric but Q is before P */
188 pd = raid_disks - 1 - (stripe % raid_disks);
189 if (block == -1) return pd;
190 if (block == -2) return (pd+raid_disks-1) % raid_disks;
191 return (pd + 1 + block) % raid_disks;
e86c9dd6
NB
192 }
193 return -1;
194}
e0d95aac
N
195static int is_ddf(int layout)
196{
197 switch (layout)
198 {
199 default:
200 return 0;
201 case ALGORITHM_ROTATING_N_CONTINUE:
202 case ALGORITHM_ROTATING_N_RESTART:
203 case ALGORITHM_ROTATING_ZERO_RESTART:
204 return 1;
205 }
206}
e86c9dd6
NB
207
208
209static void xor_blocks(char *target, char **sources, int disks, int size)
210{
211 int i, j;
212 /* Amazingly inefficient... */
213 for (i=0; i<size; i++) {
214 char c = 0;
215 for (j=0 ; j<disks; j++)
216 c ^= sources[j][i];
217 target[i] = c;
218 }
219}
220
a6288483 221static void qsyndrome(uint8_t *p, uint8_t *q, uint8_t **sources, int disks, int size)
48327135
NB
222{
223 int d, z;
a6288483 224 uint8_t wq0, wp0, wd0, w10, w20;
48327135
NB
225 for ( d = 0; d < size; d++) {
226 wq0 = wp0 = sources[disks-1][d];
227 for ( z = disks-2 ; z >= 0 ; z-- ) {
228 wd0 = sources[z][d];
229 wp0 ^= wd0;
230 w20 = (wq0&0x80) ? 0xff : 0x00;
231 w10 = (wq0 << 1) & 0xff;
232 w20 &= 0x1d;
233 w10 ^= w20;
234 wq0 = w10 ^ wd0;
235 }
236 p[d] = wp0;
237 q[d] = wq0;
238 }
239}
240
a6288483
N
241
242/*
243 * The following was taken from linux/drivers/md/mktables.c, and modified
244 * to create in-memory tables rather than C code
245 */
246static uint8_t gfmul(uint8_t a, uint8_t b)
247{
248 uint8_t v = 0;
249
250 while (b) {
251 if (b & 1)
252 v ^= a;
253 a = (a << 1) ^ (a & 0x80 ? 0x1d : 0);
254 b >>= 1;
255 }
256
257 return v;
258}
259
260static uint8_t gfpow(uint8_t a, int b)
261{
262 uint8_t v = 1;
263
264 b %= 255;
265 if (b < 0)
266 b += 255;
267
268 while (b) {
269 if (b & 1)
270 v = gfmul(v, a);
271 a = gfmul(a, a);
272 b >>= 1;
273 }
274
275 return v;
276}
277
278int tables_ready = 0;
279uint8_t raid6_gfmul[256][256];
280uint8_t raid6_gfexp[256];
281uint8_t raid6_gfinv[256];
282uint8_t raid6_gfexi[256];
283void make_tables(void)
284{
285 int i, j;
286 uint8_t v;
287
288 /* Compute multiplication table */
289 for (i = 0; i < 256; i++)
290 for (j = 0; j < 256; j++)
291 raid6_gfmul[i][j] = gfmul(i, j);
292
293 /* Compute power-of-2 table (exponent) */
294 v = 1;
295 for (i = 0; i < 256; i++) {
296 raid6_gfexp[i] = v;
297 v = gfmul(v, 2);
298 if (v == 1)
299 v = 0; /* For entry 255, not a real entry */
300 }
301
302 /* Compute inverse table x^-1 == x^254 */
303 for (i = 0; i < 256; i++)
304 raid6_gfinv[i] = gfpow(i, 254);
305
306 /* Compute inv(2^x + 1) (exponent-xor-inverse) table */
307 for (i = 0; i < 256; i ++)
308 raid6_gfexi[i] = raid6_gfinv[raid6_gfexp[i] ^ 1];
309
310 tables_ready = 1;
311}
312
313uint8_t *zero;
314/* Following was taken from linux/drivers/md/raid6recov.c */
315
316/* Recover two failed data blocks. */
317void raid6_2data_recov(int disks, size_t bytes, int faila, int failb,
318 uint8_t **ptrs)
319{
320 uint8_t *p, *q, *dp, *dq;
321 uint8_t px, qx, db;
322 const uint8_t *pbmul; /* P multiplier table for B data */
323 const uint8_t *qmul; /* Q multiplier table (for both) */
324
325 p = ptrs[disks-2];
326 q = ptrs[disks-1];
327
328 /* Compute syndrome with zero for the missing data pages
329 Use the dead data pages as temporary storage for
330 delta p and delta q */
331 dp = ptrs[faila];
332 ptrs[faila] = zero;
333 dq = ptrs[failb];
334 ptrs[failb] = zero;
335
336 qsyndrome(dp, dq, ptrs, disks-2, bytes);
337
338 /* Restore pointer table */
339 ptrs[faila] = dp;
340 ptrs[failb] = dq;
341
342 /* Now, pick the proper data tables */
343 pbmul = raid6_gfmul[raid6_gfexi[failb-faila]];
344 qmul = raid6_gfmul[raid6_gfinv[raid6_gfexp[faila]^raid6_gfexp[failb]]];
345
346 /* Now do it... */
347 while ( bytes-- ) {
348 px = *p ^ *dp;
349 qx = qmul[*q ^ *dq];
350 *dq++ = db = pbmul[px] ^ qx; /* Reconstructed B */
351 *dp++ = db ^ px; /* Reconstructed A */
352 p++; q++;
353 }
354}
355
356/* Recover failure of one data block plus the P block */
357void raid6_datap_recov(int disks, size_t bytes, int faila, uint8_t **ptrs)
358{
359 uint8_t *p, *q, *dq;
360 const uint8_t *qmul; /* Q multiplier table */
361
362 p = ptrs[disks-2];
363 q = ptrs[disks-1];
364
365 /* Compute syndrome with zero for the missing data page
366 Use the dead data page as temporary storage for delta q */
367 dq = ptrs[faila];
368 ptrs[faila] = zero;
369
370 qsyndrome(p, dq, ptrs, disks-2, bytes);
371
372 /* Restore pointer table */
373 ptrs[faila] = dq;
374
375 /* Now, pick the proper data tables */
376 qmul = raid6_gfmul[raid6_gfinv[raid6_gfexp[faila]]];
377
378 /* Now do it... */
379 while ( bytes-- ) {
380 *p++ ^= *dq = qmul[*q ^ *dq];
381 q++; dq++;
382 }
383}
384
e86c9dd6
NB
385/* Save data:
386 * We are given:
a6288483 387 * A list of 'fds' of the active disks. Some may be absent.
48327135 388 * A geometry: raid_disks, chunk_size, level, layout
e86c9dd6
NB
389 * A list of 'fds' for mirrored targets. They are already seeked to
390 * right (Write) location
a6288483
N
391 * A start and length which must be stripe-aligned
392 * 'buf' is large enough to hold one stripe, and is aligned
e86c9dd6
NB
393 */
394
395int save_stripes(int *source, unsigned long long *offsets,
396 int raid_disks, int chunk_size, int level, int layout,
397 int nwrites, int *dest,
a6288483
N
398 unsigned long long start, unsigned long long length,
399 char *buf)
e86c9dd6 400{
e86c9dd6
NB
401 int len;
402 int data_disks = raid_disks - (level == 0 ? 0 : level <=5 ? 1 : 2);
403 int disk;
a6288483 404 int i;
e86c9dd6 405
a6288483
N
406 if (!tables_ready)
407 make_tables();
408
409 if (zero == NULL) {
410 zero = malloc(chunk_size);
411 memset(zero, 0, chunk_size);
412 }
413
414 len = data_disks * chunk_size;
e86c9dd6 415 while (length > 0) {
a6288483
N
416 int failed = 0;
417 int fdisk[3], fblock[3];
418 for (disk = 0; disk < raid_disks ; disk++) {
419 unsigned long long offset;
420 int dnum;
a6288483
N
421
422 offset = (start/chunk_size/data_disks)*chunk_size;
423 dnum = geo_map(disk < data_disks ? disk : data_disks - disk - 1,
424 start/chunk_size/data_disks,
425 raid_disks, level, layout);
7236ee7a 426 if (dnum < 0) abort();
a6288483 427 if (source[dnum] < 0 ||
cc50ccdc 428 lseek64(source[dnum], offsets[dnum]+offset, 0) < 0 ||
7236ee7a
N
429 read(source[dnum], buf+disk * chunk_size, chunk_size)
430 != chunk_size)
a6288483
N
431 if (failed <= 2) {
432 fdisk[failed] = dnum;
433 fblock[failed] = disk;
434 failed++;
435 }
436 }
437 if (failed == 0 || fblock[0] >= data_disks)
438 /* all data disks are good */
439 ;
440 else if (failed == 1 || fblock[1] >= data_disks+1) {
441 /* one failed data disk and good parity */
442 char *bufs[data_disks];
443 for (i=0; i < data_disks; i++)
444 if (fblock[0] == i)
445 bufs[i] = buf + data_disks*chunk_size;
446 else
447 bufs[i] = buf + i*chunk_size;
448
449 xor_blocks(buf + fblock[0]*chunk_size,
450 bufs, data_disks, chunk_size);
451 } else if (failed > 2 || level != 6)
452 /* too much failure */
e86c9dd6 453 return -1;
a6288483
N
454 else {
455 /* RAID6 computations needed. */
456 uint8_t *bufs[data_disks+4];
457 int qdisk;
458 int syndrome_disks;
459 disk = geo_map(-1, start/chunk_size/data_disks,
460 raid_disks, level, layout);
461 qdisk = geo_map(-2, start/chunk_size/data_disks,
462 raid_disks, level, layout);
463 if (is_ddf(layout)) {
464 /* q over 'raid_disks' blocks, in device order.
465 * 'p' and 'q' get to be all zero
466 */
467 for (i = 0; i < raid_disks; i++)
cc50ccdc
N
468 bufs[i] = zero;
469 for (i = 0; i < data_disks; i++) {
470 int dnum = geo_map(i,
471 start/chunk_size/data_disks,
472 raid_disks, level, layout);
473 int snum;
474 /* i is the logical block number, so is index to 'buf'.
475 * dnum is physical disk number
476 * and thus the syndrome number.
477 */
478 snum = dnum;
479 bufs[snum] = (uint8_t*)buf + chunk_size * i;
480 }
a6288483
N
481 syndrome_disks = raid_disks;
482 } else {
483 /* for md, q is over 'data_disks' blocks,
484 * starting immediately after 'q'
1eac9f84
N
485 * Note that for the '_6' variety, the p block
486 * makes a hole that we need to be careful of.
a6288483 487 */
1eac9f84
N
488 int j;
489 int snum = 0;
490 for (j = 0; j < raid_disks; j++) {
491 int dnum = (qdisk + 1 + j) % raid_disks;
492 if (dnum == disk || dnum == qdisk)
493 continue;
494 for (i = 0; i < data_disks; i++)
495 if (geo_map(i,
496 start/chunk_size/data_disks,
497 raid_disks, level, layout) == dnum)
498 break;
cc50ccdc
N
499 /* i is the logical block number, so is index to 'buf'.
500 * dnum is physical disk number
501 * snum is syndrome disk for which 0 is immediately after Q
502 */
cc50ccdc 503 bufs[snum] = (uint8_t*)buf + chunk_size * i;
1eac9f84
N
504
505 if (fblock[0] == i)
506 fdisk[0] = snum;
507 if (fblock[1] == i)
508 fdisk[1] = snum;
509 snum++;
cc50ccdc 510 }
a6288483 511
a6288483
N
512 syndrome_disks = data_disks;
513 }
cc50ccdc
N
514
515 /* Place P and Q blocks at end of bufs */
516 bufs[syndrome_disks] = (uint8_t*)buf + chunk_size * data_disks;
517 bufs[syndrome_disks+1] = (uint8_t*)buf + chunk_size * (data_disks+1);
518
a6288483
N
519 if (fblock[1] == data_disks)
520 /* One data failed, and parity failed */
521 raid6_datap_recov(syndrome_disks+2, chunk_size,
522 fdisk[0], bufs);
cc50ccdc
N
523 else {
524 if (fdisk[0] > fdisk[1]) {
525 int t = fdisk[0];
526 fdisk[0] = fdisk[1];
527 fdisk[1] = t;
528 }
a6288483
N
529 /* Two data blocks failed, P,Q OK */
530 raid6_2data_recov(syndrome_disks+2, chunk_size,
531 fdisk[0], fdisk[1], bufs);
cc50ccdc 532 }
a6288483
N
533 }
534
e86c9dd6
NB
535 for (i=0; i<nwrites; i++)
536 if (write(dest[i], buf, len) != len)
537 return -1;
a6288483 538
e86c9dd6
NB
539 length -= len;
540 start += len;
e86c9dd6
NB
541 }
542 return 0;
543}
544
545/* Restore data:
546 * We are given:
547 * A list of 'fds' of the active disks. Some may be '-1' for not-available.
353632d9 548 * A geometry: raid_disks, chunk_size, level, layout
e86c9dd6
NB
549 * An 'fd' to read from. It is already seeked to the right (Read) location.
550 * A start and length.
551 * The length must be a multiple of the stripe size.
552 *
553 * We build a full stripe in memory and then write it out.
554 * We assume that there are enough working devices.
555 */
556int restore_stripes(int *dest, unsigned long long *offsets,
557 int raid_disks, int chunk_size, int level, int layout,
353632d9 558 int source, unsigned long long read_offset,
e86c9dd6
NB
559 unsigned long long start, unsigned long long length)
560{
e9e43ec3 561 char *stripe_buf;
e86c9dd6
NB
562 char **stripes = malloc(raid_disks * sizeof(char*));
563 char **blocks = malloc(raid_disks * sizeof(char*));
564 int i;
565
a6288483 566 int data_disks = raid_disks - (level == 0 ? 0 : level <= 5 ? 1 : 2);
e86c9dd6 567
fcf57625
N
568 if (posix_memalign((void**)&stripe_buf, 4096, raid_disks * chunk_size))
569 stripe_buf = NULL;
a6288483
N
570 if (zero == NULL) {
571 zero = malloc(chunk_size);
572 if (zero)
573 memset(zero, 0, chunk_size);
574 }
e0d95aac
N
575 if (stripe_buf == NULL || stripes == NULL || blocks == NULL
576 || zero == NULL) {
e86c9dd6
NB
577 free(stripe_buf);
578 free(stripes);
579 free(blocks);
e0d95aac 580 free(zero);
e86c9dd6
NB
581 return -2;
582 }
583 for (i=0; i<raid_disks; i++)
584 stripes[i] = stripe_buf + i * chunk_size;
585 while (length > 0) {
f21e18ca 586 unsigned int len = data_disks * chunk_size;
e86c9dd6 587 unsigned long long offset;
48327135 588 int disk, qdisk;
a6288483 589 int syndrome_disks;
e86c9dd6
NB
590 if (length < len)
591 return -3;
592 for (i=0; i < data_disks; i++) {
593 int disk = geo_map(i, start/chunk_size/data_disks,
594 raid_disks, level, layout);
f21e18ca
N
595 if ((unsigned long long)lseek64(source, read_offset, 0)
596 != read_offset)
353632d9 597 return -1;
f21e18ca
N
598 if (read(source, stripes[disk],
599 chunk_size) != chunk_size)
e86c9dd6 600 return -1;
353632d9 601 read_offset += chunk_size;
e86c9dd6
NB
602 }
603 /* We have the data, now do the parity */
604 offset = (start/chunk_size/data_disks) * chunk_size;
48327135
NB
605 switch (level) {
606 case 4:
607 case 5:
608 disk = geo_map(-1, start/chunk_size/data_disks,
e86c9dd6 609 raid_disks, level, layout);
e0d95aac
N
610 for (i = 0; i < data_disks; i++)
611 blocks[i] = stripes[(disk+1+i) % raid_disks];
e86c9dd6 612 xor_blocks(stripes[disk], blocks, data_disks, chunk_size);
48327135
NB
613 break;
614 case 6:
615 disk = geo_map(-1, start/chunk_size/data_disks,
616 raid_disks, level, layout);
617 qdisk = geo_map(-2, start/chunk_size/data_disks,
618 raid_disks, level, layout);
e0d95aac
N
619 if (is_ddf(layout)) {
620 /* q over 'raid_disks' blocks, in device order.
621 * 'p' and 'q' get to be all zero
622 */
623 for (i = 0; i < raid_disks; i++)
624 if (i == disk || i == qdisk)
a6288483 625 blocks[i] = (char*)zero;
e0d95aac
N
626 else
627 blocks[i] = stripes[i];
a6288483 628 syndrome_disks = raid_disks;
e0d95aac 629 } else {
a6288483 630 /* for md, q is over 'data_disks' blocks,
e0d95aac
N
631 * starting immediately after 'q'
632 */
633 for (i = 0; i < data_disks; i++)
634 blocks[i] = stripes[(qdisk+1+i) % raid_disks];
48327135 635
a6288483 636 syndrome_disks = data_disks;
e0d95aac 637 }
a6288483
N
638 qsyndrome((uint8_t*)stripes[disk],
639 (uint8_t*)stripes[qdisk],
640 (uint8_t**)blocks,
641 syndrome_disks, chunk_size);
48327135 642 break;
e86c9dd6
NB
643 }
644 for (i=0; i < raid_disks ; i++)
645 if (dest[i] >= 0) {
646 if (lseek64(dest[i], offsets[i]+offset, 0) < 0)
647 return -1;
648 if (write(dest[i], stripes[i], chunk_size) != chunk_size)
649 return -1;
650 }
651 length -= len;
652 start += len;
653 }
654 return 0;
655}
656
657#ifdef MAIN
658
48327135
NB
659int test_stripes(int *source, unsigned long long *offsets,
660 int raid_disks, int chunk_size, int level, int layout,
661 unsigned long long start, unsigned long long length)
662{
663 /* ready the data and p (and q) blocks, and check we got them right */
664 char *stripe_buf = malloc(raid_disks * chunk_size);
665 char **stripes = malloc(raid_disks * sizeof(char*));
666 char **blocks = malloc(raid_disks * sizeof(char*));
667 char *p = malloc(chunk_size);
668 char *q = malloc(chunk_size);
669
670 int i;
671 int data_disks = raid_disks - (level == 5 ? 1: 2);
672 for ( i = 0 ; i < raid_disks ; i++)
673 stripes[i] = stripe_buf + i * chunk_size;
674
675 while (length > 0) {
676 int disk;
677
678 for (i = 0 ; i < raid_disks ; i++) {
679 lseek64(source[i], offsets[i]+start, 0);
680 read(source[i], stripes[i], chunk_size);
681 }
682 for (i = 0 ; i < data_disks ; i++) {
683 int disk = geo_map(i, start/chunk_size, raid_disks,
684 level, layout);
685 blocks[i] = stripes[disk];
686 printf("%d->%d\n", i, disk);
687 }
688 switch(level) {
689 case 6:
521f349c 690 qsyndrome(p, q, (uint8_t**)blocks, data_disks, chunk_size);
48327135
NB
691 disk = geo_map(-1, start/chunk_size, raid_disks,
692 level, layout);
693 if (memcmp(p, stripes[disk], chunk_size) != 0) {
694 printf("P(%d) wrong at %llu\n", disk,
695 start / chunk_size);
696 }
697 disk = geo_map(-2, start/chunk_size, raid_disks,
698 level, layout);
699 if (memcmp(q, stripes[disk], chunk_size) != 0) {
700 printf("Q(%d) wrong at %llu\n", disk,
701 start / chunk_size);
702 }
703 break;
704 }
705 length -= chunk_size;
706 start += chunk_size;
707 }
708 return 0;
709}
710
e86c9dd6
NB
711unsigned long long getnum(char *str, char **err)
712{
713 char *e;
714 unsigned long long rv = strtoull(str, &e, 10);
715 if (e==str || *e) {
716 *err = str;
717 return 0;
718 }
719 return rv;
720}
721
722main(int argc, char *argv[])
723{
724 /* save/restore file raid_disks chunk_size level layout start length devices...
725 */
726 int save;
727 int *fds;
728 char *file;
a6288483 729 char *buf;
e86c9dd6
NB
730 int storefd;
731 unsigned long long *offsets;
732 int raid_disks, chunk_size, level, layout;
733 unsigned long long start, length;
734 int i;
735
736 char *err = NULL;
737 if (argc < 10) {
738 fprintf(stderr, "Usage: test_stripe save/restore file raid_disks"
739 " chunk_size level layout start length devices...\n");
740 exit(1);
741 }
742 if (strcmp(argv[1], "save")==0)
743 save = 1;
744 else if (strcmp(argv[1], "restore") == 0)
745 save = 0;
48327135
NB
746 else if (strcmp(argv[1], "test") == 0)
747 save = 2;
e86c9dd6
NB
748 else {
749 fprintf(stderr, "test_stripe: must give 'save' or 'restore'.\n");
750 exit(2);
751 }
752
753 file = argv[2];
754 raid_disks = getnum(argv[3], &err);
755 chunk_size = getnum(argv[4], &err);
756 level = getnum(argv[5], &err);
757 layout = getnum(argv[6], &err);
758 start = getnum(argv[7], &err);
759 length = getnum(argv[8], &err);
760 if (err) {
761 fprintf(stderr, "test_stripe: Bad number: %s\n", err);
762 exit(2);
763 }
764 if (argc != raid_disks + 9) {
765 fprintf(stderr, "test_stripe: wrong number of devices: want %d found %d\n",
766 raid_disks, argc-9);
767 exit(2);
768 }
769 fds = malloc(raid_disks * sizeof(*fds));
770 offsets = malloc(raid_disks * sizeof(*offsets));
771 memset(offsets, 0, raid_disks * sizeof(*offsets));
772
773 storefd = open(file, O_RDWR);
774 if (storefd < 0) {
775 perror(file);
776 fprintf(stderr, "test_stripe: could not open %s.\n", file);
777 exit(3);
778 }
779 for (i=0; i<raid_disks; i++) {
780 fds[i] = open(argv[9+i], O_RDWR);
781 if (fds[i] < 0) {
782 perror(argv[9+i]);
783 fprintf(stderr,"test_stripe: cannot open %s.\n", argv[9+i]);
784 exit(3);
785 }
786 }
787
a6288483
N
788 buf = malloc(raid_disks * chunk_size);
789
48327135 790 if (save == 1) {
e86c9dd6
NB
791 int rv = save_stripes(fds, offsets,
792 raid_disks, chunk_size, level, layout,
793 1, &storefd,
a6288483 794 start, length, buf);
e86c9dd6 795 if (rv != 0) {
48327135
NB
796 fprintf(stderr,
797 "test_stripe: save_stripes returned %d\n", rv);
798 exit(1);
799 }
800 } else if (save == 2) {
801 int rv = test_stripes(fds, offsets,
802 raid_disks, chunk_size, level, layout,
803 start, length);
804 if (rv != 0) {
805 fprintf(stderr,
806 "test_stripe: test_stripes returned %d\n", rv);
e86c9dd6
NB
807 exit(1);
808 }
809 } else {
810 int rv = restore_stripes(fds, offsets,
811 raid_disks, chunk_size, level, layout,
353632d9 812 storefd, 0ULL,
e86c9dd6
NB
813 start, length);
814 if (rv != 0) {
48327135
NB
815 fprintf(stderr,
816 "test_stripe: restore_stripes returned %d\n",
817 rv);
e86c9dd6
NB
818 exit(1);
819 }
820 }
821 exit(0);
822}
823
824#endif /* MAIN */