Changes the argument format of raid_rec() and renames raid_par() to raid_gen().

This commit is contained in:
Andrea Mazzoleni 2014-01-08 17:07:13 +01:00
parent 365b4127c0
commit 00a05a80e5
15 changed files with 363 additions and 390 deletions

View file

@ -16,9 +16,9 @@
#include "gf.h"
/*
* PAR1 (RAID5 with xor) 32bit C implementation
* GEN1 (RAID5 with xor) 32bit C implementation
*/
void raid_par1_int32(int nd, size_t size, void **vv)
void raid_gen1_int32(int nd, size_t size, void **vv)
{
uint8_t **v = (uint8_t **)vv;
uint8_t *p;
@ -44,9 +44,9 @@ void raid_par1_int32(int nd, size_t size, void **vv)
}
/*
* PAR1 (RAID5 with xor) 64bit C implementation
* GEN1 (RAID5 with xor) 64bit C implementation
*/
void raid_par1_int64(int nd, size_t size, void **vv)
void raid_gen1_int64(int nd, size_t size, void **vv)
{
uint8_t **v = (uint8_t **)vv;
uint8_t *p;
@ -72,9 +72,9 @@ void raid_par1_int64(int nd, size_t size, void **vv)
}
/*
* PAR2 (RAID6 with powers of 2) 32bit C implementation
* GEN2 (RAID6 with powers of 2) 32bit C implementation
*/
void raid_par2_int32(int nd, size_t size, void **vv)
void raid_gen2_int32(int nd, size_t size, void **vv)
{
uint8_t **v = (uint8_t **)vv;
uint8_t *p;
@ -113,9 +113,9 @@ void raid_par2_int32(int nd, size_t size, void **vv)
}
/*
* PAR2 (RAID6 with powers of 2) 64bit C implementation
* GEN2 (RAID6 with powers of 2) 64bit C implementation
*/
void raid_par2_int64(int nd, size_t size, void **vv)
void raid_gen2_int64(int nd, size_t size, void **vv)
{
uint8_t **v = (uint8_t **)vv;
uint8_t *p;
@ -154,14 +154,14 @@ void raid_par2_int64(int nd, size_t size, void **vv)
}
/*
* PAR3 (triple parity with Cauchy matrix) 8bit C implementation
* GEN3 (triple parity with Cauchy matrix) 8bit C implementation
*
* Note that instead of a generic multiplication table, likely resulting
* in multiple cache misses, a precomputed table could be used.
* But this is only a kind of reference function, and we are not really
* interested in speed.
*/
void raid_par3_int8(int nd, size_t size, void **vv)
void raid_gen3_int8(int nd, size_t size, void **vv)
{
uint8_t **v = (uint8_t **)vv;
uint8_t *p;
@ -201,14 +201,14 @@ void raid_par3_int8(int nd, size_t size, void **vv)
}
/*
* PAR4 (quad parity with Cauchy matrix) 8bit C implementation
* GEN4 (quad parity with Cauchy matrix) 8bit C implementation
*
* Note that instead of a generic multiplication table, likely resulting
* in multiple cache misses, a precomputed table could be used.
* But this is only a kind of reference function, and we are not really
* interested in speed.
*/
void raid_par4_int8(int nd, size_t size, void **vv)
void raid_gen4_int8(int nd, size_t size, void **vv)
{
uint8_t **v = (uint8_t **)vv;
uint8_t *p;
@ -253,14 +253,14 @@ void raid_par4_int8(int nd, size_t size, void **vv)
}
/*
* PAR5 (penta parity with Cauchy matrix) 8bit C implementation
* GEN5 (penta parity with Cauchy matrix) 8bit C implementation
*
* Note that instead of a generic multiplication table, likely resulting
* in multiple cache misses, a precomputed table could be used.
* But this is only a kind of reference function, and we are not really
* interested in speed.
*/
void raid_par5_int8(int nd, size_t size, void **vv)
void raid_gen5_int8(int nd, size_t size, void **vv)
{
uint8_t **v = (uint8_t **)vv;
uint8_t *p;
@ -310,14 +310,14 @@ void raid_par5_int8(int nd, size_t size, void **vv)
}
/*
* PAR6 (hexa parity with Cauchy matrix) 8bit C implementation
* GEN6 (hexa parity with Cauchy matrix) 8bit C implementation
*
* Note that instead of a generic multiplication table, likely resulting
* in multiple cache misses, a precomputed table could be used.
* But this is only a kind of reference function, and we are not really
* interested in speed.
*/
void raid_par6_int8(int nd, size_t size, void **vv)
void raid_gen6_int8(int nd, size_t size, void **vv)
{
uint8_t **v = (uint8_t **)vv;
uint8_t *p;
@ -397,7 +397,7 @@ void raid_rec1_int8(int nr, int *id, int *ip, int nd, size_t size, void **vv)
/* if it's RAID5 uses the faster function */
if (ip[0] == 0) {
raid_rec1_par1(id, nd, size, vv);
raid_rec1of1(id, nd, size, vv);
return;
}
@ -454,7 +454,7 @@ void raid_rec2_int8(int nr, int *id, int *ip, int nd, size_t size, void **vv)
/* if it's RAID6 recovering with P and Q uses the faster function */
if (ip[0] == 0 && ip[1] == 1) {
raid_rec2_par2(id, ip, nd, size, vv);
raid_rec2of2_int8(id, ip, nd, size, vv);
return;
}

View file

@ -32,34 +32,34 @@
* These are intented to provide access for testing.
*/
int raid_selftest(void);
void raid_par_ref(int nd, int np, size_t size, void **vv);
void raid_gen_ref(int nd, int np, size_t size, void **vv);
void raid_invert(uint8_t *M, uint8_t *V, int n);
void raid_delta_gen(int nr, int *id, int *ip, int nd, size_t size, void **v);
void raid_rec1_par1(int *id, int nd, size_t size, void **v);
void raid_rec2_par2(int *id, int *ip, int nd, size_t size, void **vv);
void raid_par1_int32(int nd, size_t size, void **vv);
void raid_par1_int64(int nd, size_t size, void **vv);
void raid_par1_sse2(int nd, size_t size, void **vv);
void raid_par2_int32(int nd, size_t size, void **vv);
void raid_par2_int64(int nd, size_t size, void **vv);
void raid_par2_sse2(int nd, size_t size, void **vv);
void raid_par2_sse2ext(int nd, size_t size, void **vv);
void raid_parz_int32(int nd, size_t size, void **vv);
void raid_parz_int64(int nd, size_t size, void **vv);
void raid_parz_sse2(int nd, size_t size, void **vv);
void raid_parz_sse2ext(int nd, size_t size, void **vv);
void raid_par3_int8(int nd, size_t size, void **vv);
void raid_par3_ssse3(int nd, size_t size, void **vv);
void raid_par3_ssse3ext(int nd, size_t size, void **vv);
void raid_par4_int8(int nd, size_t size, void **vv);
void raid_par4_ssse3(int nd, size_t size, void **vv);
void raid_par4_ssse3ext(int nd, size_t size, void **vv);
void raid_par5_int8(int nd, size_t size, void **vv);
void raid_par5_ssse3(int nd, size_t size, void **vv);
void raid_par5_ssse3ext(int nd, size_t size, void **vv);
void raid_par6_int8(int nd, size_t size, void **vv);
void raid_par6_ssse3(int nd, size_t size, void **vv);
void raid_par6_ssse3ext(int nd, size_t size, void **vv);
void raid_rec1of1(int *id, int nd, size_t size, void **v);
void raid_rec2of2_int8(int *id, int *ip, int nd, size_t size, void **vv);
void raid_gen1_int32(int nd, size_t size, void **vv);
void raid_gen1_int64(int nd, size_t size, void **vv);
void raid_gen1_sse2(int nd, size_t size, void **vv);
void raid_gen2_int32(int nd, size_t size, void **vv);
void raid_gen2_int64(int nd, size_t size, void **vv);
void raid_gen2_sse2(int nd, size_t size, void **vv);
void raid_gen2_sse2ext(int nd, size_t size, void **vv);
void raid_genz_int32(int nd, size_t size, void **vv);
void raid_genz_int64(int nd, size_t size, void **vv);
void raid_genz_sse2(int nd, size_t size, void **vv);
void raid_genz_sse2ext(int nd, size_t size, void **vv);
void raid_gen3_int8(int nd, size_t size, void **vv);
void raid_gen3_ssse3(int nd, size_t size, void **vv);
void raid_gen3_ssse3ext(int nd, size_t size, void **vv);
void raid_gen4_int8(int nd, size_t size, void **vv);
void raid_gen4_ssse3(int nd, size_t size, void **vv);
void raid_gen4_ssse3ext(int nd, size_t size, void **vv);
void raid_gen5_int8(int nd, size_t size, void **vv);
void raid_gen5_ssse3(int nd, size_t size, void **vv);
void raid_gen5_ssse3ext(int nd, size_t size, void **vv);
void raid_gen6_int8(int nd, size_t size, void **vv);
void raid_gen6_ssse3(int nd, size_t size, void **vv);
void raid_gen6_ssse3ext(int nd, size_t size, void **vv);
void raid_rec1_int8(int nr, int *id, int *ip, int nd, size_t size, void **vv);
void raid_rec2_int8(int nr, int *id, int *ip, int nd, size_t size, void **vv);
void raid_recX_int8(int nr, int *id, int *ip, int nd, size_t size, void **vv);
@ -72,13 +72,13 @@ void raid_recX_ssse3(int nr, int *id, int *ip, int nd, size_t size, void **vv);
*
* These are intented to provide access for testing.
*/
const char *raid_par1_tag(void);
const char *raid_par2_tag(void);
const char *raid_parz_tag(void);
const char *raid_par3_tag(void);
const char *raid_par4_tag(void);
const char *raid_par5_tag(void);
const char *raid_par6_tag(void);
const char *raid_gen1_tag(void);
const char *raid_gen2_tag(void);
const char *raid_genz_tag(void);
const char *raid_gen3_tag(void);
const char *raid_gen4_tag(void);
const char *raid_gen5_tag(void);
const char *raid_gen6_tag(void);
const char *raid_rec1_tag(void);
const char *raid_rec2_tag(void);
const char *raid_recX_tag(void);
@ -86,9 +86,9 @@ const char *raid_recX_tag(void);
/*
* Internal forwarders.
*/
extern void (*raid_par3_ptr)(int nd, size_t size, void **vv);
extern void (*raid_parz_ptr)(int nd, size_t size, void **vv);
extern void (*raid_par_ptr[RAID_PARITY_MAX])(
extern void (*raid_gen3_ptr)(int nd, size_t size, void **vv);
extern void (*raid_genz_ptr)(int nd, size_t size, void **vv);
extern void (*raid_gen_ptr[RAID_PARITY_MAX])(
int nd, size_t size, void **vv);
extern void (*raid_rec_ptr[RAID_PARITY_MAX])(
int nr, int *id, int *ip, int nd, size_t size, void **vv);

View file

@ -16,9 +16,9 @@
#include "gf.h"
/*
* PARz (triple parity with powers of 2^-1) 32bit C implementation
* GENz (triple parity with powers of 2^-1) 32bit C implementation
*/
void raid_parz_int32(int nd, size_t size, void **vv)
void raid_genz_int32(int nd, size_t size, void **vv)
{
uint8_t **v = (uint8_t **)vv;
uint8_t *p;
@ -67,9 +67,9 @@ void raid_parz_int32(int nd, size_t size, void **vv)
}
/*
* PARz (triple parity with powers of 2^-1) 64bit C implementation
* GENz (triple parity with powers of 2^-1) 64bit C implementation
*/
void raid_parz_int64(int nd, size_t size, void **vv)
void raid_genz_int64(int nd, size_t size, void **vv)
{
uint8_t **v = (uint8_t **)vv;
uint8_t *p;

View file

@ -38,20 +38,20 @@
* The selected value was choosen empirically with some speed tests
* with 8/12/16/20/24 data buffers of 256 KB.
*
* These are the results with no displacement:
* These are the results in MB/s with no displacement:
*
* sse2
* par1 15368 [MB/s]
* par2 6814 [MB/s]
* parz 3033 [MB/s]
* gen1 15368 [MB/s]
* gen2 6814 [MB/s]
* genz 3033 [MB/s]
*
* These are the results with displacement resulting in improvments
* in the order of 20% or more:
*
* sse2
* par1 21936 [MB/s]
* par2 11902 [MB/s]
* parz 5838 [MB/s]
* gen1 21936 [MB/s]
* gen2 11902 [MB/s]
* genz 5838 [MB/s]
*
*/
#define RAID_MALLOC_DISPLACEMENT (7*256)

View file

@ -21,19 +21,19 @@
*/
void raid_init(void)
{
raid_par3_ptr = raid_par3_int8;
raid_par_ptr[3] = raid_par4_int8;
raid_par_ptr[4] = raid_par5_int8;
raid_par_ptr[5] = raid_par6_int8;
raid_gen3_ptr = raid_gen3_int8;
raid_gen_ptr[3] = raid_gen4_int8;
raid_gen_ptr[4] = raid_gen5_int8;
raid_gen_ptr[5] = raid_gen6_int8;
if (sizeof(void *) == 4) {
raid_par_ptr[0] = raid_par1_int32;
raid_par_ptr[1] = raid_par2_int32;
raid_parz_ptr = raid_parz_int32;
raid_gen_ptr[0] = raid_gen1_int32;
raid_gen_ptr[1] = raid_gen2_int32;
raid_genz_ptr = raid_genz_int32;
} else {
raid_par_ptr[0] = raid_par1_int64;
raid_par_ptr[1] = raid_par2_int64;
raid_parz_ptr = raid_parz_int64;
raid_gen_ptr[0] = raid_gen1_int64;
raid_gen_ptr[1] = raid_gen2_int64;
raid_genz_ptr = raid_genz_int64;
}
raid_rec_ptr[0] = raid_rec1_int8;
@ -45,32 +45,32 @@ void raid_init(void)
#ifdef CONFIG_X86
if (raid_cpu_has_sse2()) {
raid_par_ptr[0] = raid_par1_sse2;
raid_gen_ptr[0] = raid_gen1_sse2;
#ifdef CONFIG_X86_64
if (raid_cpu_has_slowextendedreg()) {
raid_par_ptr[1] = raid_par2_sse2;
raid_parz_ptr = raid_parz_sse2;
raid_gen_ptr[1] = raid_gen2_sse2;
raid_genz_ptr = raid_genz_sse2;
} else {
raid_par_ptr[1] = raid_par2_sse2ext;
raid_parz_ptr = raid_parz_sse2ext;
raid_gen_ptr[1] = raid_gen2_sse2ext;
raid_genz_ptr = raid_genz_sse2ext;
}
#else
raid_par_ptr[1] = raid_par2_sse2;
raid_parz_ptr = raid_parz_sse2;
raid_gen_ptr[1] = raid_gen2_sse2;
raid_genz_ptr = raid_genz_sse2;
#endif
}
if (raid_cpu_has_ssse3()) {
#ifdef CONFIG_X86_64
raid_par3_ptr = raid_par3_ssse3ext;
raid_par_ptr[3] = raid_par4_ssse3ext;
raid_par_ptr[4] = raid_par5_ssse3ext;
raid_par_ptr[5] = raid_par6_ssse3ext;
raid_gen3_ptr = raid_gen3_ssse3ext;
raid_gen_ptr[3] = raid_gen4_ssse3ext;
raid_gen_ptr[4] = raid_gen5_ssse3ext;
raid_gen_ptr[5] = raid_gen6_ssse3ext;
#else
raid_par3_ptr = raid_par3_ssse3;
raid_par_ptr[3] = raid_par4_ssse3;
raid_par_ptr[4] = raid_par5_ssse3;
raid_par_ptr[5] = raid_par6_ssse3;
raid_gen3_ptr = raid_gen3_ssse3;
raid_gen_ptr[3] = raid_gen4_ssse3;
raid_gen_ptr[4] = raid_gen5_ssse3;
raid_gen_ptr[5] = raid_gen6_ssse3;
#endif
raid_rec_ptr[0] = raid_rec1_ssse3;
raid_rec_ptr[1] = raid_rec2_ssse3;
@ -88,7 +88,7 @@ void raid_init(void)
/*
* Refence parity computation.
*/
void raid_par_ref(int nd, int np, size_t size, void **vv)
void raid_gen_ref(int nd, int np, size_t size, void **vv)
{
uint8_t **v = (uint8_t **)vv;
size_t i;
@ -138,7 +138,7 @@ static int raid_test_par(int nd, int np, size_t size, void **v, void **ref)
for (i = 0; i < np; ++i)
t[nd+i] = v[nd+i];
raid_par(nd, np, size, t);
raid_gen(nd, np, size, t);
/* compare parity */
for (i = 0; i < np; ++i)
@ -151,37 +151,31 @@ static int raid_test_par(int nd, int np, size_t size, void **v, void **ref)
/*
* Recovering test.
*/
static int raid_test_rec(int nrd, int *id, int nrp, int *ip, int nd, int np, size_t size, void **v, void **ref)
static int raid_test_rec(int nr, int *ir, int nd, int np, size_t size, void **v, void **ref)
{
int i, j;
void *t[TEST_COUNT + RAID_PARITY_MAX];
/* setup data */
for (i = 0, j = 0; i < nd; ++i) {
if (j < nrd && id[j] == i) {
/* setup vector */
for (i = 0, j = 0; i < nd+np; ++i) {
if (j < nr && ir[j] == i) {
/* this block has to be recovered */
t[i] = v[i];
++j;
} else {
/* this block is left unchanged */
t[i] = ref[i];
}
}
/* setup parity */
for (i = 0, j = 0; i < np; ++i) {
if (j < nrp && ip[j] == i) {
t[nd+i] = v[nd+i];
++j;
} else {
t[nd+i] = ref[nd+i];
}
}
raid_rec(nrd, id, nrp, ip, nd, np, size, t);
raid_rec(nr, ir, nd, np, size, t);
/* compare all data and parity */
for (i = 0; i < nd+np; ++i)
if (t[i] != ref[i] && memcmp(t[i], ref[i], size) != 0)
for (i = 0; i < nd+np; ++i) {
if (t[i] != ref[i] && memcmp(t[i], ref[i], size) != 0) {
return -1;
}
}
return 0;
}
@ -197,8 +191,7 @@ int raid_selftest(void)
void *v_alloc;
void **v;
void *ref[nd + RAID_PARITY_MAX];
int id[RAID_PARITY_MAX];
int ip[RAID_PARITY_MAX];
int ir[RAID_PARITY_MAX];
int i, np;
int ret = 0;
@ -221,7 +214,7 @@ int raid_selftest(void)
ref[nd+i] = v[nd+RAID_PARITY_MAX+i];
/* compute reference parity */
raid_par_ref(nd, RAID_PARITY_MAX, size, ref);
raid_gen_ref(nd, RAID_PARITY_MAX, size, ref);
/* test for each parity level */
for (np = 1; np <= RAID_PARITY_MAX; ++np) {
@ -232,31 +225,31 @@ int raid_selftest(void)
/* test recovering with full broken data disks */
for (i = 0; i < np; ++i)
id[i] = nd - np + i;
ir[i] = nd - np + i;
ret = raid_test_rec(np, id, 0, ip, nd, np, size, v, ref);
if (ret != 0)
goto bail;
/* test recovering with half broken data and ending parity */
for (i = 0; i < np / 2; ++i)
id[i] = i;
for (i = 0; i < (np + 1) / 2; ++i)
ip[i] = np - np / 2 + i;
ret = raid_test_rec(np / 2, id, np / 2, ip, nd, np, size, v, ref);
ret = raid_test_rec(np, ir, nd, np, size, v, ref);
if (ret != 0)
goto bail;
/* test recovering with half broken data and leading parity */
for (i = 0; i < np / 2; ++i)
id[i] = i;
ir[i] = i;
for (i = 0; i < (np + 1) / 2; ++i)
ip[i] = i;
ir[np / 2 + i] = nd + i;
ret = raid_test_rec(np / 2, id, np / 2, ip, nd, np, size, v, ref);
ret = raid_test_rec(np, ir, nd, np, size, v, ref);
if (ret != 0)
goto bail;
/* test recovering with half broken data and ending parity */
for (i = 0; i < np / 2; ++i)
ir[i] = i;
for (i = 0; i < (np + 1) / 2; ++i)
ir[np / 2 + i] = nd + np - (np + 1) / 2 + i;
ret = raid_test_rec(np, ir, nd, np, size, v, ref);
if (ret != 0)
goto bail;
}
@ -267,106 +260,4 @@ bail:
return ret;
}
static struct raid_func {
const char *name;
void *p;
} RAID_FUNC[] = {
{ "int8", raid_par3_int8 },
{ "int8", raid_par4_int8 },
{ "int8", raid_par5_int8 },
{ "int8", raid_par6_int8 },
{ "int32", raid_par1_int32 },
{ "int64", raid_par1_int64 },
{ "int32", raid_par2_int32 },
{ "int64", raid_par2_int64 },
{ "int32", raid_parz_int32 },
{ "int64", raid_parz_int64 },
{ "int8", raid_rec1_int8 },
{ "int8", raid_rec2_int8 },
{ "int8", raid_recX_int8 },
#ifdef CONFIG_X86
{ "sse2", raid_par1_sse2 },
{ "sse2", raid_par2_sse2 },
{ "sse2", raid_parz_sse2 },
{ "ssse3", raid_par3_ssse3 },
{ "ssse3", raid_par4_ssse3 },
{ "ssse3", raid_par5_ssse3 },
{ "ssse3", raid_par6_ssse3 },
{ "ssse3", raid_rec1_ssse3 },
{ "ssse3", raid_rec2_ssse3 },
{ "ssse3", raid_recX_ssse3 },
#endif
#ifdef CONFIG_X86_64
{ "sse2e", raid_par2_sse2ext },
{ "sse2e", raid_parz_sse2ext },
{ "ssse3e", raid_par3_ssse3ext },
{ "ssse3e", raid_par4_ssse3ext },
{ "ssse3e", raid_par5_ssse3ext },
{ "ssse3e", raid_par6_ssse3ext },
#endif
{ 0, 0 }
};
static const char *raid_tag(void *func)
{
struct raid_func *i = RAID_FUNC;
while (i->name != 0) {
if (i->p == func)
return i->name;
++i;
}
return "unknown";
}
const char *raid_par1_tag(void)
{
return raid_tag(raid_par_ptr[0]);
}
const char *raid_par2_tag(void)
{
return raid_tag(raid_par_ptr[1]);
}
const char *raid_parz_tag(void)
{
return raid_tag(raid_parz_ptr);
}
const char *raid_par3_tag(void)
{
return raid_tag(raid_par_ptr[2]);
}
const char *raid_par4_tag(void)
{
return raid_tag(raid_par_ptr[3]);
}
const char *raid_par5_tag(void)
{
return raid_tag(raid_par_ptr[4]);
}
const char *raid_par6_tag(void)
{
return raid_tag(raid_par_ptr[5]);
}
const char *raid_rec1_tag(void)
{
return raid_tag(raid_rec_ptr[0]);
}
const char *raid_rec2_tag(void)
{
return raid_tag(raid_rec_ptr[1]);
}
const char *raid_recX_tag(void)
{
return raid_tag(raid_rec_ptr[2]);
}

View file

@ -133,12 +133,12 @@
* for a Core i7-3740QM CPU @ 2.7GHz is:
*
* int8 int32 int64 sse2 sse2e ssse3 ssse3e
* par1 11927 22075 36004
* par2 3378 5874 18235 19164
* par3 844 8814 9419
* par4 665 6836 7415
* par5 537 5388 5686
* par6 449 4307 4789
* gen1 11927 22075 36004
* gen2 3378 5874 18235 19164
* gen3 844 8814 9419
* gen4 665 6836 7415
* gen5 537 5388 5686
* gen6 449 4307 4789
*
* Values are in MiB/s of data processed, not counting generated parity.
*
@ -150,7 +150,7 @@
* the Cauchy matrix if SSSE3 is present.
*
* int8 int32 int64 sse2 sse2e ssse3 ssse3e
* parz 2112 3118 9589 10304
* genz 2112 3118 9589 10304
*
*
* In conclusion, the use of power coefficients, and specifically powers
@ -176,10 +176,10 @@ const uint8_t (*raid_gfgen)[256];
void raid_mode(int mode)
{
if (mode == RAID_MODE_VANDERMONDE) {
raid_par_ptr[2] = raid_parz_ptr;
raid_gen_ptr[2] = raid_genz_ptr;
raid_gfgen = gfvandermonde;
} else {
raid_par_ptr[2] = raid_par3_ptr;
raid_gen_ptr[2] = raid_gen3_ptr;
raid_gfgen = gfcauchy;
}
}
@ -204,22 +204,43 @@ void raid_waste(void *waste)
raid_waste_block = waste;
}
/* internal forwarder */
void (*raid_par_ptr[RAID_PARITY_MAX])(int nd, size_t size, void **vv);
void (*raid_par3_ptr)(int nd, size_t size, void **vv);
void (*raid_parz_ptr)(int nd, size_t size, void **vv);
/*
* Forwarders for parity computation.
*
* These functions compute the parity blocks from the provided data.
*
* The number of parities to compute is implicit in the position in the
* forwarder vector. Position at index #i, computes (#i+1) parities.
*
* @nd Number of data blocks
* @size Size of the blocks pointed by @v. It must be a multipler of 64.
* @v Vector of pointers to the blocks of data and parity.
* It has (@nd + #parities) elements. The starting elements are the blocks for
* data, following with the parity blocks.
* Each block has @size bytes.
*/
void (*raid_gen_ptr[RAID_PARITY_MAX])(int nd, size_t size, void **vv);
void (*raid_gen3_ptr)(int nd, size_t size, void **vv);
void (*raid_genz_ptr)(int nd, size_t size, void **vv);
void raid_par(int nd, int np, size_t size, void **v)
void raid_gen(int nd, int np, size_t size, void **v)
{
BUG_ON(np < 1 || np > RAID_PARITY_MAX);
BUG_ON(size % 64 != 0);
raid_par_ptr[np - 1](nd, size, v);
raid_gen_ptr[np - 1](nd, size, v);
}
/**
* Inverts the square matrix M of size nxn into V.
*
* This is not a general matrix inversion because we assume the matrix M
* to have all the square submatrix not singular.
* We use Gauss elimination to invert.
*
* @M Matrix to invert with @n rows and @n columns.
* @V Destination matrix where the result is put.
* @n Number of rows and columns of the matrix.
*/
void raid_invert(uint8_t *M, uint8_t *V, int n)
{
@ -235,8 +256,8 @@ void raid_invert(uint8_t *M, uint8_t *V, int n)
uint8_t f;
/* the diagonal element cannot be 0 because */
/* we are inverting matrices with all the square submatrices */
/* not singular */
/* we are inverting matrices with all the square */
/* submatrices not singular */
BUG_ON(M[k*n+k] == 0);
/* make the diagonal element to be 1 */
@ -246,7 +267,8 @@ void raid_invert(uint8_t *M, uint8_t *V, int n)
V[k*n+j] = mul(f, V[k*n+j]);
}
/* make all the elements over and under the diagonal to be 0 */
/* make all the elements over and under the diagonal */
/* to be zero */
for (i = 0; i < n; ++i) {
if (i == k)
continue;
@ -290,7 +312,7 @@ void raid_delta_gen(int nr, int *id, int *ip, int nd, size_t size, void **v)
}
/* recompute the minimal parity required */
raid_par(nd, ip[nr - 1] + 1, size, v);
raid_gen(nd, ip[nr - 1] + 1, size, v);
for (i = 0; i < nr; ++i) {
/* restore disk buffers as before */
@ -312,7 +334,7 @@ void raid_delta_gen(int nr, int *id, int *ip, int nd, size_t size, void **v)
*
* Dx = Pd
*/
void raid_rec1_par1(int *id, int nd, size_t size, void **v)
void raid_rec1of1(int *id, int nd, size_t size, void **v)
{
void *p;
void *pa;
@ -329,7 +351,7 @@ void raid_rec1_par1(int *id, int nd, size_t size, void **v)
v[nd] = pa;
/* compute */
raid_par(nd, 1, size, v);
raid_gen(nd, 1, size, v);
/* restore as before */
v[id[0]] = pa;
@ -359,7 +381,7 @@ void raid_rec1_par1(int *id, int nd, size_t size, void **v)
*
* That are always satisfied for any 0<=id[0]<id[1]<255.
*/
void raid_rec2_par2(int *id, int *ip, int nd, size_t size, void **vv)
void raid_rec2of2_int8(int *id, int *ip, int nd, size_t size, void **vv)
{
uint8_t **v = (uint8_t **)vv;
size_t i;
@ -396,40 +418,87 @@ void raid_rec2_par2(int *id, int *ip, int nd, size_t size, void **vv)
}
}
/* internal forwarder */
/*
* Forwarders for data recovery.
*
* These functions recover data blocks using the specified parity
* to recompute the missing data.
*
* Note that the format of vectors @id/@ip is different than raid_rec().
* For example, in the vector @ip the first parity is represented with the
* value 0 and not @nd.
*
* @nr Number of failed data blocks to recover.
* @id[] Vector of @nr indexes of the data blocks to recover.
* The indexes start from 0. They must be in order.
* @ip[] Vector of @nr indexes of the parity blocks to use in the recovering.
* The indexes start from 0. They must be in order.
* @nd Number of data blocks.
* @np Number of parity blocks.
* @size Size of the blocks pointed by @v. It must be a multipler of 64.
* @v Vector of pointers to the blocks of data and parity.
* It has (@nd + @np) elements. The starting elements are the blocks
* for data, following with the parity blocks.
* Each block has @size bytes.
*/
void (*raid_rec_ptr[RAID_PARITY_MAX])(
int nr, int *id, int *ip, int nd, size_t size, void **vv);
void raid_rec(int nrd, int *id, int nrp, int *ip, int nd, int np, size_t size, void **v)
void raid_rec(int nr, int *ir, int nd, int np, size_t size, void **v)
{
BUG_ON(nrd > nd);
BUG_ON(nrd + nrp > np);
int nrd; /* number of data blocks to recover */
int nrp; /* number of parity blocks to recover */
/* enforce limits on size */
BUG_ON(size % 64 != 0);
/* enforce the order in the index vector */
BUG_ON(nr >= 2 && ir[0] > ir[1]);
BUG_ON(nr >= 3 && ir[1] > ir[2]);
BUG_ON(nr >= 4 && ir[2] > ir[3]);
BUG_ON(nr >= 5 && ir[3] > ir[4]);
BUG_ON(nr >= 6 && ir[4] > ir[5]);
/* counts the number of data blocks to recover */
nrd = 0;
while (nrd < nr && ir[nrd] < nd)
++nrd;
/* all the remaining are parity */
nrp = nr - nrd;
/* enforce basic sanity in arguments */
BUG_ON(nrd > nd);
BUG_ON(nrp > np);
/* ensure that we have enough parity to recover */
BUG_ON(nrd + nrp > np);
/* if failed data is present */
if (nrd != 0) {
int iu[RAID_PARITY_MAX];
int ip[RAID_PARITY_MAX];
int i, j, k;
/* setup the vector of parities to use */
for (i = 0, j = 0, k = 0; i < np; ++i) {
if (j < nrp && ip[j] == i) {
if (j < nrp && ir[nrd + j] == nd + i) {
/* this parity has to be recovered */
++j;
} else {
/* this parity is used for recovering */
iu[k] = i;
ip[k] = i;
++k;
}
}
/* recover the data, and limit the parity use to needed ones */
raid_rec_ptr[nrd - 1](nrd, id, iu, nd, size, v);
/* recover the nrd data blocks specified in ir[], */
/* using the first nrd parity in ip[] for recovering */
raid_rec_ptr[nrd - 1](nrd, ir, ip, nd, size, v);
}
/* recompute all the parities up to the last bad one */
if (nrp != 0)
raid_par(nd, ip[nrp - 1] + 1, size, v);
raid_gen(nd, ir[nr - 1] - nd + 1, size, v);
}
void raid_rec_dataonly(int nr, int *id, int *ip, int nd, size_t size, void **v)

View file

@ -35,7 +35,7 @@
#define RAID_MODE_VANDERMONDE 1
/**
* Max level of parity disks supported.
* Maximum number of parity disks supported.
*/
#define RAID_PARITY_MAX 6
@ -59,7 +59,7 @@ int raid_selftest(void);
/**
* Sets the mode to use. One of RAID_MODE_*.
*
* You can change mode at any time, and it will affect next calls to raid_par(),
* You can change mode at any time, and it will affect next calls to raid_gen(),
* raid_rec() and raid_recpar().
*
* The two modes are compatible for the first two levels of parity.
@ -82,7 +82,12 @@ void raid_zero(void *zero);
void raid_waste(void *zero);
/**
* Computes the parity.
* Computes the parity blocks.
*
* This function computes the specified number of parity blocks of the
* provided set of data blocks.
*
* Each parity block, will allow to recover on data block.
*
* @nd Number of data blocks.
* @np Number of parities blocks to compute.
@ -90,38 +95,45 @@ void raid_waste(void *zero);
* @v Vector of pointers to the blocks of data and parity.
* It has (@nd + @np) elements. The starting elements are the blocks for
* data, following with the parity blocks.
* Each blocks has @size bytes.
* Data blocks are only read and not modified. Parity blocks are written.
* Each block has @size bytes.
*/
void raid_par(int nd, int np, size_t size, void **v);
void raid_gen(int nd, int np, size_t size, void **v);
/**
* Recovers failures in data and parity blocks.
*
* All the data and parity blocks marked as bad in the @id and @ip vector
* are recovered and recomputed.
* This function recovers all the data and parity blocks marked as bad
* in the @ir vector.
*
* The parities blocks to use for recovering are automatically selected from
* the ones NOT present in the @ip vector.
* Ensure to have @nr <= @np, otherwise recovering is not possible.
*
* Ensure to have @nrd + @nrp <= @np, otherwise recovering is not possible.
* The parities blocks used for recovering are automatically selected from
* the ones NOT present in the @ir vector.
*
* @nrd Number of failed data blocks to recover.
* @id[] Vector of @nrd indexes of the data blocks to recover.
* In case there are more parity blocks than needed to recover, the parities
* at lower indexes are used in the recovering, and the others are ignored.
*
* Note that no internal integrity check is done when recovering. If the
* provided parities are correct the resulting data will be also correct.
* If parities are wrong, also the resulting recovered data will be wrong.
* This happens even in the case you have more parities blocks than needed,
* and some form of integrity verification is possible.
*
* @nr Number of failed data and parity blocks to recover.
* @ir[] Vector of @nr indexes of the data and parity blocks to recover.
* The indexes start from 0. They must be in order.
* @nrp Number of failed parity blocks to recover.
* @ip[] Vector of @nrp indexes of the parity blocks to recover.
* The indexes start from 0. They must be in order.
* All the parities not specified here are assumed correct, and they are
* not recomputed.
* The first parity is represented with value @nd, the second with value
* @nd + 1, just like positions in the @v vector.
* @nd Number of data blocks.
* @np Number of parity blocks.
* @size Size of the blocks pointed by @v. It must be a multipler of 64.
* @v Vector of pointers to the blocks of data and parity.
* It has (@nd + @np) elements. The starting elements are the blocks
* for data, following with the parity blocks.
* Each blocks has @size bytes.
* Each block has @size bytes.
*/
void raid_rec(int nrd, int *id, int nrp, int *ip, int nd, int np, size_t size, void **v);
void raid_rec(int nr, int *ir, int nd, int np, size_t size, void **v);
/**
* Recovers failures of data blocks using the specified parities.
@ -150,10 +162,10 @@ void raid_rec_dataonly(int nr, int *id, int *ip, int nd, size_t size, void **v);
* Sorts a small vector of integers.
*
* If you have block indexes not in order, you can use this function to sort
* them before callign raid_rec().
* them before calling raid_rec().
*
* @n Number of integers. No more than RAID_PARITY_MAX.
* \paran v Vector of integers.
* @v Vector of integers.
*/
void raid_sort(int n, int *v);

View file

@ -176,7 +176,7 @@ int raid_test_rec(int mode, int nd, size_t size)
}
/* compute the parity */
raid_par_ref(nd, np, size, v);
raid_gen_ref(nd, np, size, v);
/* set all the parity to the waste v */
for (i = 0; i < np; ++i)
@ -257,7 +257,7 @@ int raid_test_par(int mode, int nd, size_t size)
raid_mrand_vector(nv, size, v);
/* compute the parity */
raid_par_ref(nd, np, size, v);
raid_gen_ref(nd, np, size, v);
/* copy in back buffers */
for (i = 0; i < np; ++i)
@ -266,50 +266,50 @@ int raid_test_par(int mode, int nd, size_t size)
/* load all the available functions */
nf = 0;
f[nf++] = raid_par1_int32;
f[nf++] = raid_par1_int64;
f[nf++] = raid_par2_int32;
f[nf++] = raid_par2_int64;
f[nf++] = raid_gen1_int32;
f[nf++] = raid_gen1_int64;
f[nf++] = raid_gen2_int32;
f[nf++] = raid_gen2_int64;
#ifdef CONFIG_X86
if (raid_cpu_has_sse2()) {
f[nf++] = raid_par1_sse2;
f[nf++] = raid_par2_sse2;
f[nf++] = raid_gen1_sse2;
f[nf++] = raid_gen2_sse2;
#ifdef CONFIG_X86_64
f[nf++] = raid_par2_sse2ext;
f[nf++] = raid_gen2_sse2ext;
#endif
}
#endif
if (mode == RAID_MODE_CAUCHY) {
f[nf++] = raid_par3_int8;
f[nf++] = raid_par4_int8;
f[nf++] = raid_par5_int8;
f[nf++] = raid_par6_int8;
f[nf++] = raid_gen3_int8;
f[nf++] = raid_gen4_int8;
f[nf++] = raid_gen5_int8;
f[nf++] = raid_gen6_int8;
#ifdef CONFIG_X86
if (raid_cpu_has_ssse3()) {
f[nf++] = raid_par3_ssse3;
f[nf++] = raid_par4_ssse3;
f[nf++] = raid_par5_ssse3;
f[nf++] = raid_par6_ssse3;
f[nf++] = raid_gen3_ssse3;
f[nf++] = raid_gen4_ssse3;
f[nf++] = raid_gen5_ssse3;
f[nf++] = raid_gen6_ssse3;
#ifdef CONFIG_X86_64
f[nf++] = raid_par3_ssse3ext;
f[nf++] = raid_par4_ssse3ext;
f[nf++] = raid_par5_ssse3ext;
f[nf++] = raid_par6_ssse3ext;
f[nf++] = raid_gen3_ssse3ext;
f[nf++] = raid_gen4_ssse3ext;
f[nf++] = raid_gen5_ssse3ext;
f[nf++] = raid_gen6_ssse3ext;
#endif
}
#endif
} else {
f[nf++] = raid_parz_int32;
f[nf++] = raid_parz_int64;
f[nf++] = raid_genz_int32;
f[nf++] = raid_genz_int64;
#ifdef CONFIG_X86
if (raid_cpu_has_sse2()) {
f[nf++] = raid_parz_sse2;
f[nf++] = raid_genz_sse2;
#ifdef CONFIG_X86_64
f[nf++] = raid_parz_sse2ext;
f[nf++] = raid_genz_sse2ext;
#endif
}
#endif

View file

@ -17,13 +17,13 @@
#ifdef CONFIG_X86
/*
* PAR1 (RAID5 with xor) SSE2 implementation
* GEN1 (RAID5 with xor) SSE2 implementation
*
* Intentionally don't process more than 64 bytes because 64 is the typical
* cache block, and processing 128 bytes doesn't increase performance, and in
* some cases it even decreases it.
*/
void raid_par1_sse2(int nd, size_t size, void **vv)
void raid_gen1_sse2(int nd, size_t size, void **vv)
{
uint8_t **v = (uint8_t **)vv;
uint8_t *p;
@ -70,9 +70,9 @@ static const struct gfconst16 {
#ifdef CONFIG_X86
/*
* PAR2 (RAID6 with powers of 2) SSE2 implementation
* GEN2 (RAID6 with powers of 2) SSE2 implementation
*/
void raid_par2_sse2(int nd, size_t size, void **vv)
void raid_gen2_sse2(int nd, size_t size, void **vv)
{
uint8_t **v = (uint8_t **)vv;
uint8_t *p;
@ -124,11 +124,11 @@ void raid_par2_sse2(int nd, size_t size, void **vv)
#ifdef CONFIG_X86_64
/*
* PAR2 (RAID6 with powers of 2) SSE2 implementation
* GEN2 (RAID6 with powers of 2) SSE2 implementation
*
* Note that it uses 16 registers, meaning that x64 is required.
*/
void raid_par2_sse2ext(int nd, size_t size, void **vv)
void raid_gen2_sse2ext(int nd, size_t size, void **vv)
{
uint8_t **v = (uint8_t **)vv;
uint8_t *p;
@ -204,9 +204,9 @@ void raid_par2_sse2ext(int nd, size_t size, void **vv)
#ifdef CONFIG_X86
/*
* PAR3 (triple parity with Cauchy matrix) SSSE3 implementation
* GEN3 (triple parity with Cauchy matrix) SSSE3 implementation
*/
void raid_par3_ssse3(int nd, size_t size, void **vv)
void raid_gen3_ssse3(int nd, size_t size, void **vv)
{
uint8_t **v = (uint8_t **)vv;
uint8_t *p;
@ -301,11 +301,11 @@ void raid_par3_ssse3(int nd, size_t size, void **vv)
#ifdef CONFIG_X86_64
/*
* PAR3 (triple parity with Cauchy matrix) SSSE3 implementation
* GEN3 (triple parity with Cauchy matrix) SSSE3 implementation
*
* Note that it uses 16 registers, meaning that x64 is required.
*/
void raid_par3_ssse3ext(int nd, size_t size, void **vv)
void raid_gen3_ssse3ext(int nd, size_t size, void **vv)
{
uint8_t **v = (uint8_t **)vv;
uint8_t *p;
@ -442,9 +442,9 @@ void raid_par3_ssse3ext(int nd, size_t size, void **vv)
#ifdef CONFIG_X86
/*
* PAR4 (quad parity with Cauchy matrix) SSSE3 implementation
* GEN4 (quad parity with Cauchy matrix) SSSE3 implementation
*/
void raid_par4_ssse3(int nd, size_t size, void **vv)
void raid_gen4_ssse3(int nd, size_t size, void **vv)
{
uint8_t **v = (uint8_t **)vv;
uint8_t *p;
@ -558,11 +558,11 @@ void raid_par4_ssse3(int nd, size_t size, void **vv)
#ifdef CONFIG_X86_64
/*
* PAR4 (quad parity with Cauchy matrix) SSSE3 implementation
* GEN4 (quad parity with Cauchy matrix) SSSE3 implementation
*
* Note that it uses 16 registers, meaning that x64 is required.
*/
void raid_par4_ssse3ext(int nd, size_t size, void **vv)
void raid_gen4_ssse3ext(int nd, size_t size, void **vv)
{
uint8_t **v = (uint8_t **)vv;
uint8_t *p;
@ -731,13 +731,13 @@ void raid_par4_ssse3ext(int nd, size_t size, void **vv)
#ifdef CONFIG_X86
/*
* PAR5 (penta parity with Cauchy matrix) SSSE3 implementation
* GEN5 (penta parity with Cauchy matrix) SSSE3 implementation
*/
#ifdef _WIN32
/* ensures that stack is aligned at 16 bytes because we allocate SSE registers in it */
__attribute__((force_align_arg_pointer))
#endif
void raid_par5_ssse3(int nd, size_t size, void **vv)
void raid_gen5_ssse3(int nd, size_t size, void **vv)
/* ensures that stack is aligned at 16 bytes because we allocate SSE registers in it */
{
uint8_t **v = (uint8_t **)vv;
@ -872,11 +872,11 @@ void raid_par5_ssse3(int nd, size_t size, void **vv)
#ifdef CONFIG_X86_64
/*
* PAR5 (penta parity with Cauchy matrix) SSSE3 implementation
* GEN5 (penta parity with Cauchy matrix) SSSE3 implementation
*
* Note that it uses 16 registers, meaning that x64 is required.
*/
void raid_par5_ssse3ext(int nd, size_t size, void **vv)
void raid_gen5_ssse3ext(int nd, size_t size, void **vv)
{
uint8_t **v = (uint8_t **)vv;
uint8_t *p;
@ -1005,13 +1005,13 @@ void raid_par5_ssse3ext(int nd, size_t size, void **vv)
#ifdef CONFIG_X86
/*
* PAR6 (hexa parity with Cauchy matrix) SSSE3 implementation
* GEN6 (hexa parity with Cauchy matrix) SSSE3 implementation
*/
#ifdef _WIN32
/* ensures that stack is aligned at 16 bytes because we allocate SSE registers in it */
__attribute__((force_align_arg_pointer))
#endif
void raid_par6_ssse3(int nd, size_t size, void **vv)
void raid_gen6_ssse3(int nd, size_t size, void **vv)
{
uint8_t **v = (uint8_t **)vv;
uint8_t *p;
@ -1167,11 +1167,11 @@ void raid_par6_ssse3(int nd, size_t size, void **vv)
#ifdef CONFIG_X86_64
/*
* PAR6 (hexa parity with Cauchy matrix) SSSE3 implementation
* GEN6 (hexa parity with Cauchy matrix) SSSE3 implementation
*
* Note that it uses 16 registers, meaning that x64 is required.
*/
void raid_par6_ssse3ext(int nd, size_t size, void **vv)
void raid_gen6_ssse3ext(int nd, size_t size, void **vv)
{
uint8_t **v = (uint8_t **)vv;
uint8_t *p;
@ -1332,7 +1332,7 @@ void raid_rec1_ssse3(int nr, int *id, int *ip, int nd, size_t size, void **vv)
/* if it's RAID5 uses the faster function */
if (ip[0] == 0) {
raid_rec1_par1(id, nd, size, vv);
raid_rec1of1(id, nd, size, vv);
return;
}

View file

@ -31,9 +31,9 @@ static const struct gfzconst16 {
#ifdef CONFIG_X86
/*
* PARz (triple parity with powers of 2^-1) SSE2 implementation
* GENz (triple parity with powers of 2^-1) SSE2 implementation
*/
void raid_parz_sse2(int nd, size_t size, void **vv)
void raid_genz_sse2(int nd, size_t size, void **vv)
{
uint8_t **v = (uint8_t **)vv;
uint8_t *p;
@ -89,11 +89,11 @@ void raid_parz_sse2(int nd, size_t size, void **vv)
#ifdef CONFIG_X86_64
/*
* PARz (triple parity with powers of 2^-1) SSE2 implementation
* GENz (triple parity with powers of 2^-1) SSE2 implementation
*
* Note that it uses 16 registers, meaning that x64 is required.
*/
void raid_parz_sse2ext(int nd, size_t size, void **vv)
void raid_genz_sse2ext(int nd, size_t size, void **vv)
{
uint8_t **v = (uint8_t **)vv;
uint8_t *p;