]> git.ipfire.org Git - thirdparty/mdadm.git/blob - restripe.c
(no commit message)
[thirdparty/mdadm.git] / restripe.c
1 /*
2 * mdadm - manage Linux "md" devices aka RAID arrays.
3 *
4 * Copyright (C) 2006-2009 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"
26 #include <stdint.h>
27
28 /* To restripe, we read from old geometry to a buffer, and
29 * read from buffer to new geometry.
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.
33 *
34 */
35
36 static int geo_map(int block, unsigned long long stripe, int raid_disks,
37 int level, int layout)
38 {
39 /* On the given stripe, find which disk in the array will have
40 * block numbered 'block'.
41 * '-1' means the parity block.
42 * '-2' means the Q syndrome.
43 */
44 int pd;
45
46 switch(level*100 + layout) {
47 case 000:
48 case 400:
49 case 500 + ALGORITHM_PARITY_N:
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
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
137 case 600 + ALGORITHM_LEFT_ASYMMETRIC:
138 pd = raid_disks - 1 - (stripe % raid_disks);
139 if (block == -1) return pd;
140 if (block == -2) return (pd+1) % raid_disks;
141 if (pd == raid_disks - 1)
142 return block+1;
143 if (block >= pd)
144 return block+2;
145 return block;
146
147 case 600 + ALGORITHM_ROTATING_ZERO_RESTART:
148 /* Different order for calculating Q, otherwize same as ... */
149 case 600 + ALGORITHM_RIGHT_ASYMMETRIC:
150 pd = stripe % raid_disks;
151 if (block == -1) return pd;
152 if (block == -2) return (pd+1) % raid_disks;
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;
162 if (block == -2) return (pd+1) % raid_disks;
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;
168 if (block == -2) return (pd+1) % raid_disks;
169 return (pd + 2 + block) % raid_disks;
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;
192 }
193 return -1;
194 }
195 static 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 }
207
208
209 static 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
221 static void qsyndrome(uint8_t *p, uint8_t *q, uint8_t **sources, int disks, int size)
222 {
223 int d, z;
224 uint8_t wq0, wp0, wd0, w10, w20;
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
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 */
246 static 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
260 static 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
278 int tables_ready = 0;
279 uint8_t raid6_gfmul[256][256];
280 uint8_t raid6_gfexp[256];
281 uint8_t raid6_gfinv[256];
282 uint8_t raid6_gfexi[256];
283 void 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
313 uint8_t *zero;
314 /* Following was taken from linux/drivers/md/raid6recov.c */
315
316 /* Recover two failed data blocks. */
317 void 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 */
357 void 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
385 /* Save data:
386 * We are given:
387 * A list of 'fds' of the active disks. Some may be absent.
388 * A geometry: raid_disks, chunk_size, level, layout
389 * A list of 'fds' for mirrored targets. They are already seeked to
390 * right (Write) location
391 * A start and length which must be stripe-aligned
392 * 'buf' is large enough to hold one stripe, and is aligned
393 */
394
395 int save_stripes(int *source, unsigned long long *offsets,
396 int raid_disks, int chunk_size, int level, int layout,
397 int nwrites, int *dest,
398 unsigned long long start, unsigned long long length,
399 char *buf)
400 {
401 int len;
402 int data_disks = raid_disks - (level == 0 ? 0 : level <=5 ? 1 : 2);
403 int disk;
404 int i;
405
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;
415 while (length > 0) {
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;
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);
426 if (dnum < 0) abort();
427 if (source[dnum] < 0 ||
428 lseek64(source[dnum], offsets[dnum]+offset, 0) < 0 ||
429 read(source[dnum], buf+disk * chunk_size, chunk_size)
430 != chunk_size)
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 */
453 return -1;
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 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 }
481 syndrome_disks = raid_disks;
482 } else {
483 /* for md, q is over 'data_disks' blocks,
484 * starting immediately after 'q'
485 * Note that for the '_6' variety, the p block
486 * makes a hole that we need to be careful of.
487 */
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;
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 */
503 bufs[snum] = (uint8_t*)buf + chunk_size * i;
504
505 if (fblock[0] == i)
506 fdisk[0] = snum;
507 if (fblock[1] == i)
508 fdisk[1] = snum;
509 snum++;
510 }
511
512 syndrome_disks = data_disks;
513 }
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
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);
523 else {
524 if (fdisk[0] > fdisk[1]) {
525 int t = fdisk[0];
526 fdisk[0] = fdisk[1];
527 fdisk[1] = t;
528 }
529 /* Two data blocks failed, P,Q OK */
530 raid6_2data_recov(syndrome_disks+2, chunk_size,
531 fdisk[0], fdisk[1], bufs);
532 }
533 }
534
535 for (i=0; i<nwrites; i++)
536 if (write(dest[i], buf, len) != len)
537 return -1;
538
539 length -= len;
540 start += len;
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.
548 * A geometry: raid_disks, chunk_size, level, layout
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 */
556 int restore_stripes(int *dest, unsigned long long *offsets,
557 int raid_disks, int chunk_size, int level, int layout,
558 int source, unsigned long long read_offset,
559 unsigned long long start, unsigned long long length)
560 {
561 char *stripe_buf;
562 char **stripes = malloc(raid_disks * sizeof(char*));
563 char **blocks = malloc(raid_disks * sizeof(char*));
564 int i;
565
566 int data_disks = raid_disks - (level == 0 ? 0 : level <= 5 ? 1 : 2);
567
568 if (posix_memalign((void**)&stripe_buf, 4096, raid_disks * chunk_size))
569 stripe_buf = NULL;
570 if (zero == NULL) {
571 zero = malloc(chunk_size);
572 if (zero)
573 memset(zero, 0, chunk_size);
574 }
575 if (stripe_buf == NULL || stripes == NULL || blocks == NULL
576 || zero == NULL) {
577 free(stripe_buf);
578 free(stripes);
579 free(blocks);
580 free(zero);
581 return -2;
582 }
583 for (i=0; i<raid_disks; i++)
584 stripes[i] = stripe_buf + i * chunk_size;
585 while (length > 0) {
586 int len = data_disks * chunk_size;
587 unsigned long long offset;
588 int disk, qdisk;
589 int syndrome_disks;
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);
595 if (lseek64(source, read_offset, 0) != read_offset)
596 return -1;
597 if (read(source, stripes[disk], chunk_size) != chunk_size)
598 return -1;
599 read_offset += chunk_size;
600 }
601 /* We have the data, now do the parity */
602 offset = (start/chunk_size/data_disks) * chunk_size;
603 switch (level) {
604 case 4:
605 case 5:
606 disk = geo_map(-1, start/chunk_size/data_disks,
607 raid_disks, level, layout);
608 for (i = 0; i < data_disks; i++)
609 blocks[i] = stripes[(disk+1+i) % raid_disks];
610 xor_blocks(stripes[disk], blocks, data_disks, chunk_size);
611 break;
612 case 6:
613 disk = geo_map(-1, start/chunk_size/data_disks,
614 raid_disks, level, layout);
615 qdisk = geo_map(-2, start/chunk_size/data_disks,
616 raid_disks, level, layout);
617 if (is_ddf(layout)) {
618 /* q over 'raid_disks' blocks, in device order.
619 * 'p' and 'q' get to be all zero
620 */
621 for (i = 0; i < raid_disks; i++)
622 if (i == disk || i == qdisk)
623 blocks[i] = (char*)zero;
624 else
625 blocks[i] = stripes[i];
626 syndrome_disks = raid_disks;
627 } else {
628 /* for md, q is over 'data_disks' blocks,
629 * starting immediately after 'q'
630 */
631 for (i = 0; i < data_disks; i++)
632 blocks[i] = stripes[(qdisk+1+i) % raid_disks];
633
634 syndrome_disks = data_disks;
635 }
636 qsyndrome((uint8_t*)stripes[disk],
637 (uint8_t*)stripes[qdisk],
638 (uint8_t**)blocks,
639 syndrome_disks, chunk_size);
640 break;
641 }
642 for (i=0; i < raid_disks ; i++)
643 if (dest[i] >= 0) {
644 if (lseek64(dest[i], offsets[i]+offset, 0) < 0)
645 return -1;
646 if (write(dest[i], stripes[i], chunk_size) != chunk_size)
647 return -1;
648 }
649 length -= len;
650 start += len;
651 }
652 return 0;
653 }
654
655 #ifdef MAIN
656
657 int test_stripes(int *source, unsigned long long *offsets,
658 int raid_disks, int chunk_size, int level, int layout,
659 unsigned long long start, unsigned long long length)
660 {
661 /* ready the data and p (and q) blocks, and check we got them right */
662 char *stripe_buf = malloc(raid_disks * chunk_size);
663 char **stripes = malloc(raid_disks * sizeof(char*));
664 char **blocks = malloc(raid_disks * sizeof(char*));
665 char *p = malloc(chunk_size);
666 char *q = malloc(chunk_size);
667
668 int i;
669 int data_disks = raid_disks - (level == 5 ? 1: 2);
670 for ( i = 0 ; i < raid_disks ; i++)
671 stripes[i] = stripe_buf + i * chunk_size;
672
673 while (length > 0) {
674 int disk;
675
676 for (i = 0 ; i < raid_disks ; i++) {
677 lseek64(source[i], offsets[i]+start, 0);
678 read(source[i], stripes[i], chunk_size);
679 }
680 for (i = 0 ; i < data_disks ; i++) {
681 int disk = geo_map(i, start/chunk_size, raid_disks,
682 level, layout);
683 blocks[i] = stripes[disk];
684 printf("%d->%d\n", i, disk);
685 }
686 switch(level) {
687 case 6:
688 qsyndrome(p, q, (uint8_t**)blocks, data_disks, chunk_size);
689 disk = geo_map(-1, start/chunk_size, raid_disks,
690 level, layout);
691 if (memcmp(p, stripes[disk], chunk_size) != 0) {
692 printf("P(%d) wrong at %llu\n", disk,
693 start / chunk_size);
694 }
695 disk = geo_map(-2, start/chunk_size, raid_disks,
696 level, layout);
697 if (memcmp(q, stripes[disk], chunk_size) != 0) {
698 printf("Q(%d) wrong at %llu\n", disk,
699 start / chunk_size);
700 }
701 break;
702 }
703 length -= chunk_size;
704 start += chunk_size;
705 }
706 return 0;
707 }
708
709 unsigned long long getnum(char *str, char **err)
710 {
711 char *e;
712 unsigned long long rv = strtoull(str, &e, 10);
713 if (e==str || *e) {
714 *err = str;
715 return 0;
716 }
717 return rv;
718 }
719
720 main(int argc, char *argv[])
721 {
722 /* save/restore file raid_disks chunk_size level layout start length devices...
723 */
724 int save;
725 int *fds;
726 char *file;
727 char *buf;
728 int storefd;
729 unsigned long long *offsets;
730 int raid_disks, chunk_size, level, layout;
731 unsigned long long start, length;
732 int i;
733
734 char *err = NULL;
735 if (argc < 10) {
736 fprintf(stderr, "Usage: test_stripe save/restore file raid_disks"
737 " chunk_size level layout start length devices...\n");
738 exit(1);
739 }
740 if (strcmp(argv[1], "save")==0)
741 save = 1;
742 else if (strcmp(argv[1], "restore") == 0)
743 save = 0;
744 else if (strcmp(argv[1], "test") == 0)
745 save = 2;
746 else {
747 fprintf(stderr, "test_stripe: must give 'save' or 'restore'.\n");
748 exit(2);
749 }
750
751 file = argv[2];
752 raid_disks = getnum(argv[3], &err);
753 chunk_size = getnum(argv[4], &err);
754 level = getnum(argv[5], &err);
755 layout = getnum(argv[6], &err);
756 start = getnum(argv[7], &err);
757 length = getnum(argv[8], &err);
758 if (err) {
759 fprintf(stderr, "test_stripe: Bad number: %s\n", err);
760 exit(2);
761 }
762 if (argc != raid_disks + 9) {
763 fprintf(stderr, "test_stripe: wrong number of devices: want %d found %d\n",
764 raid_disks, argc-9);
765 exit(2);
766 }
767 fds = malloc(raid_disks * sizeof(*fds));
768 offsets = malloc(raid_disks * sizeof(*offsets));
769 memset(offsets, 0, raid_disks * sizeof(*offsets));
770
771 storefd = open(file, O_RDWR);
772 if (storefd < 0) {
773 perror(file);
774 fprintf(stderr, "test_stripe: could not open %s.\n", file);
775 exit(3);
776 }
777 for (i=0; i<raid_disks; i++) {
778 fds[i] = open(argv[9+i], O_RDWR);
779 if (fds[i] < 0) {
780 perror(argv[9+i]);
781 fprintf(stderr,"test_stripe: cannot open %s.\n", argv[9+i]);
782 exit(3);
783 }
784 }
785
786 buf = malloc(raid_disks * chunk_size);
787
788 if (save == 1) {
789 int rv = save_stripes(fds, offsets,
790 raid_disks, chunk_size, level, layout,
791 1, &storefd,
792 start, length, buf);
793 if (rv != 0) {
794 fprintf(stderr,
795 "test_stripe: save_stripes returned %d\n", rv);
796 exit(1);
797 }
798 } else if (save == 2) {
799 int rv = test_stripes(fds, offsets,
800 raid_disks, chunk_size, level, layout,
801 start, length);
802 if (rv != 0) {
803 fprintf(stderr,
804 "test_stripe: test_stripes returned %d\n", rv);
805 exit(1);
806 }
807 } else {
808 int rv = restore_stripes(fds, offsets,
809 raid_disks, chunk_size, level, layout,
810 storefd, 0ULL,
811 start, length);
812 if (rv != 0) {
813 fprintf(stderr,
814 "test_stripe: restore_stripes returned %d\n",
815 rv);
816 exit(1);
817 }
818 }
819 exit(0);
820 }
821
822 #endif /* MAIN */