]> git.ipfire.org Git - thirdparty/mdadm.git/blame - restripe.c
Handle extra 'grow' variations.
[thirdparty/mdadm.git] / restripe.c
CommitLineData
e86c9dd6
NB
1/*
2 * mdadm - manage Linux "md" devices aka RAID arrays.
3 *
4 * Copyright (C) 2006 Neil Brown <neilb@suse.de>
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
N
427 if (source[dnum] < 0 ||
428 lseek64(source[dnum], offsets[disk]+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++)
468 if (i == disk || i == qdisk)
469 bufs[i] = zero;
470 else
471 bufs[i] = (uint8_t*)buf+i*chunk_size;
472 syndrome_disks = raid_disks;
473 } else {
474 /* for md, q is over 'data_disks' blocks,
475 * starting immediately after 'q'
476 */
477 for (i = 0; i < data_disks; i++)
478 bufs[i] = (uint8_t*)buf + chunk_size * ((qdisk+1+i) % raid_disks);
479
480 fdisk[0] = (qdisk + 1 + fdisk[0]) * raid_disks;
481 fdisk[1] = (qdisk + 1 + fdisk[1]) * raid_disks;
482 syndrome_disks = data_disks;
483 }
484 bufs[syndrome_disks] = (uint8_t*)buf + chunk_size * disk;
485 bufs[syndrome_disks+1] = (uint8_t*)buf + chunk_size * qdisk;
486 if (fblock[1] == data_disks)
487 /* One data failed, and parity failed */
488 raid6_datap_recov(syndrome_disks+2, chunk_size,
489 fdisk[0], bufs);
490 else
491 /* Two data blocks failed, P,Q OK */
492 raid6_2data_recov(syndrome_disks+2, chunk_size,
493 fdisk[0], fdisk[1], bufs);
494 }
495
e86c9dd6
NB
496 for (i=0; i<nwrites; i++)
497 if (write(dest[i], buf, len) != len)
498 return -1;
a6288483 499
e86c9dd6
NB
500 length -= len;
501 start += len;
e86c9dd6
NB
502 }
503 return 0;
504}
505
506/* Restore data:
507 * We are given:
508 * A list of 'fds' of the active disks. Some may be '-1' for not-available.
353632d9 509 * A geometry: raid_disks, chunk_size, level, layout
e86c9dd6
NB
510 * An 'fd' to read from. It is already seeked to the right (Read) location.
511 * A start and length.
512 * The length must be a multiple of the stripe size.
513 *
514 * We build a full stripe in memory and then write it out.
515 * We assume that there are enough working devices.
516 */
517int restore_stripes(int *dest, unsigned long long *offsets,
518 int raid_disks, int chunk_size, int level, int layout,
353632d9 519 int source, unsigned long long read_offset,
e86c9dd6
NB
520 unsigned long long start, unsigned long long length)
521{
522 char *stripe_buf = malloc(raid_disks * chunk_size);
523 char **stripes = malloc(raid_disks * sizeof(char*));
524 char **blocks = malloc(raid_disks * sizeof(char*));
525 int i;
526
a6288483 527 int data_disks = raid_disks - (level == 0 ? 0 : level <= 5 ? 1 : 2);
e86c9dd6 528
a6288483
N
529 if (zero == NULL) {
530 zero = malloc(chunk_size);
531 if (zero)
532 memset(zero, 0, chunk_size);
533 }
e0d95aac
N
534 if (stripe_buf == NULL || stripes == NULL || blocks == NULL
535 || zero == NULL) {
e86c9dd6
NB
536 free(stripe_buf);
537 free(stripes);
538 free(blocks);
e0d95aac 539 free(zero);
e86c9dd6
NB
540 return -2;
541 }
542 for (i=0; i<raid_disks; i++)
543 stripes[i] = stripe_buf + i * chunk_size;
544 while (length > 0) {
545 int len = data_disks * chunk_size;
546 unsigned long long offset;
48327135 547 int disk, qdisk;
a6288483 548 int syndrome_disks;
e86c9dd6
NB
549 if (length < len)
550 return -3;
551 for (i=0; i < data_disks; i++) {
552 int disk = geo_map(i, start/chunk_size/data_disks,
553 raid_disks, level, layout);
353632d9
NB
554 if (lseek64(source, read_offset, 0) != read_offset)
555 return -1;
e86c9dd6
NB
556 if (read(source, stripes[disk], chunk_size) != chunk_size)
557 return -1;
353632d9 558 read_offset += chunk_size;
e86c9dd6
NB
559 }
560 /* We have the data, now do the parity */
561 offset = (start/chunk_size/data_disks) * chunk_size;
48327135
NB
562 switch (level) {
563 case 4:
564 case 5:
565 disk = geo_map(-1, start/chunk_size/data_disks,
e86c9dd6 566 raid_disks, level, layout);
e0d95aac
N
567 for (i = 0; i < data_disks; i++)
568 blocks[i] = stripes[(disk+1+i) % raid_disks];
e86c9dd6 569 xor_blocks(stripes[disk], blocks, data_disks, chunk_size);
48327135
NB
570 break;
571 case 6:
572 disk = geo_map(-1, start/chunk_size/data_disks,
573 raid_disks, level, layout);
574 qdisk = geo_map(-2, start/chunk_size/data_disks,
575 raid_disks, level, layout);
e0d95aac
N
576 if (is_ddf(layout)) {
577 /* q over 'raid_disks' blocks, in device order.
578 * 'p' and 'q' get to be all zero
579 */
580 for (i = 0; i < raid_disks; i++)
581 if (i == disk || i == qdisk)
a6288483 582 blocks[i] = (char*)zero;
e0d95aac
N
583 else
584 blocks[i] = stripes[i];
a6288483 585 syndrome_disks = raid_disks;
e0d95aac 586 } else {
a6288483 587 /* for md, q is over 'data_disks' blocks,
e0d95aac
N
588 * starting immediately after 'q'
589 */
590 for (i = 0; i < data_disks; i++)
591 blocks[i] = stripes[(qdisk+1+i) % raid_disks];
48327135 592
a6288483 593 syndrome_disks = data_disks;
e0d95aac 594 }
a6288483
N
595 qsyndrome((uint8_t*)stripes[disk],
596 (uint8_t*)stripes[qdisk],
597 (uint8_t**)blocks,
598 syndrome_disks, chunk_size);
48327135 599 break;
e86c9dd6
NB
600 }
601 for (i=0; i < raid_disks ; i++)
602 if (dest[i] >= 0) {
603 if (lseek64(dest[i], offsets[i]+offset, 0) < 0)
604 return -1;
605 if (write(dest[i], stripes[i], chunk_size) != chunk_size)
606 return -1;
607 }
608 length -= len;
609 start += len;
610 }
611 return 0;
612}
613
614#ifdef MAIN
615
48327135
NB
616int test_stripes(int *source, unsigned long long *offsets,
617 int raid_disks, int chunk_size, int level, int layout,
618 unsigned long long start, unsigned long long length)
619{
620 /* ready the data and p (and q) blocks, and check we got them right */
621 char *stripe_buf = malloc(raid_disks * chunk_size);
622 char **stripes = malloc(raid_disks * sizeof(char*));
623 char **blocks = malloc(raid_disks * sizeof(char*));
624 char *p = malloc(chunk_size);
625 char *q = malloc(chunk_size);
626
627 int i;
628 int data_disks = raid_disks - (level == 5 ? 1: 2);
629 for ( i = 0 ; i < raid_disks ; i++)
630 stripes[i] = stripe_buf + i * chunk_size;
631
632 while (length > 0) {
633 int disk;
634
635 for (i = 0 ; i < raid_disks ; i++) {
636 lseek64(source[i], offsets[i]+start, 0);
637 read(source[i], stripes[i], chunk_size);
638 }
639 for (i = 0 ; i < data_disks ; i++) {
640 int disk = geo_map(i, start/chunk_size, raid_disks,
641 level, layout);
642 blocks[i] = stripes[disk];
643 printf("%d->%d\n", i, disk);
644 }
645 switch(level) {
646 case 6:
647 qsyndrome(p, q, blocks, data_disks, chunk_size);
648 disk = geo_map(-1, start/chunk_size, raid_disks,
649 level, layout);
650 if (memcmp(p, stripes[disk], chunk_size) != 0) {
651 printf("P(%d) wrong at %llu\n", disk,
652 start / chunk_size);
653 }
654 disk = geo_map(-2, start/chunk_size, raid_disks,
655 level, layout);
656 if (memcmp(q, stripes[disk], chunk_size) != 0) {
657 printf("Q(%d) wrong at %llu\n", disk,
658 start / chunk_size);
659 }
660 break;
661 }
662 length -= chunk_size;
663 start += chunk_size;
664 }
665 return 0;
666}
667
e86c9dd6
NB
668unsigned long long getnum(char *str, char **err)
669{
670 char *e;
671 unsigned long long rv = strtoull(str, &e, 10);
672 if (e==str || *e) {
673 *err = str;
674 return 0;
675 }
676 return rv;
677}
678
679main(int argc, char *argv[])
680{
681 /* save/restore file raid_disks chunk_size level layout start length devices...
682 */
683 int save;
684 int *fds;
685 char *file;
a6288483 686 char *buf;
e86c9dd6
NB
687 int storefd;
688 unsigned long long *offsets;
689 int raid_disks, chunk_size, level, layout;
690 unsigned long long start, length;
691 int i;
692
693 char *err = NULL;
694 if (argc < 10) {
695 fprintf(stderr, "Usage: test_stripe save/restore file raid_disks"
696 " chunk_size level layout start length devices...\n");
697 exit(1);
698 }
699 if (strcmp(argv[1], "save")==0)
700 save = 1;
701 else if (strcmp(argv[1], "restore") == 0)
702 save = 0;
48327135
NB
703 else if (strcmp(argv[1], "test") == 0)
704 save = 2;
e86c9dd6
NB
705 else {
706 fprintf(stderr, "test_stripe: must give 'save' or 'restore'.\n");
707 exit(2);
708 }
709
710 file = argv[2];
711 raid_disks = getnum(argv[3], &err);
712 chunk_size = getnum(argv[4], &err);
713 level = getnum(argv[5], &err);
714 layout = getnum(argv[6], &err);
715 start = getnum(argv[7], &err);
716 length = getnum(argv[8], &err);
717 if (err) {
718 fprintf(stderr, "test_stripe: Bad number: %s\n", err);
719 exit(2);
720 }
721 if (argc != raid_disks + 9) {
722 fprintf(stderr, "test_stripe: wrong number of devices: want %d found %d\n",
723 raid_disks, argc-9);
724 exit(2);
725 }
726 fds = malloc(raid_disks * sizeof(*fds));
727 offsets = malloc(raid_disks * sizeof(*offsets));
728 memset(offsets, 0, raid_disks * sizeof(*offsets));
729
730 storefd = open(file, O_RDWR);
731 if (storefd < 0) {
732 perror(file);
733 fprintf(stderr, "test_stripe: could not open %s.\n", file);
734 exit(3);
735 }
736 for (i=0; i<raid_disks; i++) {
737 fds[i] = open(argv[9+i], O_RDWR);
738 if (fds[i] < 0) {
739 perror(argv[9+i]);
740 fprintf(stderr,"test_stripe: cannot open %s.\n", argv[9+i]);
741 exit(3);
742 }
743 }
744
a6288483
N
745 buf = malloc(raid_disks * chunk_size);
746
48327135 747 if (save == 1) {
e86c9dd6
NB
748 int rv = save_stripes(fds, offsets,
749 raid_disks, chunk_size, level, layout,
750 1, &storefd,
a6288483 751 start, length, buf);
e86c9dd6 752 if (rv != 0) {
48327135
NB
753 fprintf(stderr,
754 "test_stripe: save_stripes returned %d\n", rv);
755 exit(1);
756 }
757 } else if (save == 2) {
758 int rv = test_stripes(fds, offsets,
759 raid_disks, chunk_size, level, layout,
760 start, length);
761 if (rv != 0) {
762 fprintf(stderr,
763 "test_stripe: test_stripes returned %d\n", rv);
e86c9dd6
NB
764 exit(1);
765 }
766 } else {
767 int rv = restore_stripes(fds, offsets,
768 raid_disks, chunk_size, level, layout,
353632d9 769 storefd, 0ULL,
e86c9dd6
NB
770 start, length);
771 if (rv != 0) {
48327135
NB
772 fprintf(stderr,
773 "test_stripe: restore_stripes returned %d\n",
774 rv);
e86c9dd6
NB
775 exit(1);
776 }
777 }
778 exit(0);
779}
780
781#endif /* MAIN */