Adds preliminary support for RAID based on a Cauchy matrix.

This commit is contained in:
Andrea Mazzoleni 2013-10-22 23:40:05 +02:00
parent c95917ecfe
commit 136af37e96
13 changed files with 70993 additions and 238 deletions

View file

@ -1,6 +1,13 @@
SnapRAID HISTORY
================
6.0 2013/10 (BETA)
==================
* Added support for unlimted RAIDQP (QuadParity), RAIDPP (Penta Parity)
and RAIDHP (Hexa parity).
We use a Cauchy parity generator that gets good performance only if
SSSE3 is available.
5.0 2013/10 (BETA)
==================
* Added support for RAIDTP (Triple Parity) and RAIDQP (Quad Parity).

25
check.c
View file

@ -164,7 +164,7 @@ static int is_hash_matching(struct snapraid_state* state, int rehash, unsigned d
/* 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);
raid_gen(RAID_POWER, state->level, buffer, diskmax, state->block_size);
return 1;
}
@ -177,12 +177,12 @@ static int is_hash_matching(struct snapraid_state* state, int rehash, unsigned d
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);
raid_gen(RAID_POWER, 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);
raid_gen(RAID_POWER, state->level, buffer, diskmax, state->block_size);
return 1;
}
@ -199,11 +199,12 @@ static int repair_step(struct snapraid_state* state, int rehash, unsigned pos, u
unsigned i, j;
int error;
int has_hash;
int kind = RAID_POWER;
/* no fix required */
if (failed_count == 0) {
/* recompute only parity and qarity */
raid_gen(state->level, buffer, diskmax, state->block_size);
raid_gen(kind, state->level, buffer, diskmax, state->block_size);
return 0;
}
@ -228,7 +229,7 @@ static int repair_step(struct snapraid_state* state, int rehash, unsigned pos, u
memcpy(buffer[diskmax+COMBO1[i].a], buffer_recov[COMBO1[i].a], state->block_size);
/* recover data */
raid_recov_1data(failed[failed_map[0]].index, COMBO1[i].a, buffer, diskmax, buffer_zero, state->block_size);
raid_recov_1data(kind, failed[failed_map[0]].index, COMBO1[i].a, buffer, diskmax, buffer_zero, state->block_size);
if (is_hash_matching(state, rehash, diskmax, failed, failed_map, failed_count, buffer, buffer_zero))
return 0;
@ -249,7 +250,7 @@ static int repair_step(struct snapraid_state* state, int rehash, unsigned pos, u
memcpy(buffer[diskmax+COMBO2[i].a], buffer_recov[COMBO2[i].a], state->block_size);
/* recover data */
raid_recov_1data(failed[failed_map[0]].index, COMBO2[i].a, buffer, diskmax, buffer_zero, state->block_size);
raid_recov_1data(kind, failed[failed_map[0]].index, COMBO2[i].a, buffer, diskmax, buffer_zero, state->block_size);
if (is_parity_matching(state, diskmax, COMBO2[i].b, buffer, buffer_recov))
return 0;
@ -271,7 +272,7 @@ static int repair_step(struct snapraid_state* state, int rehash, unsigned pos, u
memcpy(buffer[diskmax+COMBO2[i].b], buffer_recov[COMBO2[i].b], state->block_size);
/* recover data */
raid_recov_2data(failed[failed_map[0]].index, failed[failed_map[1]].index, COMBO2[i].a, COMBO2[i].b, buffer, diskmax, buffer_zero, state->block_size);
raid_recov_2data(kind, failed[failed_map[0]].index, failed[failed_map[1]].index, COMBO2[i].a, COMBO2[i].b, buffer, diskmax, buffer_zero, state->block_size);
if (is_hash_matching(state, rehash, diskmax, failed, failed_map, failed_count, buffer, buffer_zero))
return 0;
@ -293,7 +294,7 @@ static int repair_step(struct snapraid_state* state, int rehash, unsigned pos, u
memcpy(buffer[diskmax+COMBO3[i].b], buffer_recov[COMBO3[i].b], state->block_size);
/* recover data */
raid_recov_2data(failed[failed_map[0]].index, failed[failed_map[1]].index, COMBO3[i].a, COMBO3[i].b, buffer, diskmax, buffer_zero, state->block_size);
raid_recov_2data(kind, failed[failed_map[0]].index, failed[failed_map[1]].index, COMBO3[i].a, COMBO3[i].b, buffer, diskmax, buffer_zero, state->block_size);
if (is_parity_matching(state, diskmax, COMBO3[i].c, buffer, buffer_recov))
return 0;
@ -316,7 +317,7 @@ static int repair_step(struct snapraid_state* state, int rehash, unsigned pos, u
memcpy(buffer[diskmax+COMBO3[i].c], buffer_recov[COMBO3[i].c], state->block_size);
/* recover data */
raid_recov_3data(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, diskmax, buffer_zero, state->block_size);
raid_recov_3data(kind, 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, diskmax, buffer_zero, state->block_size);
if (is_hash_matching(state, rehash, diskmax, failed, failed_map, failed_count, buffer, buffer_zero))
return 0;
@ -339,7 +340,7 @@ static int repair_step(struct snapraid_state* state, int rehash, unsigned pos, u
memcpy(buffer[diskmax+COMBO4[i].c], buffer_recov[COMBO4[i].c], state->block_size);
/* recover data */
raid_recov_3data(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, diskmax, buffer_zero, state->block_size);
raid_recov_3data(kind, 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, diskmax, buffer_zero, state->block_size);
if (is_parity_matching(state, diskmax, COMBO4[i].d, buffer, buffer_recov))
return 0;
@ -363,7 +364,7 @@ static int repair_step(struct snapraid_state* state, int rehash, unsigned pos, u
memcpy(buffer[diskmax+COMBO4[i].d], buffer_recov[COMBO4[i].d], state->block_size);
/* recover data */
raid_recov_4data(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, diskmax, buffer_zero, state->block_size);
raid_recov_4data(kind, 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, diskmax, buffer_zero, state->block_size);
if (is_hash_matching(state, rehash, diskmax, failed, failed_map, failed_count, buffer, buffer_zero))
return 0;
@ -440,7 +441,7 @@ static int repair(struct snapraid_state* state, int rehash, unsigned pos, unsign
/* if nothing to fix */
if (!something_to_recover) {
/* recompute only parity and qarity */
raid_gen(state->level, buffer, diskmax, state->block_size);
raid_gen(RAID_POWER, state->level, buffer, diskmax, state->block_size);
return 0;
}

View file

@ -1,6 +1,6 @@
dnl Process this file with autoconf to produce a configure script.
AC_PREREQ([2.65])
AC_INIT([snapraid], [5.0], [], [], [http://snapraid.sourceforge.net])
AC_INIT([snapraid], [6.0], [], [], [http://snapraid.sourceforge.net])
AM_INIT_AUTOMAKE([foreign no-dependencies -Wall])
AC_CONFIG_SRCDIR([snapraid.c])
AC_CONFIG_HEADER([config.h])

View file

@ -39,11 +39,114 @@ unsigned char gfmul(unsigned char a, unsigned char b)
return v;
}
unsigned char gfinv[256];
#define POWER_PARITY 4
#define POWER_DISK 255
/**
* Setup the power matrix used to generate parity.
* The first row is formed by all 1.
* The second row contains power of 2, the third power of 4, and so on...
* Note that this matrix is valid only for up to Quad Parity and for up to 21 data disks.
*/
void set_power(unsigned char* matrix)
{
int i, j;
unsigned char g;
g = 1;
for(i=0;i<POWER_PARITY;++i) {
unsigned char v = 1;
for(j=0;j<POWER_DISK;++j) {
matrix[i*POWER_DISK+j] = v;
v = gfmul(g, v);
}
g = gfmul(2, g);
}
}
#define CAUCHY_PARITY 6
#define CAUCHY_DISK (256-(CAUCHY_PARITY-1))
/**
* Setup the Extended Cauchy matrix used to generate parity.
* The first row is formed by all 1.
* The second row are power of 2, 2^0, 2^1, 2^2, ...
* The others row are computed.
*/
void set_cauchy(unsigned char* matrix)
{
int i, j;
unsigned char cv, rv;
/* first row all 1, this is an Extended Cauchy matrix */
for(i=0;i<CAUCHY_DISK;++i) {
matrix[0*CAUCHY_DISK+i] = 1;
}
/* second row power of 2, this is the first row of the Cauchy matrix */
cv = 1;
for(i=0;i<CAUCHY_DISK;++i) {
matrix[1*CAUCHY_DISK+i] = cv;
cv = gfmul(2, cv);
}
/* other rows using a Cauchy matrix */
rv = 2;
for(j=0;j<CAUCHY_PARITY-2;++j) {
unsigned char ce;
ce = 1;
for(i=0;i<CAUCHY_DISK;++i) {
cv = gfinv[ce];
matrix[(j+2)*CAUCHY_DISK+i] = gfinv[rv ^ cv];
ce = gfmul(2, ce);
}
rv = gfmul(2, rv);
}
}
/**
* Next power of 2.
*/
unsigned np(unsigned v)
{
--v;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
++v;
return v;
}
int main(void)
{
unsigned char gfinv[256];
unsigned char v;
int i, j;
int i, j, k, p;
unsigned char matrix[8 * 256];
printf("/*\n");
printf(" * Copyright (C) 2011 Andrea Mazzoleni\n");
printf(" *\n");
printf(" * This program is free software: you can redistribute it and/or modify\n");
printf(" * it under the terms of the GNU General Public License as published by\n");
printf(" * the Free Software Foundation, either version 2 of the License, or\n");
printf(" * (at your option) any later version.\n");
printf(" *\n");
printf(" * This program is distributed in the hope that it will be useful,\n");
printf(" * but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
printf(" * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n");
printf(" * GNU General Public License for more details.\n");
printf(" *\n");
printf(" * You should have received a copy of the GNU General Public License\n");
printf(" * along with this program. If not, see <http://www.gnu.org/licenses/>.\n");
printf(" */\n");
printf("\n");
/* a*b */
printf("const unsigned char __attribute__((aligned(256))) gfmul[256][256] =\n");
@ -98,22 +201,6 @@ 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");
@ -177,9 +264,136 @@ int main(void)
printf("#define GFPOLY8 { 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d } \n");
printf("#define GFPOLY16 { 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d } \n");
printf("#define GFMASK16 { 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f } \n");
printf("\n");
/* power matrix */
set_power(matrix);
printf("/**\n");
printf(" * Power matrix used to generate parity.\n");
printf(" * This matrix is valid for up to 4 parity with 21 data disks.\n");
printf(" *\n");
for(p=0;p<POWER_PARITY;++p) {
printf(" * ");
for(i=0;i<POWER_DISK;++i) {
printf("%02x ", matrix[p*POWER_DISK+i]);
if (p+1 == 4 && i+1 == 21) {
/* stop at 4 parity and 21 data disks */
break;
}
}
printf("\n");
}
printf(" */\n");
printf("const unsigned char __attribute__((aligned(256))) gfmatrix_power[%u][256] =\n", POWER_PARITY);
printf("{\n");
for(p=0;p<POWER_PARITY;++p) {
printf("\t{\n");
for(i=0;i<POWER_DISK;++i) {
if (i % 8 == 0)
printf("\t\t");
printf("0x%02x,", matrix[p*POWER_DISK+i]);
if (p+1 == 4 && i+1 == 21) {
/* stop at 4 parity and 21 data disks */
break;
}
if (i % 8 == 7)
printf("\n");
else
printf(" ");
}
printf("\n\t},\n");
}
printf("};\n\n");
/* matrix matrix */
set_cauchy(matrix);
printf("/**\n");
printf(" * Extended Cauchy matrix used to generate parity.\n");
printf(" * This matrix is valid for up to %u parity with %u data disks.\n", CAUCHY_PARITY, CAUCHY_DISK);
printf(" *\n");
for(p=0;p<CAUCHY_PARITY;++p) {
printf(" * ");
for(i=0;i<CAUCHY_DISK;++i) {
printf("%02x ", matrix[p*CAUCHY_DISK+i]);
}
printf("\n");
}
printf(" */\n");
printf("const unsigned char __attribute__((aligned(256))) gfmatrix_cauchy[%u][256] =\n", CAUCHY_PARITY);
printf("{\n");
for(p=0;p<CAUCHY_PARITY;++p) {
printf("\t{\n");
for(i=0;i<CAUCHY_DISK;++i) {
if (i % 8 == 0)
printf("\t\t");
printf("0x%02x,", matrix[p*CAUCHY_DISK+i]);
if (i % 8 == 7)
printf("\n");
else
printf(" ");
}
printf("\n\t},\n");
}
printf("};\n\n");
printf("/**\n");
printf(" * Multiplication tables for the Extended Cauchy matrix.\n");
printf(" *\n");
printf(" * Indexes are [DISK][DATA][PARITY - 1].\n");
printf(" * Where DISK is from 0 to %u, DATA from 0 to 255, PARITY from 1 to %u.\n", CAUCHY_DISK - 1, CAUCHY_PARITY - 1);
printf(" */\n");
printf("const unsigned char __attribute__((aligned(256))) gfcauchy_mul[%u][256][%u] =\n", CAUCHY_DISK, np(CAUCHY_PARITY - 1));
printf("{\n");
for(i=0;i<CAUCHY_DISK;++i) {
printf("\t{\n");
for(j=0;j<256;++j) {
printf("\t\t{ ");
for(p=1;p<CAUCHY_PARITY;++p) {
v = gfmul(matrix[p*CAUCHY_DISK+i], j);
printf("0x%02x", (unsigned)v);
if (p != CAUCHY_PARITY - 1)
printf(", ");
}
printf(" },\n");
}
printf("\t},\n");
}
printf("};\n\n");
printf("#if defined(__i386__) || defined(__x86_64__)\n");
printf("/**\n");
printf(" * PSHUFB tables for the Extended Cauchy matrix.\n");
printf(" *\n");
printf(" * Indexes are [DISK][DATA][PARITY - 2].\n");
printf(" * Where DISK is from 0 to %u, DATA from 0 to 255, PARITY from 2 to %u.\n", CAUCHY_DISK - 1, CAUCHY_PARITY - 1);
printf(" */\n");
printf("const unsigned char __attribute__((aligned(256))) gfcauchy_pshufb[%u][%u][2][16] =\n", CAUCHY_DISK, np(CAUCHY_PARITY - 2));
printf("{\n");
for(i=0;i<CAUCHY_DISK;++i) {
printf("\t{\n");
for(p=2;p<CAUCHY_PARITY;++p) {
printf("\t\t{\n");
for(j=0;j<2;++j) {
printf("\t\t\t{ ");
for(k=0;k<16;++k) {
v = gfmul(matrix[p*CAUCHY_DISK+i], k);
if (j == 1)
v = gfmul(v, 16);
printf("0x%02x", (unsigned)v);
if (k != 15)
printf(", ");
}
printf(" },\n");
}
printf("\t\t},\n");
}
printf("\t},\n");
}
printf("};\n");
printf("#endif\n\n");
return 0;
}

901
raid.c

File diff suppressed because it is too large Load diff

42
raid.h
View file

@ -22,14 +22,25 @@
/* raid */
/**
* Max number of data disks for RAID6.
* Kind of generator matrix used.
*/
#define RAID6_DATA_LIMIT 255
#define RAID_POWER 0 /**< Power matrix. Fast but no more than 4 parity with 21 data disks */
#define RAID_CAUCHY 1 /**< Cauchy matrix. Slower, but no limit. */
/**
* Max number of data disks for RAIDQP.
* Max number of data disks for RAID_POWER for up to TripleParity.
*/
#define RAIDQP_DATA_LIMIT 21
#define RAID_POWER_DATA_LIMIT 255
/**
* Max number of data disks for RAID_POWER with QuadParity.
*/
#define RAID_POWER_QP_DATA_LIMIT 21
/**
* Max number of data disks with RAID_CAUCHY.
*/
#define RAID_CAUCHY_DATA_LIMIT 251
/**
* Initializes the RAID system.
@ -38,13 +49,14 @@ void raid_init(void);
/**
* Computes the specified number of parities.
* \param kind Kind of parity. RAID_POWER or RAID_CAUCHY.
* \param level Number of parities to compute.
* \param vbuf Vector of pointers to the blocks for disks and parities.
* It has (::data + ::level) elements. Each element points to a buffer of ::size bytes.
* \param data Number of data disks.
* \param size Size of the blocks pointed by vbuf.
*/
void raid_gen(unsigned level, unsigned char** vbuf, unsigned data, unsigned size);
void raid_gen(unsigned kind, unsigned level, unsigned char** vbuf, unsigned data, unsigned size);
/*
* Recovers failure of one data block x using parity i.
@ -58,25 +70,25 @@ void raid_gen(unsigned level, unsigned char** vbuf, unsigned data, unsigned size
* This buffer is not modified.
* \param size Size of the blocks pointed by vbuf.
*/
void raid_recov_1data(int x, int i, unsigned char** vbuf, unsigned data, unsigned char* zero, unsigned size);
void raid_recov_1data(unsigned kind, int x, int i, unsigned char** vbuf, unsigned data, unsigned char* zero, unsigned size);
/*
* Recovers failure of two data blocks x,y using parity i,j.
* Note that only the data blocks are recovered. The full parity is instead destroyed.
*/
void raid_recov_2data(int x, int y, int i, int j, unsigned char** vbuf, unsigned data, unsigned char* zero, unsigned size);
void raid_recov_2data(unsigned kind, int x, int y, int i, int j, unsigned char** vbuf, unsigned data, unsigned char* zero, unsigned size);
/*
* Recovers failure of three data blocks x,y,z using parity i,j,k.
* Note that only the data blocks are recovered. The full parity is instead destroyed.
*/
void raid_recov_3data(int x, int y, int z, int i, int j, int k, unsigned char** vbuf, unsigned data, unsigned char* zero, unsigned size);
void raid_recov_3data(unsigned kind, int x, int y, int z, int i, int j, int k, unsigned char** vbuf, unsigned data, unsigned char* zero, unsigned size);
/*
* Recovers failure of four data blocks x,y,z,v using parity i,j,k,l.
* Note that only the data blocks are recovered. The full parity is instead destroyed.
*/
void raid_recov_4data(int x, int y, int z, int v, int i, int j, int k, int l, unsigned char** vbuf, unsigned data, unsigned char* zero, unsigned size);
void raid_recov_4data(unsigned kind, int x, int y, int z, int v, int i, int j, int k, int l, unsigned char** vbuf, unsigned data, unsigned char* zero, unsigned size);
/**
* Gets the name of the selected function to compute parity.
@ -85,6 +97,9 @@ const char* raid5_tag(void);
const char* raid6_tag(void);
const char* raidTP_tag(void);
const char* raidQP_tag(void);
const char* cauchyQP_tag(void);
const char* cauchyPP_tag(void);
const char* cauchyHP_tag(void);
/**
* Internal specialized parity computation.
@ -114,6 +129,15 @@ void raidQP_sse2ext(unsigned char** vbuf, unsigned data, unsigned size);
void raidQP_ssse3(unsigned char** vbuf, unsigned data, unsigned size);
void raidQP_ssse3ext(unsigned char** vbuf, unsigned data, unsigned size);
void raidQP_avxext(unsigned char** vbuf, unsigned data, unsigned size);
void cauchyQP_int8(unsigned char** vbuf, unsigned data, unsigned size);
void cauchyQP_ssse3(unsigned char** vbuf, unsigned data, unsigned size);
void cauchyQP_ssse3ext(unsigned char** vbuf, unsigned data, unsigned size);
void cauchyPP_int8(unsigned char** vbuf, unsigned data, unsigned size);
void cauchyPP_ssse3(unsigned char** vbuf, unsigned data, unsigned size);
void cauchyPP_ssse3ext(unsigned char** vbuf, unsigned data, unsigned size);
void cauchyHP_int8(unsigned char** vbuf, unsigned data, unsigned size);
void cauchyHP_ssse3(unsigned char** vbuf, unsigned data, unsigned size);
void cauchyHP_ssse3ext(unsigned char** vbuf, unsigned data, unsigned size);
#endif

View file

@ -315,7 +315,7 @@ static int state_scrub_process(struct snapraid_state* state, struct snapraid_par
}
/* compute the parity */
raid_gen(state->level, buffer, diskmax, state->block_size);
raid_gen(RAID_POWER, state->level, buffer, diskmax, state->block_size);
/* compare the parity */
for(l=0;l<state->level;++l) {

View file

@ -46,7 +46,7 @@ static struct hash_test_vector TEST_SPOOKY2[] = {
{ 0, 0, { 0 } }
};
static void recovtest(unsigned diskmax, unsigned block_size)
static void recovtest(unsigned kind, unsigned diskmax, unsigned block_size)
{
void* buffer_alloc;
unsigned char** buffer;
@ -57,6 +57,7 @@ static void recovtest(unsigned diskmax, unsigned block_size)
unsigned char* buffer_zero;
unsigned char* buffer_bad;
unsigned buffermax;
unsigned level;
unsigned i, j, k, l;
unsigned n;
@ -92,7 +93,13 @@ static void recovtest(unsigned diskmax, unsigned block_size)
{ 3, { 0, 1, 2 } }
};
buffermax = diskmax + LEV_MAX * 2 + 1 + 1;
if (kind == RAID_POWER) {
level = 4;
} else {
level = 4; /* TODO preliminary support limited to 4 parity */
}
buffermax = diskmax + level * 2 + 1 + 1;
buffer = malloc_nofail_vector_align(buffermax, block_size, &buffer_alloc);
@ -112,7 +119,7 @@ static void recovtest(unsigned diskmax, unsigned block_size)
}
/* compute the parity */
raid_gen(LEV_MAX, buffer, diskmax, block_size);
raid_gen(kind, level, buffer, diskmax, block_size);
/* check 4data */
for(i=0;i<diskmax;++i) {
@ -124,6 +131,10 @@ static void recovtest(unsigned diskmax, unsigned block_size)
unsigned char* c;
unsigned char* d;
/* enforce the limit */
if (kind == RAID_POWER && diskmax > RAID_POWER_QP_DATA_LIMIT && l >= 3)
continue;
/* save */
a = buffer[i];
b = buffer[j];
@ -137,7 +148,7 @@ static void recovtest(unsigned diskmax, unsigned block_size)
buffer[l] = buffer_test3;
/* recover */
raid_recov_4data(i, j, k, l, 0, 1, 2, 3, buffer, diskmax, buffer_zero, block_size);
raid_recov_4data(kind, i, j, k, l, 0, 1, 2, 3, buffer, diskmax, buffer_zero, block_size);
/* check */
if (memcmp(buffer_test0, a, block_size) != 0
@ -169,8 +180,9 @@ static void recovtest(unsigned diskmax, unsigned block_size)
unsigned char* c;
unsigned char* p;
/* this is the point where quad parity fails over RAIDQP_DATA_LIMIT data disks */
if (diskmax > RAIDQP_DATA_LIMIT && COMBO3[n].use[2] >= 3)
/* enforce the limit */
/* this is the point where quad parity fails over RAID_POWER_QP_DATA_LIMIT data disks */
if (kind == RAID_POWER && diskmax > RAID_POWER_QP_DATA_LIMIT && COMBO3[n].use[2] >= 3)
continue;
/* save */
@ -189,7 +201,7 @@ static void recovtest(unsigned diskmax, unsigned block_size)
buffer[l] = buffer_bad;
/* recover ignoring p */
raid_recov_3data(i, j, k, COMBO3[n].use[0], COMBO3[n].use[1], COMBO3[n].use[2], buffer, diskmax, buffer_zero, block_size);
raid_recov_3data(kind, i, j, k, COMBO3[n].use[0], COMBO3[n].use[1], COMBO3[n].use[2], buffer, diskmax, buffer_zero, block_size);
/* check */
if (memcmp(buffer_test0, a, block_size) != 0
@ -221,6 +233,10 @@ static void recovtest(unsigned diskmax, unsigned block_size)
unsigned char* p;
unsigned char* q;
/* enforce the limit */
if (kind == RAID_POWER && diskmax > RAID_POWER_QP_DATA_LIMIT && COMBO2[n].use[1] >= 3)
continue;
/* save */
a = buffer[i];
b = buffer[j];
@ -238,7 +254,7 @@ static void recovtest(unsigned diskmax, unsigned block_size)
buffer[l] = buffer_bad;
/* recover */
raid_recov_2data(i, j, COMBO2[n].use[0], COMBO2[n].use[1], buffer, diskmax, buffer_zero, block_size);
raid_recov_2data(kind, i, j, COMBO2[n].use[0], COMBO2[n].use[1], buffer, diskmax, buffer_zero, block_size);
/* check */
if (memcmp(buffer_test0, a, block_size) != 0
@ -267,6 +283,10 @@ static void recovtest(unsigned diskmax, unsigned block_size)
unsigned char* q;
unsigned char* r;
/* enforce the limit */
if (kind == RAID_POWER && diskmax > RAID_POWER_QP_DATA_LIMIT && COMBO1[n].use >= 3)
continue;
/* save */
a = buffer[i];
@ -285,7 +305,7 @@ static void recovtest(unsigned diskmax, unsigned block_size)
buffer[l] = buffer_bad;
/* recover */
raid_recov_1data(i, COMBO1[n].use, buffer, diskmax, buffer_zero, block_size);
raid_recov_1data(kind, i, COMBO1[n].use, buffer, diskmax, buffer_zero, block_size);
/* check */
if (memcmp(buffer_test0, a, block_size) != 0) {
@ -307,7 +327,7 @@ static void recovtest(unsigned diskmax, unsigned block_size)
free(buffer);
}
static void gentest(unsigned diskmax, unsigned block_size)
static void gentest(unsigned kind, unsigned diskmax, unsigned block_size)
{
void* buffer_alloc;
unsigned char** buffer;
@ -315,8 +335,15 @@ static void gentest(unsigned diskmax, unsigned block_size)
unsigned i, j;
void (*map[64])(unsigned char** buffer, unsigned diskmax, unsigned size);
unsigned mac;
unsigned level;
buffermax = diskmax + LEV_MAX * 2;
if (kind == RAID_POWER) {
level = 4;
} else {
level = LEV_MAX;
}
buffermax = diskmax + level * 2;
buffer = malloc_nofail_vector_align(buffermax, block_size, &buffer_alloc);
@ -327,55 +354,82 @@ static void gentest(unsigned diskmax, unsigned block_size)
}
/* compute the parity */
raid_gen(LEV_MAX, buffer, diskmax, block_size);
raid_gen(kind, level, buffer, diskmax, block_size);
/* copy in back buffers */
for(i=0;i<LEV_MAX;++i)
memcpy(buffer[diskmax + LEV_MAX + i], buffer[diskmax + i], block_size);
for(i=0;i<level;++i)
memcpy(buffer[diskmax + level + i], buffer[diskmax + i], block_size);
/* load all the available functions */
mac = 0;
map[mac++] = raid5_int32;
map[mac++] = raid5_int64;
map[mac++] = raid6_int32;
map[mac++] = raid6_int64;
map[mac++] = raidTP_int32;
map[mac++] = raidTP_int64;
map[mac++] = raidQP_int32;
map[mac++] = raidQP_int64;
if (kind == RAID_CAUCHY) {
map[mac++] = cauchyQP_int8;
map[mac++] = cauchyPP_int8;
map[mac++] = cauchyHP_int8;
}
if (kind == RAID_POWER) {
map[mac++] = raid5_int32;
map[mac++] = raid5_int64;
map[mac++] = raid6_int32;
map[mac++] = raid6_int64;
map[mac++] = raidTP_int32;
map[mac++] = raidTP_int64;
map[mac++] = raidQP_int32;
map[mac++] = raidQP_int64;
}
#if defined(__i386__) || defined(__x86_64__)
if (cpu_has_mmx()) {
map[mac++] = raid5_mmx;
map[mac++] = raid6_mmx;
map[mac++] = raidQP_mmx;
map[mac++] = raidTP_mmx;
if (kind == RAID_POWER) {
map[mac++] = raid5_mmx;
map[mac++] = raid6_mmx;
map[mac++] = raidQP_mmx;
map[mac++] = raidTP_mmx;
}
}
if (cpu_has_sse2()) {
map[mac++] = raid5_sse2;
map[mac++] = raid6_sse2;
map[mac++] = raidTP_sse2;
map[mac++] = raidQP_sse2;
if (kind == RAID_POWER) {
map[mac++] = raid5_sse2;
map[mac++] = raid6_sse2;
map[mac++] = raidTP_sse2;
map[mac++] = raidQP_sse2;
#if defined(__x86_64__)
map[mac++] = raid6_sse2ext;
map[mac++] = raidTP_sse2ext;
map[mac++] = raidQP_sse2ext;
map[mac++] = raid6_sse2ext;
map[mac++] = raidTP_sse2ext;
map[mac++] = raidQP_sse2ext;
#endif
}
}
if (cpu_has_ssse3()) {
map[mac++] = raidTP_ssse3;
map[mac++] = raidQP_ssse3;
if (kind == RAID_POWER) {
map[mac++] = raidTP_ssse3;
map[mac++] = raidQP_ssse3;
}
if (kind == RAID_CAUCHY) {
map[mac++] = cauchyQP_ssse3;
map[mac++] = cauchyPP_ssse3;
map[mac++] = cauchyHP_ssse3;
}
#if defined(__x86_64__)
map[mac++] = raidTP_ssse3ext;
map[mac++] = raidQP_ssse3ext;
if (kind == RAID_POWER) {
map[mac++] = raidTP_ssse3ext;
map[mac++] = raidQP_ssse3ext;
}
if (kind == RAID_CAUCHY) {
map[mac++] = cauchyQP_ssse3ext;
map[mac++] = cauchyPP_ssse3ext;
map[mac++] = cauchyHP_ssse3ext;
}
#endif
}
if (cpu_has_avx()) {
#if defined(__x86_64__)
map[mac++] = raidQP_avxext;
if (kind == RAID_POWER) {
map[mac++] = raidQP_avxext;
}
#endif
}
#endif
@ -386,8 +440,8 @@ static void gentest(unsigned diskmax, unsigned block_size)
map[j](buffer, diskmax, block_size);
/* check it */
for(i=0;i<LEV_MAX;++i) {
if (memcmp(buffer[diskmax + LEV_MAX + i], buffer[diskmax + i], block_size) != 0) {
for(i=0;i<level;++i) {
if (memcmp(buffer[diskmax + level + i], buffer[diskmax + i], block_size) != 0) {
fprintf(stderr, "Failed RAID test\n");
exit(EXIT_FAILURE);
}
@ -511,7 +565,9 @@ void selftest()
hashtest();
crc32ctest();
gentest(24, 256 * 1024);
recovtest(24, 2048);
gentest(RAID_POWER, 24, 256 * 1024);
gentest(RAID_CAUCHY, 32, 256 * 1024);
recovtest(RAID_POWER, 24, 2048);
recovtest(RAID_CAUCHY, 32, 2048);
}

169
speed.c
View file

@ -21,6 +21,7 @@
#include "util.h"
#include "raid.h"
#include "cpu.h"
#include "state.h"
/**
* Differential us of two timeval.
@ -66,7 +67,7 @@ void speed(void)
void* buffer_alloc;
unsigned char** buffer;
buffer = malloc_nofail_vector_align(diskmax + 4, block_size, &buffer_alloc);
buffer = malloc_nofail_vector_align(diskmax + LEV_MAX, block_size, &buffer_alloc);
/* initialize with fixed data */
for(i=0;i<diskmax+4;++i) {
@ -134,10 +135,10 @@ void speed(void)
#endif
printf("\n");
printf("Expected fastest raid5 is %s\n", raid5_tag());
printf("Expected fastest raid6 is %s\n", raid6_tag());
printf("Expected fastest raidTP is %s\n", raidTP_tag());
printf("Expected fastest raidQP is %s\n", raidQP_tag());
printf("Expected fastest power5 is %s\n", raid5_tag());
printf("Expected fastest power6 is %s\n", raid6_tag());
printf("Expected fastest powerTP is %s\n", raidTP_tag());
printf("Expected fastest powerQP is %s\n", raidQP_tag());
printf("If these expectations are false, please report it in the SnapRAID forum\n");
@ -223,6 +224,7 @@ void speed(void)
/* RAID table */
printf("RAID functions used to compute the parity:\n");
printf("%10s", "");
printf(" %6s", "int8");
printf(" %6s", "int32");
printf(" %6s", "int64");
#if defined(__i386__) || defined(__x86_64__)
@ -240,9 +242,11 @@ void speed(void)
printf("\n");
/* RAID5 */
printf("%10s", "raid5");
printf("%10s", "power5");
fflush(stdout);
printf(" %6s", "");
SPEED_START {
raid5_int32(buffer, diskmax, block_size);
} SPEED_STOP
@ -279,9 +283,11 @@ void speed(void)
printf("\n");
/* RAID6 */
printf("%10s", "raid6");
printf("%10s", "power6");
fflush(stdout);
printf(" %6s", "");
SPEED_START {
raid6_int32(buffer, diskmax, block_size);
} SPEED_STOP
@ -327,9 +333,11 @@ void speed(void)
printf("\n");
/* RAIDTP */
printf("%10s", "raidTP");
printf("%10s", "powerTP");
fflush(stdout);
printf(" %6s", "");
SPEED_START {
raidTP_int32(buffer, diskmax, block_size);
} SPEED_STOP
@ -393,9 +401,11 @@ void speed(void)
printf("\n");
/* RAIDQP */
printf("%10s", "raidQP");
printf("%10s", "powerQP");
fflush(stdout);
printf(" %6s", "");
SPEED_START {
raidQP_int32(buffer, diskmax, block_size);
} SPEED_STOP
@ -468,6 +478,147 @@ void speed(void)
}
#endif
printf("\n");
/* CAUCHYQP */
printf("%10s", "cauchyQP");
fflush(stdout);
SPEED_START {
cauchyQP_int8(buffer, diskmax, block_size);
} SPEED_STOP
printf(" %6"PRIu64, ds / dt);
fflush(stdout);
printf(" %6s", "");
printf(" %6s", "");
if (cpu_has_mmx()) {
printf(" %6s", "");
}
if (cpu_has_sse2()) {
printf(" %6s", "");
#if defined(__x86_64__)
printf(" %6s", "");
#endif
}
#if defined(__i386__) || defined(__x86_64__)
if (cpu_has_ssse3()) {
SPEED_START {
cauchyQP_ssse3(buffer, diskmax, block_size);
} SPEED_STOP
printf(" %6"PRIu64, ds / dt);
fflush(stdout);
#if defined(__x86_64__)
SPEED_START {
cauchyQP_ssse3ext(buffer, diskmax, block_size);
} SPEED_STOP
printf(" %6"PRIu64, ds / dt);
fflush(stdout);
#endif
}
#endif
printf("\n");
/* CAUCHYPP */
printf("%10s", "cauchyPP");
fflush(stdout);
SPEED_START {
cauchyPP_int8(buffer, diskmax, block_size);
} SPEED_STOP
printf(" %6"PRIu64, ds / dt);
fflush(stdout);
printf(" %6s", "");
printf(" %6s", "");
if (cpu_has_mmx()) {
printf(" %6s", "");
}
if (cpu_has_sse2()) {
printf(" %6s", "");
#if defined(__x86_64__)
printf(" %6s", "");
#endif
}
#if defined(__i386__) || defined(__x86_64__)
if (cpu_has_ssse3()) {
SPEED_START {
cauchyPP_ssse3(buffer, diskmax, block_size);
} SPEED_STOP
printf(" %6"PRIu64, ds / dt);
fflush(stdout);
#if defined(__x86_64__)
SPEED_START {
cauchyPP_ssse3ext(buffer, diskmax, block_size);
} SPEED_STOP
printf(" %6"PRIu64, ds / dt);
fflush(stdout);
#endif
}
#endif
printf("\n");
/* CAUCHYHP */
printf("%10s", "cauchyHP");
fflush(stdout);
SPEED_START {
cauchyHP_int8(buffer, diskmax, block_size);
} SPEED_STOP
printf(" %6"PRIu64, ds / dt);
fflush(stdout);
printf(" %6s", "");
printf(" %6s", "");
if (cpu_has_mmx()) {
printf(" %6s", "");
}
if (cpu_has_sse2()) {
printf(" %6s", "");
#if defined(__x86_64__)
printf(" %6s", "");
#endif
}
#if defined(__i386__) || defined(__x86_64__)
if (cpu_has_ssse3()) {
SPEED_START {
cauchyHP_ssse3(buffer, diskmax, block_size);
} SPEED_STOP
printf(" %6"PRIu64, ds / dt);
fflush(stdout);
#if defined(__x86_64__)
SPEED_START {
cauchyHP_ssse3ext(buffer, diskmax, block_size);
} SPEED_STOP
printf(" %6"PRIu64, ds / dt);
fflush(stdout);
#endif
}
#endif
printf("\n");
printf("\n");
free(buffer_alloc);

12
state.c
View file

@ -32,6 +32,8 @@ const char* lev_name(unsigned l)
case 1 : return "Q-Parity";
case 2 : return "R-Parity";
case 3 : return "S-Parity";
case 4 : return "T-Parity";
case 5 : return "U-Parity";
}
return 0;
@ -44,6 +46,8 @@ const char* lev_config_name(unsigned l)
case 1 : return "q-parity";
case 2 : return "r-parity";
case 3 : return "s-parity";
case 4 : return "t-parity";
case 5 : return "u-parity";
}
return 0;
@ -179,14 +183,14 @@ static void state_config_check(struct snapraid_state* state, const char* path)
++diskcount;
}
if (state->level >= 2 && diskcount > RAID6_DATA_LIMIT) {
if (state->level >= 2 && diskcount > RAID_POWER_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);
fprintf(stderr, "Too many disks for RAID6. No more than %u.\n", RAID_POWER_DATA_LIMIT);
exit(EXIT_FAILURE);
}
if (state->level >= 4 && diskcount > RAIDQP_DATA_LIMIT) {
if (state->level >= 4 && diskcount > RAID_POWER_QP_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);
fprintf(stderr, "Too many disks for RAIDQP. No more than %u.\n", RAID_POWER_QP_DATA_LIMIT);
exit(EXIT_FAILURE);
}

View file

@ -18,13 +18,15 @@
#ifndef __STATE_H
#define __STATE_H
#include "elem.h"
/****************************************************************************/
/* parity level */
/**
* Max level of parity supported.
*/
#define LEV_MAX 4
#define LEV_MAX 6
/**
* Returns the parity name: Parity, Q-Parity, R-Parity, S-Parity.

2
sync.c
View file

@ -374,7 +374,7 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari
/* updates the parity only if really needed */
if (parity_needs_to_be_updated) {
/* compute the parity */
raid_gen(state->level, buffer, diskmax, state->block_size);
raid_gen(RAID_POWER, state->level, buffer, diskmax, state->block_size);
/* write the parity */
for(l=0;l<state->level;++l) {

69673
tables.h

File diff suppressed because it is too large Load diff