mirror of
https://github.com/amadvance/snapraid.git
synced 2026-10-26 10:51:54 -04:00
Merge branch 'quadparity'
This commit is contained in:
commit
7a1fdf151b
9 changed files with 1602 additions and 713 deletions
485
check.c
485
check.c
|
|
@ -89,6 +89,106 @@ static int blockcmp(struct snapraid_state* state, int rehash, struct snapraid_bl
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Combinations of 1 of 4 elements.
|
||||
*/
|
||||
static const struct combo1 {
|
||||
int a;
|
||||
} COMBO1[] = {
|
||||
{ 0 },
|
||||
{ 1 },
|
||||
{ 2 },
|
||||
{ 3 },
|
||||
};
|
||||
|
||||
/**
|
||||
* Combinations of 2 of 4 elements.
|
||||
*/
|
||||
static const struct combo2 {
|
||||
int a;
|
||||
int b;
|
||||
} COMBO2[] = {
|
||||
{ 0, 1 },
|
||||
{ 0, 2 },
|
||||
{ 0, 3 },
|
||||
{ 1, 2 },
|
||||
{ 1, 3 },
|
||||
{ 2, 3 }
|
||||
};
|
||||
|
||||
/**
|
||||
* Combinations of 3 of 4 elements.
|
||||
*/
|
||||
static const struct combo3 {
|
||||
int a;
|
||||
int b;
|
||||
int c;
|
||||
} COMBO3[] = {
|
||||
{ 0, 1, 2 },
|
||||
{ 0, 1, 3 },
|
||||
{ 0, 2, 3 },
|
||||
{ 1, 2, 3 }
|
||||
};
|
||||
|
||||
/**
|
||||
* Combinations of 4 of 4 elements.
|
||||
*/
|
||||
static const struct combo4 {
|
||||
int a;
|
||||
int b;
|
||||
int c;
|
||||
int d;
|
||||
} COMBO4[] = {
|
||||
{ 0, 1, 2, 4 },
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if the hash of at least one failed block is now matching.
|
||||
*/
|
||||
static int is_hash_matching(struct snapraid_state* state, int rehash, unsigned diskmax, struct failed_struct* failed, unsigned* failed_map, unsigned failed_count, unsigned char** buffer, unsigned char* buffer_zero)
|
||||
{
|
||||
unsigned j;
|
||||
int hash_checked;
|
||||
|
||||
hash_checked = 0; /* keep track if we check at least one block */
|
||||
|
||||
/* check if the recovered blocks are OK */
|
||||
for(j=0;j<failed_count;++j) {
|
||||
if (block_has_updated_hash(failed[failed_map[j]].block)) { /* if the block can be checked */
|
||||
hash_checked = 1;
|
||||
if (blockcmp(state, rehash, failed[failed_map[j]].block, buffer[failed[failed_map[j]].index], buffer_zero) != 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* if we checked something, and no block failed the check */
|
||||
if (hash_checked && j==failed_count) {
|
||||
/* recompute all the redundancy information */
|
||||
raid_gen(state->level, buffer, diskmax, state->block_size);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if specified parity is now matching with a recomputed one.
|
||||
*/
|
||||
static int is_parity_matching(struct snapraid_state* state, unsigned diskmax, unsigned i, unsigned char** buffer, unsigned char** buffer_recov)
|
||||
{
|
||||
/* recompute parity, note that we don't need parity over i */
|
||||
raid_gen(i + 1, buffer, diskmax, state->block_size);
|
||||
|
||||
/* if the recovered parity block matches */
|
||||
if (memcmp(buffer[diskmax+i], buffer_recov[i], state->block_size) == 0) {
|
||||
/* recompute all the redundancy information */
|
||||
raid_gen(state->level, buffer, diskmax, state->block_size);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Repair errors.
|
||||
* Returns <0 if failure for missing strategy, >0 if data is wrong and we cannot rebuild correctly, 0 on success.
|
||||
|
|
@ -96,13 +196,9 @@ static int blockcmp(struct snapraid_state* state, int rehash, struct snapraid_bl
|
|||
*/
|
||||
static int repair_step(struct snapraid_state* state, int rehash, unsigned pos, unsigned diskmax, struct failed_struct* failed, unsigned* failed_map, unsigned failed_count, unsigned char** buffer, unsigned char** buffer_recov, unsigned char* buffer_zero)
|
||||
{
|
||||
unsigned j;
|
||||
int error = 0;
|
||||
unsigned i, j;
|
||||
int error;
|
||||
int has_hash;
|
||||
int hash_checked;
|
||||
unsigned char* buffer_parity = buffer_recov[0];
|
||||
unsigned char* buffer_qarity = buffer_recov[1];
|
||||
unsigned char* buffer_rarity = buffer_recov[2];
|
||||
|
||||
/* no fix required */
|
||||
if (failed_count == 0) {
|
||||
|
|
@ -111,6 +207,8 @@ static int repair_step(struct snapraid_state* state, int rehash, unsigned pos, u
|
|||
return 0;
|
||||
}
|
||||
|
||||
error = 0;
|
||||
|
||||
/* check if there is at least a failed block that can be checked for correctness using the hash */
|
||||
/* if there isn't, we have to sacrifice a parity block to check that the result is correct */
|
||||
has_hash = 0;
|
||||
|
|
@ -119,288 +217,160 @@ static int repair_step(struct snapraid_state* state, int rehash, unsigned pos, u
|
|||
has_hash = 1;
|
||||
}
|
||||
|
||||
/* RAID5 recovering from p */
|
||||
if (failed_count == 1 && buffer_parity != 0 && has_hash) {
|
||||
/* copy the redundancy to use */
|
||||
memcpy(buffer[diskmax], buffer_parity, state->block_size);
|
||||
/* recover one block with hash */
|
||||
if (failed_count == 1 && has_hash) {
|
||||
for(i=0;i<sizeof(COMBO1)/sizeof(COMBO1[0]);++i) {
|
||||
/* if parity is missing, do nothing */
|
||||
if (buffer_recov[COMBO1[i].a] == 0)
|
||||
continue;
|
||||
|
||||
/* recover data */
|
||||
raid5_recov_data(buffer, diskmax, state->block_size, failed[failed_map[0]].index);
|
||||
/* copy the redundancy to use */
|
||||
memcpy(buffer[diskmax+COMBO1[i].a], buffer_recov[COMBO1[i].a], state->block_size);
|
||||
|
||||
hash_checked = 0; /* keep track if we check at least one block */
|
||||
/* recover data */
|
||||
raid_recov_1data(buffer, diskmax, state->block_size, failed[failed_map[0]].index, COMBO1[i].a, buffer_zero);
|
||||
|
||||
/* check if the recovered blocks are OK */
|
||||
for(j=0;j<failed_count;++j) {
|
||||
if (block_has_updated_hash(failed[failed_map[j]].block)) { /* if the block can be checked */
|
||||
hash_checked = 1;
|
||||
if (blockcmp(state, rehash, failed[failed_map[j]].block, buffer[failed[failed_map[j]].index], buffer_zero) != 0)
|
||||
break;
|
||||
}
|
||||
if (is_hash_matching(state, rehash, diskmax, failed, failed_map, failed_count, buffer, buffer_zero))
|
||||
return 0;
|
||||
|
||||
fprintf(stdlog, "error:%u:%s: Data error\n", pos, lev_config_name(COMBO1[i].a));
|
||||
++error;
|
||||
}
|
||||
|
||||
/* if we checked something, and no block failed the check */
|
||||
if (hash_checked && j==failed_count) {
|
||||
/* recompute all the redundancy information */
|
||||
raid_gen(state->level, buffer, diskmax, state->block_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fprintf(stdlog, "error:%u:parity: Data error\n", pos);
|
||||
++error;
|
||||
}
|
||||
|
||||
/* RAID6 recovering from q, ignoring p */
|
||||
if (failed_count == 1 && buffer_qarity != 0 && has_hash) {
|
||||
/* copy the redundancy to use */
|
||||
memcpy(buffer[diskmax+1], buffer_qarity, state->block_size);
|
||||
/* recover one block without hash */
|
||||
if (failed_count == 1 && !has_hash) {
|
||||
for(i=0;i<sizeof(COMBO2)/sizeof(COMBO2[0]);++i) {
|
||||
/* if parity is missing, do nothing */
|
||||
if (buffer_recov[COMBO2[i].a] == 0 || buffer_recov[COMBO2[i].b] == 0)
|
||||
continue;
|
||||
|
||||
/* recover data */
|
||||
raid6_recov_datap(buffer, diskmax, state->block_size, failed[failed_map[0]].index, buffer_zero);
|
||||
/* copy the redundancy to use */
|
||||
memcpy(buffer[diskmax+COMBO2[i].a], buffer_recov[COMBO2[i].a], state->block_size);
|
||||
|
||||
hash_checked = 0; /* keep track if we check at least one block */
|
||||
/* recover data */
|
||||
raid_recov_1data(buffer, diskmax, state->block_size, failed[failed_map[0]].index, COMBO2[i].a, buffer_zero);
|
||||
|
||||
/* check if the recovered blocks are OK */
|
||||
for(j=0;j<failed_count;++j) {
|
||||
if (block_has_updated_hash(failed[failed_map[j]].block)) { /* if the block can be checked */
|
||||
hash_checked = 1;
|
||||
if (blockcmp(state, rehash, failed[failed_map[j]].block, buffer[failed[failed_map[j]].index], buffer_zero) != 0)
|
||||
break;
|
||||
}
|
||||
if (is_parity_matching(state, diskmax, COMBO2[i].b, buffer, buffer_recov))
|
||||
return 0;
|
||||
|
||||
fprintf(stdlog, "error:%u:%s/%s: Data error\n", pos, lev_config_name(COMBO2[i].a), lev_config_name(COMBO2[i].b));
|
||||
++error;
|
||||
}
|
||||
|
||||
/* if we checked something, and no block failed the check */
|
||||
if (hash_checked && j==failed_count) {
|
||||
/* recompute all the redundancy information */
|
||||
raid_gen(state->level, buffer, diskmax, state->block_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fprintf(stdlog, "error:%u:q-parity: Data error\n", pos);
|
||||
++error;
|
||||
}
|
||||
|
||||
/* RAID6 recovering from q, using p to check the result */
|
||||
if (failed_count == 1 && buffer_parity != 0 && buffer_qarity != 0 && !has_hash) {
|
||||
/* copy the redundancy to use */
|
||||
memcpy(buffer[diskmax+1], buffer_qarity, state->block_size);
|
||||
/* recover two blocks with hash */
|
||||
if (failed_count == 2 && has_hash) {
|
||||
for(i=0;i<sizeof(COMBO2)/sizeof(COMBO2[0]);++i) {
|
||||
/* if parity is missing, do nothing */
|
||||
if (buffer_recov[COMBO2[i].a] == 0 || buffer_recov[COMBO2[i].b] == 0)
|
||||
continue;
|
||||
|
||||
/* recover data */
|
||||
raid6_recov_datap(buffer, diskmax, state->block_size, failed[failed_map[0]].index, buffer_zero);
|
||||
/* copy the redundancy to use */
|
||||
memcpy(buffer[diskmax+COMBO2[i].a], buffer_recov[COMBO2[i].a], state->block_size);
|
||||
memcpy(buffer[diskmax+COMBO2[i].b], buffer_recov[COMBO2[i].b], state->block_size);
|
||||
|
||||
/* recompute parity with RAID5 to get p from it */
|
||||
raid_gen(1, buffer, diskmax, state->block_size);
|
||||
/* recover data */
|
||||
raid_recov_2data(buffer, diskmax, state->block_size, failed[failed_map[0]].index, failed[failed_map[1]].index, COMBO2[i].a, COMBO2[i].b, buffer_zero);
|
||||
|
||||
/* if the recovered parity block matches */
|
||||
if (memcmp(buffer[diskmax], buffer_parity, state->block_size) == 0) {
|
||||
/* recompute all the redundancy information */
|
||||
raid_gen(state->level, buffer, diskmax, state->block_size);
|
||||
return 0;
|
||||
if (is_hash_matching(state, rehash, diskmax, failed, failed_map, failed_count, buffer, buffer_zero))
|
||||
return 0;
|
||||
|
||||
fprintf(stdlog, "error:%u:%s/%s: Data error\n", pos, lev_config_name(COMBO2[i].a), lev_config_name(COMBO2[i].b));
|
||||
++error;
|
||||
}
|
||||
|
||||
fprintf(stdlog, "error:%u:parity/q-parity: Data error\n", pos);
|
||||
++error;
|
||||
}
|
||||
|
||||
/* RAID6 recovering from p+q */
|
||||
if (failed_count == 2 && buffer_parity != 0 && buffer_qarity != 0 && has_hash) {
|
||||
/* copy the redundancy to use */
|
||||
memcpy(buffer[diskmax], buffer_parity, state->block_size);
|
||||
memcpy(buffer[diskmax+1], buffer_qarity, state->block_size);
|
||||
/* recover two blocks without hash */
|
||||
if (failed_count == 2 && !has_hash) {
|
||||
for(i=0;i<sizeof(COMBO3)/sizeof(COMBO3[0]);++i) {
|
||||
/* if parity is missing, do nothing */
|
||||
if (buffer_recov[COMBO3[i].a] == 0 || buffer_recov[COMBO3[i].b] == 0 || buffer_recov[COMBO3[i].c] == 0)
|
||||
continue;
|
||||
|
||||
/* recover 2 data */
|
||||
raid6_recov_2data(buffer, diskmax, state->block_size, failed[failed_map[0]].index, failed[failed_map[1]].index, buffer_zero);
|
||||
/* copy the redundancy to use */
|
||||
memcpy(buffer[diskmax+COMBO3[i].a], buffer_recov[COMBO3[i].a], state->block_size);
|
||||
memcpy(buffer[diskmax+COMBO3[i].b], buffer_recov[COMBO3[i].b], state->block_size);
|
||||
|
||||
hash_checked = 0; /* keep track if we check at least one block */
|
||||
/* recover data */
|
||||
raid_recov_2data(buffer, diskmax, state->block_size, failed[failed_map[0]].index, failed[failed_map[1]].index, COMBO3[i].a, COMBO3[i].b, buffer_zero);
|
||||
|
||||
/* check if the recovered blocks are OK */
|
||||
for(j=0;j<failed_count;++j) {
|
||||
if (block_has_updated_hash(failed[failed_map[j]].block)) { /* if the block can be checked */
|
||||
hash_checked = 1;
|
||||
if (blockcmp(state, rehash, failed[failed_map[j]].block, buffer[failed[failed_map[j]].index], buffer_zero) != 0)
|
||||
break;
|
||||
}
|
||||
if (is_parity_matching(state, diskmax, COMBO3[i].c, buffer, buffer_recov))
|
||||
return 0;
|
||||
|
||||
fprintf(stdlog, "error:%u:%s/%s/%s: Data error\n", pos, lev_config_name(COMBO3[i].a), lev_config_name(COMBO3[i].b), lev_config_name(COMBO3[i].c));
|
||||
++error;
|
||||
}
|
||||
|
||||
/* if we checked something, and no block failed the check */
|
||||
if (hash_checked && j==failed_count) {
|
||||
/* recompute all the redundancy information */
|
||||
raid_gen(state->level, buffer, diskmax, state->block_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fprintf(stdlog, "error:%u:parity/q-parity: Data error\n", pos);
|
||||
++error;
|
||||
}
|
||||
|
||||
/* RAIDTP recovering from r, ignoring p,q */
|
||||
if (failed_count == 1 && buffer_rarity != 0 && has_hash) {
|
||||
/* copy the redundancy to use */
|
||||
memcpy(buffer[diskmax+2], buffer_rarity, state->block_size);
|
||||
/* recover three blocks with hash */
|
||||
if (failed_count == 3 && has_hash) {
|
||||
for(i=0;i<sizeof(COMBO3)/sizeof(COMBO3[0]);++i) {
|
||||
/* if parity is missing, do nothing */
|
||||
if (buffer_recov[COMBO3[i].a] == 0 || buffer_recov[COMBO3[i].b] == 0 || buffer_recov[COMBO3[i].c] == 0)
|
||||
continue;
|
||||
|
||||
/* recover data */
|
||||
raidTP_recov_datapq(buffer, diskmax, state->block_size, failed[failed_map[0]].index, buffer_zero);
|
||||
/* copy the redundancy to use */
|
||||
memcpy(buffer[diskmax+COMBO3[i].a], buffer_recov[COMBO3[i].a], state->block_size);
|
||||
memcpy(buffer[diskmax+COMBO3[i].b], buffer_recov[COMBO3[i].b], state->block_size);
|
||||
memcpy(buffer[diskmax+COMBO3[i].c], buffer_recov[COMBO3[i].c], state->block_size);
|
||||
|
||||
hash_checked = 0; /* keep track if we check at least one block */
|
||||
/* recover data */
|
||||
raid_recov_3data(buffer, diskmax, state->block_size, failed[failed_map[0]].index, failed[failed_map[1]].index, failed[failed_map[2]].index, COMBO3[i].a, COMBO3[i].b, COMBO3[i].c, buffer_zero);
|
||||
|
||||
/* check if the recovered blocks are OK */
|
||||
for(j=0;j<failed_count;++j) {
|
||||
if (block_has_updated_hash(failed[failed_map[j]].block)) { /* if the block can be checked */
|
||||
hash_checked = 1;
|
||||
if (blockcmp(state, rehash, failed[failed_map[j]].block, buffer[failed[failed_map[j]].index], buffer_zero) != 0)
|
||||
break;
|
||||
}
|
||||
if (is_hash_matching(state, rehash, diskmax, failed, failed_map, failed_count, buffer, buffer_zero))
|
||||
return 0;
|
||||
|
||||
fprintf(stdlog, "error:%u:%s/%s/%s: Data error\n", pos, lev_config_name(COMBO3[i].a), lev_config_name(COMBO3[i].b), lev_config_name(COMBO3[i].c));
|
||||
++error;
|
||||
}
|
||||
|
||||
/* if we checked something, and no block failed the check */
|
||||
if (hash_checked && j==failed_count) {
|
||||
/* recompute all the redundancy information */
|
||||
raid_gen(state->level, buffer, diskmax, state->block_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fprintf(stdlog, "error:%u:rarity: Data error\n", pos);
|
||||
++error;
|
||||
}
|
||||
|
||||
/* RAIDTP recovering from r, using p or q to check the result */
|
||||
if (failed_count == 1 && (buffer_parity != 0 || buffer_qarity != 0) && buffer_rarity != 0 && !has_hash) {
|
||||
/* copy the redundancy to use */
|
||||
memcpy(buffer[diskmax+2], buffer_rarity, state->block_size);
|
||||
/* recover three blocks without hash */
|
||||
if (failed_count == 3 && !has_hash) {
|
||||
for(i=0;i<sizeof(COMBO4)/sizeof(COMBO4[0]);++i) {
|
||||
/* if parity is missing, do nothing */
|
||||
if (buffer_recov[COMBO4[i].a] == 0 || buffer_recov[COMBO4[i].b] == 0 || buffer_recov[COMBO4[i].c] == 0 || buffer_recov[COMBO4[i].d] == 0)
|
||||
continue;
|
||||
|
||||
/* recover data */
|
||||
raidTP_recov_datapq(buffer, diskmax, state->block_size, failed[failed_map[0]].index, buffer_zero);
|
||||
/* copy the redundancy to use */
|
||||
memcpy(buffer[diskmax+COMBO4[i].a], buffer_recov[COMBO4[i].a], state->block_size);
|
||||
memcpy(buffer[diskmax+COMBO4[i].b], buffer_recov[COMBO4[i].b], state->block_size);
|
||||
memcpy(buffer[diskmax+COMBO4[i].c], buffer_recov[COMBO4[i].c], state->block_size);
|
||||
|
||||
/* recompute parity with RAID6 to get p and q from it */
|
||||
raid_gen(2, buffer, diskmax, state->block_size);
|
||||
/* recover data */
|
||||
raid_recov_3data(buffer, diskmax, state->block_size, failed[failed_map[0]].index, failed[failed_map[1]].index, failed[failed_map[2]].index, COMBO4[i].a, COMBO4[i].b, COMBO4[i].c, buffer_zero);
|
||||
|
||||
/* if the recovered parity block matches */
|
||||
if ((buffer_parity != 0 && memcmp(buffer[diskmax], buffer_parity, state->block_size) == 0)
|
||||
|| (buffer_qarity != 0 && memcmp(buffer[diskmax+1], buffer_qarity, state->block_size) == 0)
|
||||
) {
|
||||
/* recompute all the redundancy information */
|
||||
raid_gen(state->level, buffer, diskmax, state->block_size);
|
||||
return 0;
|
||||
if (is_parity_matching(state, diskmax, COMBO4[i].d, buffer, buffer_recov))
|
||||
return 0;
|
||||
|
||||
fprintf(stdlog, "error:%u:%s/%s/%s/%s: Data error\n", pos, lev_config_name(COMBO4[i].a), lev_config_name(COMBO4[i].b), lev_config_name(COMBO4[i].c), lev_config_name(COMBO4[i].d));
|
||||
++error;
|
||||
}
|
||||
|
||||
fprintf(stdlog, "error:%u:parity/qarity/rarity: Data error\n", pos);
|
||||
++error;
|
||||
}
|
||||
|
||||
/* RAIDTP recovering from p+r */
|
||||
if (failed_count == 2 && buffer_parity != 0 && buffer_rarity != 0 && has_hash) {
|
||||
/* copy the redundancy to use */
|
||||
memcpy(buffer[diskmax], buffer_parity, state->block_size);
|
||||
memcpy(buffer[diskmax+2], buffer_rarity, state->block_size);
|
||||
/* recover four blocks with hash */
|
||||
if (failed_count == 4 && has_hash) {
|
||||
for(i=0;i<sizeof(COMBO4)/sizeof(COMBO4[0]);++i) {
|
||||
/* if parity is missing, do nothing */
|
||||
if (buffer_recov[COMBO4[i].a] == 0 || buffer_recov[COMBO4[i].b] == 0 || buffer_recov[COMBO4[i].c] == 0 || buffer_recov[COMBO4[i].d] == 0)
|
||||
continue;
|
||||
|
||||
/* recover 2 data */
|
||||
raidTP_recov_2dataq(buffer, diskmax, state->block_size, failed[failed_map[0]].index, failed[failed_map[1]].index, buffer_zero);
|
||||
/* copy the redundancy to use */
|
||||
memcpy(buffer[diskmax+COMBO4[i].a], buffer_recov[COMBO4[i].a], state->block_size);
|
||||
memcpy(buffer[diskmax+COMBO4[i].b], buffer_recov[COMBO4[i].b], state->block_size);
|
||||
memcpy(buffer[diskmax+COMBO4[i].c], buffer_recov[COMBO4[i].c], state->block_size);
|
||||
memcpy(buffer[diskmax+COMBO4[i].d], buffer_recov[COMBO4[i].d], state->block_size);
|
||||
|
||||
hash_checked = 0; /* keep track if we check at least one block */
|
||||
/* recover data */
|
||||
raid_recov_4data(buffer, diskmax, state->block_size, failed[failed_map[0]].index, failed[failed_map[1]].index, failed[failed_map[2]].index, failed[failed_map[3]].index, COMBO4[i].a, COMBO4[i].b, COMBO4[i].c, COMBO4[i].d, buffer_zero);
|
||||
|
||||
/* check if the recovered blocks are OK */
|
||||
for(j=0;j<failed_count;++j) {
|
||||
if (block_has_updated_hash(failed[failed_map[j]].block)) { /* if the block can be checked */
|
||||
hash_checked = 1;
|
||||
if (blockcmp(state, rehash, failed[failed_map[j]].block, buffer[failed[failed_map[j]].index], buffer_zero) != 0)
|
||||
break;
|
||||
}
|
||||
if (is_hash_matching(state, rehash, diskmax, failed, failed_map, failed_count, buffer, buffer_zero))
|
||||
return 0;
|
||||
|
||||
fprintf(stdlog, "error:%u:%s/%s/%s/%s: Data error\n", pos, lev_config_name(COMBO4[i].a), lev_config_name(COMBO4[i].b), lev_config_name(COMBO4[i].c), lev_config_name(COMBO4[i].d));
|
||||
++error;
|
||||
}
|
||||
|
||||
/* if we checked something, and no block failed the check */
|
||||
if (hash_checked && j==failed_count) {
|
||||
/* recompute all the redundancy information */
|
||||
raid_gen(state->level, buffer, diskmax, state->block_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fprintf(stdlog, "error:%u:parity/rarity: Data error\n", pos);
|
||||
++error;
|
||||
}
|
||||
|
||||
/* RAIDTP recovering from q+r */
|
||||
if (failed_count == 2 && buffer_qarity != 0 && buffer_rarity != 0 && has_hash) {
|
||||
/* copy the redundancy to use */
|
||||
memcpy(buffer[diskmax+1], buffer_qarity, state->block_size);
|
||||
memcpy(buffer[diskmax+2], buffer_rarity, state->block_size);
|
||||
|
||||
/* recover 2 data */
|
||||
raidTP_recov_2datap(buffer, diskmax, state->block_size, failed[failed_map[0]].index, failed[failed_map[1]].index, buffer_zero);
|
||||
|
||||
hash_checked = 0; /* keep track if we check at least one block */
|
||||
|
||||
/* check if the recovered blocks are OK */
|
||||
for(j=0;j<failed_count;++j) {
|
||||
if (block_has_updated_hash(failed[failed_map[j]].block)) { /* if the block can be checked */
|
||||
hash_checked = 1;
|
||||
if (blockcmp(state, rehash, failed[failed_map[j]].block, buffer[failed[failed_map[j]].index], buffer_zero) != 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* if we checked something, and no block failed the check */
|
||||
if (hash_checked && j==failed_count) {
|
||||
/* recompute all the redundancy information */
|
||||
raid_gen(state->level, buffer, diskmax, state->block_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fprintf(stdlog, "error:%u:qarity/rarity: Data error\n", pos);
|
||||
++error;
|
||||
}
|
||||
|
||||
/* RAIDTP recovering from q+r, using p to check the result */
|
||||
if (failed_count == 2 && buffer_parity != 0 && buffer_qarity != 0 && buffer_rarity != 0 && !has_hash) {
|
||||
/* copy the redundancy to use */
|
||||
memcpy(buffer[diskmax+1], buffer_qarity, state->block_size);
|
||||
memcpy(buffer[diskmax+2], buffer_rarity, state->block_size);
|
||||
|
||||
/* recover data */
|
||||
raidTP_recov_2datap(buffer, diskmax, state->block_size, failed[failed_map[0]].index, failed[failed_map[1]].index, buffer_zero);
|
||||
|
||||
/* recompute parity with RAID5 to get p from it */
|
||||
raid_gen(1, buffer, diskmax, state->block_size);
|
||||
|
||||
/* if the recovered parity block matches */
|
||||
if (buffer_parity != 0 && memcmp(buffer[diskmax], buffer_parity, state->block_size) == 0) {
|
||||
/* recompute all the redundancy information */
|
||||
raid_gen(state->level, buffer, diskmax, state->block_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fprintf(stdlog, "error:%u:parity/qarity/rarity: Data error\n", pos);
|
||||
++error;
|
||||
}
|
||||
|
||||
/* RAIDTP recovering from p+q+r */
|
||||
if (failed_count == 3 && buffer_parity != 0 && buffer_qarity != 0 && buffer_rarity != 0 && has_hash) {
|
||||
/* copy the redundancy to use */
|
||||
memcpy(buffer[diskmax], buffer_parity, state->block_size);
|
||||
memcpy(buffer[diskmax+1], buffer_qarity, state->block_size);
|
||||
memcpy(buffer[diskmax+2], buffer_rarity, state->block_size);
|
||||
|
||||
/* recover 3 data */
|
||||
raidTP_recov_3data(buffer, diskmax, state->block_size, failed[failed_map[0]].index, failed[failed_map[1]].index, failed[failed_map[2]].index, buffer_zero);
|
||||
|
||||
hash_checked = 0; /* keep track if we check at least one block */
|
||||
|
||||
/* check if the recovered blocks are OK */
|
||||
for(j=0;j<failed_count;++j) {
|
||||
if (block_has_updated_hash(failed[failed_map[j]].block)) { /* if the block can be checked */
|
||||
hash_checked = 1;
|
||||
if (blockcmp(state, rehash, failed[failed_map[j]].block, buffer[failed[failed_map[j]].index], buffer_zero) != 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* if we checked something, and no block failed the check */
|
||||
if (hash_checked && j==failed_count) {
|
||||
/* recompute all the redundancy information */
|
||||
raid_gen(state->level, buffer, diskmax, state->block_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fprintf(stdlog, "error:%u:parity/qarity/rarity: Data error\n", pos);
|
||||
++error;
|
||||
}
|
||||
|
||||
/* return the number of failed attempts, or -1 if no strategy */
|
||||
|
|
@ -914,19 +884,12 @@ static int state_check_process(struct snapraid_state* state, int check, int fix,
|
|||
unsigned char* buffer_zero;
|
||||
|
||||
/* buffers for parity read and not computed */
|
||||
if (state->level == 1) {
|
||||
buffer_recov[0] = buffer[diskmax + 1];
|
||||
buffer_recov[1] = 0;
|
||||
buffer_recov[2] = 0;
|
||||
} else if (state->level == 2) {
|
||||
buffer_recov[0] = buffer[diskmax + 2];
|
||||
buffer_recov[1] = buffer[diskmax + 3];
|
||||
buffer_recov[2] = 0;
|
||||
} else {
|
||||
buffer_recov[0] = buffer[diskmax + 3];
|
||||
buffer_recov[1] = buffer[diskmax + 4];
|
||||
buffer_recov[2] = buffer[diskmax + 5];
|
||||
}
|
||||
for(l=0;l<state->level;++l)
|
||||
buffer_recov[l] = buffer[diskmax + state->level + l];
|
||||
for(;l<LEV_MAX;++l)
|
||||
buffer_recov[l] = 0;
|
||||
|
||||
/* the zero buffer is the last one */
|
||||
buffer_zero = buffer[buffermax-1];
|
||||
|
||||
/* read the parity */
|
||||
|
|
|
|||
16
mktables.c
16
mktables.c
|
|
@ -98,6 +98,22 @@ int main(void)
|
|||
}
|
||||
printf("};\n\n");
|
||||
|
||||
/* 8^a */
|
||||
printf("const unsigned char __attribute__((aligned(256))) gfexp8[256] =\n");
|
||||
printf("{\n");
|
||||
v = 1;
|
||||
for(i=0;i<256;++i) {
|
||||
if (i % 8 == 0)
|
||||
printf("\t");
|
||||
printf("0x%02x,", v);
|
||||
v = gfmul(v, 8);
|
||||
if (i % 8 == 7)
|
||||
printf("\n");
|
||||
else
|
||||
printf(" ");
|
||||
}
|
||||
printf("};\n\n");
|
||||
|
||||
/* 1/a */
|
||||
printf("const unsigned char __attribute__((aligned(256))) gfinv[256] =\n");
|
||||
printf("{\n");
|
||||
|
|
|
|||
49
raid.h
49
raid.h
|
|
@ -21,49 +21,40 @@
|
|||
/****************************************************************************/
|
||||
/* raid */
|
||||
|
||||
/**
|
||||
* Max number of data disks for RAID6.
|
||||
*/
|
||||
#define RAID6_DATA_LIMIT 21
|
||||
|
||||
/**
|
||||
* Max number of data disks for RAIDQP.
|
||||
*/
|
||||
#define RAIDQP_DATA_LIMIT 21
|
||||
|
||||
/**
|
||||
* Syndrome computation.
|
||||
*/
|
||||
void raid_gen(unsigned level, unsigned char** buffer, unsigned diskmax, unsigned size);
|
||||
|
||||
/*
|
||||
* Recover failure of one data block.
|
||||
* Recover failure of one data block x using parity i.
|
||||
*/
|
||||
void raid5_recov_data(unsigned char** dptrs, unsigned diskmax, unsigned size, int faila);
|
||||
void raid_recov_1data(unsigned char** dptrs, unsigned diskmax, unsigned size, int x, int i, unsigned char* zero);
|
||||
|
||||
/*
|
||||
* Recover two failed data blocks.
|
||||
* Recover failure of two data blocks x,y using parity i,j.
|
||||
*/
|
||||
void raid6_recov_2data(unsigned char** dptrs, unsigned diskmax, unsigned size, int faila, int failb, unsigned char* zero);
|
||||
void raid_recov_2data(unsigned char** dptrs, unsigned diskmax, unsigned size, int x, int y, int i, int j, unsigned char* zero);
|
||||
|
||||
/*
|
||||
* Recover failure of one data block ignoring P.
|
||||
* Note that P content is not recovered.
|
||||
* Recover failure of three data blocks x,y,z using parity i,j,k.
|
||||
*/
|
||||
void raid6_recov_datap(unsigned char** dptrs, unsigned diskmax, unsigned size, int faila, unsigned char* zero);
|
||||
void raid_recov_3data(unsigned char** dptrs, unsigned diskmax, unsigned size, int x, int y, int z, int i, int j, int k, unsigned char* zero);
|
||||
|
||||
/*
|
||||
* Recover failure of one data block ignoring P and Q.
|
||||
* Note that P and Q content is not recovered.
|
||||
* Recover failure of four data blocks x,y,z,v using parity i,j,k,l.
|
||||
*/
|
||||
void raidTP_recov_datapq(unsigned char** dptrs, unsigned diskmax, unsigned size, int faila, unsigned char* zero);
|
||||
|
||||
/*
|
||||
* Recover failure of two data blocks ignoring P.
|
||||
* Note that P content is not recovered.
|
||||
*/
|
||||
void raidTP_recov_2datap(unsigned char** dptrs, unsigned diskmax, unsigned size, int faila, int failb, unsigned char* zero);
|
||||
|
||||
/*
|
||||
* Recover failure of two data blocks ignoring Q.
|
||||
* Note that Q content is not recovered.
|
||||
*/
|
||||
void raidTP_recov_2dataq(unsigned char** dptrs, unsigned diskmax, unsigned size, int faila, int failb, unsigned char* zero);
|
||||
|
||||
/*
|
||||
* Recover failure of three data blocks.
|
||||
*/
|
||||
void raidTP_recov_3data(unsigned char** dptrs, unsigned diskmax, unsigned size, int faila, int failb, int failc, unsigned char* zero);
|
||||
void raid_recov_4data(unsigned char** dptrs, unsigned diskmax, unsigned size, int x, int y, int z, int v, int i, int j, int k, int l, unsigned char* zero);
|
||||
|
||||
/**
|
||||
* Initializes the RAID system.
|
||||
|
|
@ -87,6 +78,10 @@ void raidTP_int32r2(unsigned char** dptr, unsigned diskmax, unsigned size);
|
|||
void raidTP_mmxr1(unsigned char** buffer, unsigned diskmax, unsigned size);
|
||||
void raidTP_sse2r1(unsigned char** dptr, unsigned diskmax, unsigned size);
|
||||
void raidTP_sse2r2(unsigned char** dptr, unsigned diskmax, unsigned size);
|
||||
void raidQP_int32r2(unsigned char** dptr, unsigned diskmax, unsigned size);
|
||||
void raidQP_mmxr1(unsigned char** buffer, unsigned diskmax, unsigned size);
|
||||
void raidQP_sse2r1(unsigned char** dptr, unsigned diskmax, unsigned size);
|
||||
void raidQP_sse2r2(unsigned char** buffer, unsigned diskmax, unsigned size);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
450
selftest.c
450
selftest.c
|
|
@ -20,6 +20,8 @@
|
|||
#include "snapraid.h"
|
||||
#include "util.h"
|
||||
#include "raid.h"
|
||||
#include "elem.h"
|
||||
#include "state.h"
|
||||
|
||||
struct hash_test_vector {
|
||||
const char* data;
|
||||
|
|
@ -43,170 +45,60 @@ static struct hash_test_vector TEST_SPOOKY2[] = {
|
|||
{ 0, 0, { 0 } }
|
||||
};
|
||||
|
||||
static void raid5test(unsigned diskmax, unsigned block_size)
|
||||
{
|
||||
void* buffer_alloc;
|
||||
unsigned char** buffer;
|
||||
unsigned char* buffer_test;
|
||||
unsigned buffermax;
|
||||
unsigned i, j;
|
||||
|
||||
buffermax = diskmax + 1 + 1;
|
||||
|
||||
buffer = malloc_nofail_vector_align(buffermax, block_size, &buffer_alloc);
|
||||
|
||||
buffer_test = buffer[buffermax-1];
|
||||
|
||||
/* fill with random */
|
||||
for(i=0;i<diskmax;++i) {
|
||||
for(j=0;j<block_size;++j)
|
||||
buffer[i][j] = rand();
|
||||
}
|
||||
|
||||
/* compute the parity */
|
||||
raid_gen(1, buffer, diskmax, block_size);
|
||||
|
||||
for(i=0;i<diskmax;++i) {
|
||||
unsigned char* a;
|
||||
|
||||
/* save */
|
||||
a = buffer[i];
|
||||
|
||||
/* damage */
|
||||
buffer[i] = buffer_test;
|
||||
|
||||
/* recover */
|
||||
raid5_recov_data(buffer, diskmax, block_size, i);
|
||||
|
||||
/* restore */
|
||||
buffer[i] = a;
|
||||
|
||||
/* check */
|
||||
if (memcmp(buffer_test, buffer[i], block_size) != 0) {
|
||||
fprintf(stderr, "Failed RAID5 test\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
free(buffer_alloc);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
static void raid6test(unsigned diskmax, unsigned block_size)
|
||||
{
|
||||
void* buffer_alloc;
|
||||
unsigned char** buffer;
|
||||
unsigned char* buffer_test0;
|
||||
unsigned char* buffer_test1;
|
||||
unsigned char* buffer_zero;
|
||||
unsigned char* buffer_bad;
|
||||
unsigned buffermax;
|
||||
unsigned i, j;
|
||||
|
||||
buffermax = diskmax + 2 + 2 + 1 + 1;
|
||||
|
||||
buffer = malloc_nofail_vector_align(buffermax, block_size, &buffer_alloc);
|
||||
|
||||
buffer_test0 = buffer[buffermax-4];
|
||||
buffer_test1 = buffer[buffermax-3];
|
||||
buffer_zero = buffer[buffermax-2];
|
||||
buffer_bad = buffer[buffermax-1];
|
||||
memset(buffer_zero, 0, block_size);
|
||||
memset(buffer_bad, 0xA5, block_size);
|
||||
|
||||
/* fill with random */
|
||||
for(i=0;i<diskmax;++i) {
|
||||
for(j=0;j<block_size;++j)
|
||||
buffer[i][j] = rand();
|
||||
}
|
||||
|
||||
/* compute the parity */
|
||||
raid_gen(2, buffer, diskmax, block_size);
|
||||
|
||||
/* check 2data */
|
||||
for(i=0;i<diskmax;++i) {
|
||||
for(j=i+1;j<diskmax;++j) {
|
||||
unsigned char* a;
|
||||
unsigned char* b;
|
||||
|
||||
/* save */
|
||||
a = buffer[i];
|
||||
b = buffer[j];
|
||||
|
||||
/* damage */
|
||||
buffer[i] = buffer_test0;
|
||||
buffer[j] = buffer_test1;
|
||||
|
||||
/* recover */
|
||||
raid6_recov_2data(buffer, diskmax, block_size, i, j, buffer_zero);
|
||||
|
||||
/* restore */
|
||||
buffer[i] = a;
|
||||
buffer[j] = b;
|
||||
|
||||
/* check */
|
||||
if (memcmp(buffer_test0, buffer[i], block_size) != 0
|
||||
|| memcmp(buffer_test1, buffer[j], block_size) != 0
|
||||
) {
|
||||
fprintf(stderr, "Failed RAID6 test\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* check datap */
|
||||
for(i=0;i<diskmax;++i) {
|
||||
unsigned char* a;
|
||||
unsigned char* p;
|
||||
|
||||
/* other is p */
|
||||
j = diskmax;
|
||||
|
||||
/* save */
|
||||
a = buffer[i];
|
||||
p = buffer[j];
|
||||
|
||||
/* damage */
|
||||
buffer[i] = buffer_test0;
|
||||
buffer[j] = buffer_bad;
|
||||
|
||||
/* recover */
|
||||
raid6_recov_datap(buffer, diskmax, block_size, i, buffer_zero);
|
||||
|
||||
/* restore */
|
||||
buffer[i] = a;
|
||||
buffer[j] = p;
|
||||
|
||||
/* check */
|
||||
if (memcmp(buffer_test0, buffer[i], block_size) != 0) {
|
||||
fprintf(stderr, "Failed RAID6 test\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
free(buffer_alloc);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
static void raidTPtest(unsigned diskmax, unsigned block_size)
|
||||
static void raidtest(unsigned diskmax, unsigned block_size)
|
||||
{
|
||||
void* buffer_alloc;
|
||||
unsigned char** buffer;
|
||||
unsigned char* buffer_test0;
|
||||
unsigned char* buffer_test1;
|
||||
unsigned char* buffer_test2;
|
||||
unsigned char* buffer_test3;
|
||||
unsigned char* buffer_zero;
|
||||
unsigned char* buffer_bad;
|
||||
unsigned buffermax;
|
||||
unsigned i, j, k;
|
||||
unsigned i, j, k, l;
|
||||
unsigned n;
|
||||
|
||||
buffermax = diskmax + 3 + 3 + 1 + 1;
|
||||
struct combo1 {
|
||||
int ignore[3];
|
||||
int use;
|
||||
} COMBO1[] = {
|
||||
{ { 1, 2, 3 }, 0 },
|
||||
{ { 0, 2, 3 }, 1 },
|
||||
{ { 0, 1, 3 }, 2 },
|
||||
{ { 0, 1, 2 }, 3 }
|
||||
};
|
||||
|
||||
struct combo2 {
|
||||
int ignore[2];
|
||||
int use[2];
|
||||
} COMBO2[] = {
|
||||
{ { 0, 1 }, { 2, 3 } },
|
||||
{ { 0, 2 }, { 1, 3 } },
|
||||
{ { 0, 3 }, { 1, 2 } },
|
||||
{ { 1, 2 }, { 0, 3 } },
|
||||
{ { 1, 3 }, { 0, 2 } },
|
||||
{ { 2, 3 }, { 0, 1 } }
|
||||
};
|
||||
|
||||
struct combo3 {
|
||||
int ignore;
|
||||
int use[3];
|
||||
} COMBO3[] = {
|
||||
{ 0, { 1, 2, 3 } },
|
||||
{ 1, { 0, 2, 3 } },
|
||||
{ 2, { 0, 1, 3 } },
|
||||
{ 3, { 0, 1, 2 } }
|
||||
};
|
||||
|
||||
buffermax = diskmax + LEV_MAX * 2 + 1 + 1;
|
||||
|
||||
buffer = malloc_nofail_vector_align(buffermax, block_size, &buffer_alloc);
|
||||
|
||||
buffer_test0 = buffer[buffermax-5];
|
||||
buffer_test1 = buffer[buffermax-4];
|
||||
buffer_test2 = buffer[buffermax-3];
|
||||
buffer_test0 = buffer[buffermax-6];
|
||||
buffer_test1 = buffer[buffermax-5];
|
||||
buffer_test2 = buffer[buffermax-4];
|
||||
buffer_test3 = buffer[buffermax-3];
|
||||
buffer_zero = buffer[buffermax-2];
|
||||
buffer_bad = buffer[buffermax-1];
|
||||
memset(buffer_zero, 0, block_size);
|
||||
|
|
@ -219,154 +111,194 @@ static void raidTPtest(unsigned diskmax, unsigned block_size)
|
|||
}
|
||||
|
||||
/* compute the parity */
|
||||
raid_gen(3, buffer, diskmax, block_size);
|
||||
raid_gen(LEV_MAX, buffer, diskmax, block_size);
|
||||
|
||||
/* check 3data */
|
||||
/* check 4data */
|
||||
for(i=0;i<diskmax;++i) {
|
||||
for(j=i+1;j<diskmax;++j) {
|
||||
for(k=j+1;k<diskmax;++k) {
|
||||
unsigned char* a;
|
||||
unsigned char* b;
|
||||
unsigned char* c;
|
||||
for(l=k+1;l<diskmax;++l) {
|
||||
unsigned char* a;
|
||||
unsigned char* b;
|
||||
unsigned char* c;
|
||||
unsigned char* d;
|
||||
|
||||
/* save */
|
||||
a = buffer[i];
|
||||
b = buffer[j];
|
||||
c = buffer[k];
|
||||
/* save */
|
||||
a = buffer[i];
|
||||
b = buffer[j];
|
||||
c = buffer[k];
|
||||
d = buffer[l];
|
||||
|
||||
/* damage */
|
||||
buffer[i] = buffer_test0;
|
||||
buffer[j] = buffer_test1;
|
||||
buffer[k] = buffer_test2;
|
||||
/* damage */
|
||||
buffer[i] = buffer_test0;
|
||||
buffer[j] = buffer_test1;
|
||||
buffer[k] = buffer_test2;
|
||||
buffer[l] = buffer_test3;
|
||||
|
||||
/* recover */
|
||||
raidTP_recov_3data(buffer, diskmax, block_size, i, j, k, buffer_zero);
|
||||
/* recover */
|
||||
raid_recov_4data(buffer, diskmax, block_size, i, j, k, l, 0, 1, 2, 3, buffer_zero);
|
||||
|
||||
/* restore */
|
||||
buffer[i] = a;
|
||||
buffer[j] = b;
|
||||
buffer[k] = c;
|
||||
/* check */
|
||||
if (memcmp(buffer_test0, a, block_size) != 0
|
||||
|| memcmp(buffer_test1, b, block_size) != 0
|
||||
|| memcmp(buffer_test2, c, block_size) != 0
|
||||
|| memcmp(buffer_test3, d, block_size) != 0
|
||||
) {
|
||||
fprintf(stderr, "Failed RAID test\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* check */
|
||||
if (memcmp(buffer_test0, buffer[i], block_size) != 0
|
||||
|| memcmp(buffer_test1, buffer[j], block_size) != 0
|
||||
|| memcmp(buffer_test2, buffer[k], block_size) != 0
|
||||
) {
|
||||
fprintf(stderr, "Failed RAIDTP test\n");
|
||||
exit(EXIT_FAILURE);
|
||||
/* restore */
|
||||
buffer[i] = a;
|
||||
buffer[j] = b;
|
||||
buffer[k] = c;
|
||||
buffer[l] = d;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* check 2dataq */
|
||||
/* check 3data */
|
||||
for(i=0;i<diskmax;++i) {
|
||||
for(j=i+1;j<diskmax;++j) {
|
||||
unsigned char* a;
|
||||
unsigned char* b;
|
||||
unsigned char* q;
|
||||
for(k=j+1;k<diskmax;++k) {
|
||||
for(n=0;n<sizeof(COMBO3)/sizeof(COMBO3[0]);++n) {
|
||||
unsigned char* a;
|
||||
unsigned char* b;
|
||||
unsigned char* c;
|
||||
unsigned char* p;
|
||||
|
||||
/* other is q */
|
||||
k = diskmax + 1;
|
||||
/* this is the point where quad parity fails over RAIDQP_DATA_LIMIT data disks */
|
||||
if (diskmax > RAIDQP_DATA_LIMIT && COMBO3[n].use[2] >= 3)
|
||||
continue;
|
||||
|
||||
/* save */
|
||||
a = buffer[i];
|
||||
b = buffer[j];
|
||||
q = buffer[k];
|
||||
/* save */
|
||||
a = buffer[i];
|
||||
b = buffer[j];
|
||||
c = buffer[k];
|
||||
|
||||
/* damage */
|
||||
buffer[i] = buffer_test0;
|
||||
buffer[j] = buffer_test1;
|
||||
buffer[k] = buffer_bad;
|
||||
/* damage */
|
||||
buffer[i] = buffer_test0;
|
||||
buffer[j] = buffer_test1;
|
||||
buffer[k] = buffer_test2;
|
||||
|
||||
/* recover */
|
||||
raidTP_recov_2dataq(buffer, diskmax, block_size, i, j, buffer_zero);
|
||||
/* ignore parity */
|
||||
l = diskmax + COMBO3[n].ignore;
|
||||
p = buffer[l];
|
||||
buffer[l] = buffer_bad;
|
||||
|
||||
/* restore */
|
||||
buffer[i] = a;
|
||||
buffer[j] = b;
|
||||
buffer[k] = q;
|
||||
/* recover ignoring p */
|
||||
raid_recov_3data(buffer, diskmax, block_size, i, j, k, COMBO3[n].use[0], COMBO3[n].use[1], COMBO3[n].use[2], buffer_zero);
|
||||
|
||||
/* check */
|
||||
if (memcmp(buffer_test0, buffer[i], block_size) != 0
|
||||
|| memcmp(buffer_test1, buffer[j], block_size) != 0
|
||||
) {
|
||||
fprintf(stderr, "Failed RAIDTP test\n");
|
||||
exit(EXIT_FAILURE);
|
||||
/* check */
|
||||
if (memcmp(buffer_test0, a, block_size) != 0
|
||||
|| memcmp(buffer_test1, b, block_size) != 0
|
||||
|| memcmp(buffer_test2, c, block_size) != 0
|
||||
) {
|
||||
fprintf(stderr, "Failed RAID test\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* restore parity */
|
||||
buffer[l] = p;
|
||||
|
||||
/* restore */
|
||||
buffer[i] = a;
|
||||
buffer[j] = b;
|
||||
buffer[k] = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* check 2datap */
|
||||
/* check 2data */
|
||||
for(i=0;i<diskmax;++i) {
|
||||
for(j=i+1;j<diskmax;++j) {
|
||||
for(n=0;n<sizeof(COMBO2)/sizeof(COMBO2[0]);++n) {
|
||||
unsigned char* a;
|
||||
unsigned char* b;
|
||||
unsigned char* p;
|
||||
unsigned char* q;
|
||||
|
||||
/* save */
|
||||
a = buffer[i];
|
||||
b = buffer[j];
|
||||
|
||||
/* damage */
|
||||
buffer[i] = buffer_test0;
|
||||
buffer[j] = buffer_test1;
|
||||
|
||||
/* ignore parity */
|
||||
k = diskmax + COMBO2[n].ignore[0];
|
||||
l = diskmax + COMBO2[n].ignore[1];
|
||||
p = buffer[k];
|
||||
q = buffer[l];
|
||||
buffer[k] = buffer_bad;
|
||||
buffer[l] = buffer_bad;
|
||||
|
||||
/* recover */
|
||||
raid_recov_2data(buffer, diskmax, block_size, i, j, COMBO2[n].use[0], COMBO2[n].use[1], buffer_zero);
|
||||
|
||||
/* check */
|
||||
if (memcmp(buffer_test0, a, block_size) != 0
|
||||
|| memcmp(buffer_test1, b, block_size) != 0
|
||||
) {
|
||||
fprintf(stderr, "Failed RAID test\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* restore parity */
|
||||
buffer[k] = p;
|
||||
buffer[l] = q;
|
||||
|
||||
/* restore */
|
||||
buffer[i] = a;
|
||||
buffer[j] = b;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* check 1data */
|
||||
for(n=0;n<sizeof(COMBO1)/sizeof(COMBO1[0]);++n) {
|
||||
for(i=0;i<diskmax;++i) {
|
||||
unsigned char* a;
|
||||
unsigned char* b;
|
||||
unsigned char* p;
|
||||
|
||||
/* other is p */
|
||||
k = diskmax;
|
||||
unsigned char* q;
|
||||
unsigned char* r;
|
||||
|
||||
/* save */
|
||||
a = buffer[i];
|
||||
b = buffer[j];
|
||||
p = buffer[k];
|
||||
|
||||
/* damage */
|
||||
buffer[i] = buffer_test0;
|
||||
buffer[j] = buffer_test1;
|
||||
|
||||
/* ignore parity */
|
||||
j = diskmax + COMBO1[n].ignore[0];
|
||||
k = diskmax + COMBO1[n].ignore[1];
|
||||
l = diskmax + COMBO1[n].ignore[2];
|
||||
p = buffer[j];
|
||||
q = buffer[k];
|
||||
r = buffer[l];
|
||||
buffer[j] = buffer_bad;
|
||||
buffer[k] = buffer_bad;
|
||||
buffer[l] = buffer_bad;
|
||||
|
||||
/* recover */
|
||||
raidTP_recov_2datap(buffer, diskmax, block_size, i, j, buffer_zero);
|
||||
raid_recov_1data(buffer, diskmax, block_size, i, COMBO1[n].use, buffer_zero);
|
||||
|
||||
/* check */
|
||||
if (memcmp(buffer_test0, a, block_size) != 0) {
|
||||
fprintf(stderr, "Failed RAID test\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* restore parity */
|
||||
buffer[j] = p;
|
||||
buffer[k] = q;
|
||||
buffer[l] = r;
|
||||
|
||||
/* restore */
|
||||
buffer[i] = a;
|
||||
buffer[j] = b;
|
||||
buffer[k] = p;
|
||||
|
||||
/* check */
|
||||
if (memcmp(buffer_test0, buffer[i], block_size) != 0
|
||||
|| memcmp(buffer_test1, buffer[j], block_size) != 0
|
||||
) {
|
||||
fprintf(stderr, "Failed RAIDTP test\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* check datapq */
|
||||
for(i=0;i<diskmax;++i) {
|
||||
unsigned char* a;
|
||||
unsigned char* p;
|
||||
unsigned char* q;
|
||||
|
||||
/* others are p,q */
|
||||
j = diskmax;
|
||||
k = diskmax + 1;
|
||||
|
||||
/* save */
|
||||
a = buffer[i];
|
||||
p = buffer[j];
|
||||
q = buffer[k];
|
||||
|
||||
/* damage */
|
||||
buffer[i] = buffer_test0;
|
||||
buffer[j] = buffer_bad;
|
||||
buffer[k] = buffer_bad;
|
||||
|
||||
/* recover */
|
||||
raidTP_recov_datapq(buffer, diskmax, block_size, i, buffer_zero);
|
||||
|
||||
/* restore */
|
||||
buffer[i] = a;
|
||||
buffer[j] = p;
|
||||
buffer[k] = q;
|
||||
|
||||
/* check */
|
||||
if (memcmp(buffer_test0, buffer[i], block_size) != 0) {
|
||||
fprintf(stderr, "Failed RAIDTP test\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -489,8 +421,6 @@ void selftest(int gui)
|
|||
|
||||
hashtest();
|
||||
crc32ctest();
|
||||
raid5test(33, 2048);
|
||||
raid6test(33, 2048);
|
||||
raidTPtest(33, 2048);
|
||||
raidtest(24, 2048);
|
||||
}
|
||||
|
||||
|
|
|
|||
48
speed.c
48
speed.c
|
|
@ -66,10 +66,10 @@ void speed(void)
|
|||
void* buffer_alloc;
|
||||
unsigned char** buffer;
|
||||
|
||||
buffer = malloc_nofail_vector_align(diskmax + 3, block_size, &buffer_alloc);
|
||||
buffer = malloc_nofail_vector_align(diskmax + 4, block_size, &buffer_alloc);
|
||||
|
||||
/* initialize with fixed data */
|
||||
for(i=0;i<diskmax+3;++i) {
|
||||
for(i=0;i<diskmax+4;++i) {
|
||||
memset(buffer[i], i, block_size);
|
||||
}
|
||||
for(i=0;i<HASH_SIZE;++i)
|
||||
|
|
@ -161,6 +161,18 @@ void speed(void)
|
|||
printf("sse2x2");
|
||||
#else
|
||||
printf("sse2x1");
|
||||
#endif
|
||||
else if (cpu_has_mmx())
|
||||
printf("mmxx1");
|
||||
else
|
||||
printf("int32x2");
|
||||
printf("\n");
|
||||
printf("Expected fastest RAIDQP is ");
|
||||
if (cpu_has_sse2())
|
||||
#if defined(__x86_64__)
|
||||
printf("sse2x2");
|
||||
#else
|
||||
printf("sse2x1");
|
||||
#endif
|
||||
else if (cpu_has_mmx())
|
||||
printf("mmxx1");
|
||||
|
|
@ -325,6 +337,38 @@ void speed(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
SPEED_START {
|
||||
raidQP_int32r2(buffer, diskmax, block_size);
|
||||
} SPEED_STOP
|
||||
|
||||
printf("RAIDQP int32x2 %"PRIu64" [MB/s]\n", ds / dt);
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
if (cpu_has_mmx()) {
|
||||
SPEED_START {
|
||||
raidQP_mmxr1(buffer, diskmax, block_size);
|
||||
} SPEED_STOP
|
||||
|
||||
printf("RAIDQP mmxr1 %"PRIu64" [MB/s]\n", ds / dt);
|
||||
}
|
||||
|
||||
if (cpu_has_sse2()) {
|
||||
SPEED_START {
|
||||
raidQP_sse2r1(buffer, diskmax, block_size);
|
||||
} SPEED_STOP
|
||||
|
||||
printf("RAIDQP sse2x1 %"PRIu64" [MB/s]\n", ds / dt);
|
||||
|
||||
#if defined(__x86_64__)
|
||||
SPEED_START {
|
||||
raidQP_sse2r2(buffer, diskmax, block_size);
|
||||
} SPEED_STOP
|
||||
|
||||
printf("RAIDQP sse2x2 %"PRIu64" [MB/s]\n", ds / dt);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
free(buffer_alloc);
|
||||
free(buffer);
|
||||
}
|
||||
|
|
|
|||
17
state.c
17
state.c
|
|
@ -23,6 +23,7 @@
|
|||
#include "util.h"
|
||||
#include "parity.h"
|
||||
#include "cpu.h"
|
||||
#include "raid.h"
|
||||
|
||||
const char* lev_name(unsigned l)
|
||||
{
|
||||
|
|
@ -30,6 +31,7 @@ const char* lev_name(unsigned l)
|
|||
case 0 : return "Parity";
|
||||
case 1 : return "Q-Parity";
|
||||
case 2 : return "R-Parity";
|
||||
case 3 : return "S-Parity";
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -41,6 +43,7 @@ const char* lev_config_name(unsigned l)
|
|||
case 0 : return "parity";
|
||||
case 1 : return "q-parity";
|
||||
case 2 : return "r-parity";
|
||||
case 3 : return "s-parity";
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -174,9 +177,14 @@ static void state_config_check(struct snapraid_state* state, const char* path)
|
|||
++diskcount;
|
||||
}
|
||||
|
||||
if (diskcount > 255) {
|
||||
/* RAID6 P/Q parity works for up to 255 drives, no more */
|
||||
fprintf(stderr, "Too many disks. No more than 255.\n");
|
||||
if (state->level >= 2 && diskcount > RAID6_DATA_LIMIT) {
|
||||
/* RAID6 parity works for up to 255 drives, no more */
|
||||
fprintf(stderr, "Too many disks for RAID6. No more than %u.\n", RAID6_DATA_LIMIT);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (state->level >= 4 && diskcount > RAIDQP_DATA_LIMIT) {
|
||||
/* RAIDQP parity works for up to 21 drives, no more */
|
||||
fprintf(stderr, "Too many disks for RAIDQP. No more than %u.\n", RAIDQP_DATA_LIMIT);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
|
@ -328,7 +336,7 @@ void state_config(struct snapraid_state* state, const char* path, const char* co
|
|||
exit(EXIT_FAILURE);
|
||||
}
|
||||
state->block_size *= 1024;
|
||||
} else if (strcmp(tag, "parity") == 0 || strcmp(tag, "q-parity") == 0 || strcmp(tag, "r-parity") == 0) {
|
||||
} else if (strcmp(tag, "parity") == 0 || strcmp(tag, "q-parity") == 0 || strcmp(tag, "r-parity") == 0 || strcmp(tag, "s-parity") == 0) {
|
||||
char device[PATH_MAX];
|
||||
char* slash;
|
||||
struct stat st;
|
||||
|
|
@ -338,6 +346,7 @@ void state_config(struct snapraid_state* state, const char* path, const char* co
|
|||
case 'p' : l = 0; break;
|
||||
case 'q' : l = 1; break;
|
||||
case 'r' : l = 2; break;
|
||||
case 's' : l = 3; break;
|
||||
default:
|
||||
fprintf(stderr, "Invalid '%s' specification in '%s' at line %u\n", tag, path, line);
|
||||
exit(EXIT_FAILURE);
|
||||
|
|
|
|||
6
state.h
6
state.h
|
|
@ -24,15 +24,15 @@
|
|||
/**
|
||||
* Max level of parity supported.
|
||||
*/
|
||||
#define LEV_MAX 3
|
||||
#define LEV_MAX 4
|
||||
|
||||
/**
|
||||
* Returns the parity name: Parity, Q-Parity, R-Parity.
|
||||
* Returns the parity name: Parity, Q-Parity, R-Parity, S-Parity.
|
||||
*/
|
||||
const char* lev_name(unsigned level);
|
||||
|
||||
/**
|
||||
* Returns the parity name used in the config file: parity, q-parity, r-parity.
|
||||
* Returns the parity name used in the config file: parity, q-parity, r-parity, s-parity.
|
||||
*/
|
||||
const char* lev_config_name(unsigned level);
|
||||
|
||||
|
|
|
|||
36
tables.h
36
tables.h
|
|
@ -8795,6 +8795,42 @@ const unsigned char __attribute__((aligned(256))) gfexp4[256] =
|
|||
0x58, 0x7d, 0xe9, 0x83, 0x36, 0xd8, 0x47, 0x01,
|
||||
};
|
||||
|
||||
const unsigned char __attribute__((aligned(256))) gfexp8[256] =
|
||||
{
|
||||
0x01, 0x08, 0x40, 0x3a, 0xcd, 0x26, 0x2d, 0x75,
|
||||
0x8f, 0x0c, 0x60, 0x27, 0x25, 0x35, 0xb5, 0xc1,
|
||||
0x46, 0x0a, 0x50, 0xba, 0xb9, 0xa1, 0x61, 0x2f,
|
||||
0x65, 0x0f, 0x78, 0xe7, 0x6b, 0x7f, 0xdf, 0xb6,
|
||||
0xd9, 0x86, 0x44, 0x1a, 0xd0, 0xce, 0x3e, 0xed,
|
||||
0x3b, 0xc5, 0x66, 0x17, 0xb8, 0xa9, 0x21, 0x15,
|
||||
0xa8, 0x29, 0x55, 0x92, 0xe4, 0x73, 0xbf, 0x91,
|
||||
0xfc, 0xb3, 0xf1, 0xdb, 0x96, 0xc4, 0x6e, 0x57,
|
||||
0x82, 0x64, 0x07, 0x38, 0xdd, 0xa6, 0x59, 0xf2,
|
||||
0xc3, 0x56, 0x8a, 0x24, 0x3d, 0xf5, 0xfb, 0x8b,
|
||||
0x2c, 0x7d, 0xcf, 0x36, 0xad, 0x01, 0x08, 0x40,
|
||||
0x3a, 0xcd, 0x26, 0x2d, 0x75, 0x8f, 0x0c, 0x60,
|
||||
0x27, 0x25, 0x35, 0xb5, 0xc1, 0x46, 0x0a, 0x50,
|
||||
0xba, 0xb9, 0xa1, 0x61, 0x2f, 0x65, 0x0f, 0x78,
|
||||
0xe7, 0x6b, 0x7f, 0xdf, 0xb6, 0xd9, 0x86, 0x44,
|
||||
0x1a, 0xd0, 0xce, 0x3e, 0xed, 0x3b, 0xc5, 0x66,
|
||||
0x17, 0xb8, 0xa9, 0x21, 0x15, 0xa8, 0x29, 0x55,
|
||||
0x92, 0xe4, 0x73, 0xbf, 0x91, 0xfc, 0xb3, 0xf1,
|
||||
0xdb, 0x96, 0xc4, 0x6e, 0x57, 0x82, 0x64, 0x07,
|
||||
0x38, 0xdd, 0xa6, 0x59, 0xf2, 0xc3, 0x56, 0x8a,
|
||||
0x24, 0x3d, 0xf5, 0xfb, 0x8b, 0x2c, 0x7d, 0xcf,
|
||||
0x36, 0xad, 0x01, 0x08, 0x40, 0x3a, 0xcd, 0x26,
|
||||
0x2d, 0x75, 0x8f, 0x0c, 0x60, 0x27, 0x25, 0x35,
|
||||
0xb5, 0xc1, 0x46, 0x0a, 0x50, 0xba, 0xb9, 0xa1,
|
||||
0x61, 0x2f, 0x65, 0x0f, 0x78, 0xe7, 0x6b, 0x7f,
|
||||
0xdf, 0xb6, 0xd9, 0x86, 0x44, 0x1a, 0xd0, 0xce,
|
||||
0x3e, 0xed, 0x3b, 0xc5, 0x66, 0x17, 0xb8, 0xa9,
|
||||
0x21, 0x15, 0xa8, 0x29, 0x55, 0x92, 0xe4, 0x73,
|
||||
0xbf, 0x91, 0xfc, 0xb3, 0xf1, 0xdb, 0x96, 0xc4,
|
||||
0x6e, 0x57, 0x82, 0x64, 0x07, 0x38, 0xdd, 0xa6,
|
||||
0x59, 0xf2, 0xc3, 0x56, 0x8a, 0x24, 0x3d, 0xf5,
|
||||
0xfb, 0x8b, 0x2c, 0x7d, 0xcf, 0x36, 0xad, 0x01,
|
||||
};
|
||||
|
||||
const unsigned char __attribute__((aligned(256))) gfinv[256] =
|
||||
{
|
||||
/* note that the first element is not significative */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue