Teach restripe to calculate Q syndrome for raid6.
This allows mdadm to correctly restart a raid6 grow that crashed during the critcal phase.
This commit is contained in:
parent
ae491d1e2c
commit
48327135d6
|
@ -1,6 +1,9 @@
|
||||||
Changes Prior to this release
|
Changes Prior to this release
|
||||||
- --monitor was producing some meaningless warnings due to a bug.
|
- --monitor was producing some meaningless warnings due to a bug.
|
||||||
- Fix some compiler warnings.
|
- Fix some compiler warnings.
|
||||||
|
- Fully support --grow for raid6. If a reshape crashed during the
|
||||||
|
critical period, mdadm wouldn't restore the Q information
|
||||||
|
properly.
|
||||||
|
|
||||||
Changes Prior to 2.6 release
|
Changes Prior to 2.6 release
|
||||||
- Fixed UUID printing in "--detail --brief" for version1 metadata.
|
- Fixed UUID printing in "--detail --brief" for version1 metadata.
|
||||||
|
|
120
restripe.c
120
restripe.c
|
@ -32,8 +32,10 @@
|
||||||
|
|
||||||
static int geo_map(int block, unsigned long long stripe, int raid_disks, int level, int layout)
|
static int geo_map(int block, unsigned long long stripe, int raid_disks, int level, int layout)
|
||||||
{
|
{
|
||||||
/* On the given stripe, find which disk in the array with have
|
/* On the given stripe, find which disk in the array will have
|
||||||
* block numbered 'block'.
|
* block numbered 'block'.
|
||||||
|
* '-1' means the parity block.
|
||||||
|
* '-2' means the Q syndrome.
|
||||||
*/
|
*/
|
||||||
int pd;
|
int pd;
|
||||||
|
|
||||||
|
@ -71,6 +73,7 @@ static int geo_map(int block, unsigned long long stripe, int raid_disks, int lev
|
||||||
case 600 + ALGORITHM_LEFT_ASYMMETRIC:
|
case 600 + ALGORITHM_LEFT_ASYMMETRIC:
|
||||||
pd = raid_disks - 1 - (stripe % raid_disks);
|
pd = raid_disks - 1 - (stripe % raid_disks);
|
||||||
if (block == -1) return pd;
|
if (block == -1) return pd;
|
||||||
|
if (block == -2) return (pd+1) % raid_disks;
|
||||||
if (pd == raid_disks - 1)
|
if (pd == raid_disks - 1)
|
||||||
return block+1;
|
return block+1;
|
||||||
if (block >= pd)
|
if (block >= pd)
|
||||||
|
@ -80,6 +83,7 @@ static int geo_map(int block, unsigned long long stripe, int raid_disks, int lev
|
||||||
case 600 + ALGORITHM_RIGHT_ASYMMETRIC:
|
case 600 + ALGORITHM_RIGHT_ASYMMETRIC:
|
||||||
pd = stripe % raid_disks;
|
pd = stripe % raid_disks;
|
||||||
if (block == -1) return pd;
|
if (block == -1) return pd;
|
||||||
|
if (block == -2) return (pd+1) % raid_disks;
|
||||||
if (pd == raid_disks - 1)
|
if (pd == raid_disks - 1)
|
||||||
return block+1;
|
return block+1;
|
||||||
if (block >= pd)
|
if (block >= pd)
|
||||||
|
@ -89,11 +93,13 @@ static int geo_map(int block, unsigned long long stripe, int raid_disks, int lev
|
||||||
case 600 + ALGORITHM_LEFT_SYMMETRIC:
|
case 600 + ALGORITHM_LEFT_SYMMETRIC:
|
||||||
pd = raid_disks - 1 - (stripe % raid_disks);
|
pd = raid_disks - 1 - (stripe % raid_disks);
|
||||||
if (block == -1) return pd;
|
if (block == -1) return pd;
|
||||||
|
if (block == -2) return (pd+1) % raid_disks;
|
||||||
return (pd + 2 + block) % raid_disks;
|
return (pd + 2 + block) % raid_disks;
|
||||||
|
|
||||||
case 600 + ALGORITHM_RIGHT_SYMMETRIC:
|
case 600 + ALGORITHM_RIGHT_SYMMETRIC:
|
||||||
pd = stripe % raid_disks;
|
pd = stripe % raid_disks;
|
||||||
if (block == -1) return pd;
|
if (block == -1) return pd;
|
||||||
|
if (block == -2) return (pd+1) % raid_disks;
|
||||||
return (pd + 2 + block) % raid_disks;
|
return (pd + 2 + block) % raid_disks;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -112,10 +118,30 @@ static void xor_blocks(char *target, char **sources, int disks, int size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void qsyndrome(char *p, char *q, char **sources, int disks, int size)
|
||||||
|
{
|
||||||
|
int d, z;
|
||||||
|
char wq0, wp0, wd0, w10, w20;
|
||||||
|
for ( d = 0; d < size; d++) {
|
||||||
|
wq0 = wp0 = sources[disks-1][d];
|
||||||
|
for ( z = disks-2 ; z >= 0 ; z-- ) {
|
||||||
|
wd0 = sources[z][d];
|
||||||
|
wp0 ^= wd0;
|
||||||
|
w20 = (wq0&0x80) ? 0xff : 0x00;
|
||||||
|
w10 = (wq0 << 1) & 0xff;
|
||||||
|
w20 &= 0x1d;
|
||||||
|
w10 ^= w20;
|
||||||
|
wq0 = w10 ^ wd0;
|
||||||
|
}
|
||||||
|
p[d] = wp0;
|
||||||
|
q[d] = wq0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Save data:
|
/* Save data:
|
||||||
* We are given:
|
* We are given:
|
||||||
* A list of 'fds' of the active disks. For now we require all to be present.
|
* A list of 'fds' of the active disks. For now we require all to be present.
|
||||||
* A geomtry: raid_disks, chunk_size, level, layout
|
* A geometry: raid_disks, chunk_size, level, layout
|
||||||
* A list of 'fds' for mirrored targets. They are already seeked to
|
* A list of 'fds' for mirrored targets. They are already seeked to
|
||||||
* right (Write) location
|
* right (Write) location
|
||||||
* A start and length
|
* A start and length
|
||||||
|
@ -193,6 +219,7 @@ int restore_stripes(int *dest, unsigned long long *offsets,
|
||||||
while (length > 0) {
|
while (length > 0) {
|
||||||
int len = data_disks * chunk_size;
|
int len = data_disks * chunk_size;
|
||||||
unsigned long long offset;
|
unsigned long long offset;
|
||||||
|
int disk, qdisk;
|
||||||
if (length < len)
|
if (length < len)
|
||||||
return -3;
|
return -3;
|
||||||
for (i=0; i < data_disks; i++) {
|
for (i=0; i < data_disks; i++) {
|
||||||
|
@ -207,11 +234,22 @@ int restore_stripes(int *dest, unsigned long long *offsets,
|
||||||
}
|
}
|
||||||
/* We have the data, now do the parity */
|
/* We have the data, now do the parity */
|
||||||
offset = (start/chunk_size/data_disks) * chunk_size;
|
offset = (start/chunk_size/data_disks) * chunk_size;
|
||||||
if (level >= 4) {
|
switch (level) {
|
||||||
int disk = geo_map(-1, start/chunk_size/data_disks,
|
case 4:
|
||||||
|
case 5:
|
||||||
|
disk = geo_map(-1, start/chunk_size/data_disks,
|
||||||
raid_disks, level, layout);
|
raid_disks, level, layout);
|
||||||
xor_blocks(stripes[disk], blocks, data_disks, chunk_size);
|
xor_blocks(stripes[disk], blocks, data_disks, chunk_size);
|
||||||
/* FIXME need to do raid6 Q as well */
|
break;
|
||||||
|
case 6:
|
||||||
|
disk = geo_map(-1, start/chunk_size/data_disks,
|
||||||
|
raid_disks, level, layout);
|
||||||
|
qdisk = geo_map(-2, start/chunk_size/data_disks,
|
||||||
|
raid_disks, level, layout);
|
||||||
|
|
||||||
|
qsyndrome(stripes[disk], stripes[qdisk], blocks,
|
||||||
|
data_disks, chunk_size);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
for (i=0; i < raid_disks ; i++)
|
for (i=0; i < raid_disks ; i++)
|
||||||
if (dest[i] >= 0) {
|
if (dest[i] >= 0) {
|
||||||
|
@ -228,6 +266,58 @@ int restore_stripes(int *dest, unsigned long long *offsets,
|
||||||
|
|
||||||
#ifdef MAIN
|
#ifdef MAIN
|
||||||
|
|
||||||
|
int test_stripes(int *source, unsigned long long *offsets,
|
||||||
|
int raid_disks, int chunk_size, int level, int layout,
|
||||||
|
unsigned long long start, unsigned long long length)
|
||||||
|
{
|
||||||
|
/* ready the data and p (and q) blocks, and check we got them right */
|
||||||
|
char *stripe_buf = malloc(raid_disks * chunk_size);
|
||||||
|
char **stripes = malloc(raid_disks * sizeof(char*));
|
||||||
|
char **blocks = malloc(raid_disks * sizeof(char*));
|
||||||
|
char *p = malloc(chunk_size);
|
||||||
|
char *q = malloc(chunk_size);
|
||||||
|
|
||||||
|
int i;
|
||||||
|
int data_disks = raid_disks - (level == 5 ? 1: 2);
|
||||||
|
for ( i = 0 ; i < raid_disks ; i++)
|
||||||
|
stripes[i] = stripe_buf + i * chunk_size;
|
||||||
|
|
||||||
|
while (length > 0) {
|
||||||
|
int disk;
|
||||||
|
|
||||||
|
for (i = 0 ; i < raid_disks ; i++) {
|
||||||
|
lseek64(source[i], offsets[i]+start, 0);
|
||||||
|
read(source[i], stripes[i], chunk_size);
|
||||||
|
}
|
||||||
|
for (i = 0 ; i < data_disks ; i++) {
|
||||||
|
int disk = geo_map(i, start/chunk_size, raid_disks,
|
||||||
|
level, layout);
|
||||||
|
blocks[i] = stripes[disk];
|
||||||
|
printf("%d->%d\n", i, disk);
|
||||||
|
}
|
||||||
|
switch(level) {
|
||||||
|
case 6:
|
||||||
|
qsyndrome(p, q, blocks, data_disks, chunk_size);
|
||||||
|
disk = geo_map(-1, start/chunk_size, raid_disks,
|
||||||
|
level, layout);
|
||||||
|
if (memcmp(p, stripes[disk], chunk_size) != 0) {
|
||||||
|
printf("P(%d) wrong at %llu\n", disk,
|
||||||
|
start / chunk_size);
|
||||||
|
}
|
||||||
|
disk = geo_map(-2, start/chunk_size, raid_disks,
|
||||||
|
level, layout);
|
||||||
|
if (memcmp(q, stripes[disk], chunk_size) != 0) {
|
||||||
|
printf("Q(%d) wrong at %llu\n", disk,
|
||||||
|
start / chunk_size);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
length -= chunk_size;
|
||||||
|
start += chunk_size;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned long long getnum(char *str, char **err)
|
unsigned long long getnum(char *str, char **err)
|
||||||
{
|
{
|
||||||
char *e;
|
char *e;
|
||||||
|
@ -262,6 +352,8 @@ main(int argc, char *argv[])
|
||||||
save = 1;
|
save = 1;
|
||||||
else if (strcmp(argv[1], "restore") == 0)
|
else if (strcmp(argv[1], "restore") == 0)
|
||||||
save = 0;
|
save = 0;
|
||||||
|
else if (strcmp(argv[1], "test") == 0)
|
||||||
|
save = 2;
|
||||||
else {
|
else {
|
||||||
fprintf(stderr, "test_stripe: must give 'save' or 'restore'.\n");
|
fprintf(stderr, "test_stripe: must give 'save' or 'restore'.\n");
|
||||||
exit(2);
|
exit(2);
|
||||||
|
@ -302,13 +394,23 @@ main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (save) {
|
if (save == 1) {
|
||||||
int rv = save_stripes(fds, offsets,
|
int rv = save_stripes(fds, offsets,
|
||||||
raid_disks, chunk_size, level, layout,
|
raid_disks, chunk_size, level, layout,
|
||||||
1, &storefd,
|
1, &storefd,
|
||||||
start, length);
|
start, length);
|
||||||
if (rv != 0) {
|
if (rv != 0) {
|
||||||
fprintf(stderr, "test_stripe: save_stripes returned %d\n", rv);
|
fprintf(stderr,
|
||||||
|
"test_stripe: save_stripes returned %d\n", rv);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
} else if (save == 2) {
|
||||||
|
int rv = test_stripes(fds, offsets,
|
||||||
|
raid_disks, chunk_size, level, layout,
|
||||||
|
start, length);
|
||||||
|
if (rv != 0) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"test_stripe: test_stripes returned %d\n", rv);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -317,7 +419,9 @@ main(int argc, char *argv[])
|
||||||
storefd, 0ULL,
|
storefd, 0ULL,
|
||||||
start, length);
|
start, length);
|
||||||
if (rv != 0) {
|
if (rv != 0) {
|
||||||
fprintf(stderr, "test_stripe: restore_stripes returned %d\n", rv);
|
fprintf(stderr,
|
||||||
|
"test_stripe: restore_stripes returned %d\n",
|
||||||
|
rv);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue