Import Upstream version 12.4
This commit is contained in:
43
raid/COPYING
43
raid/COPYING
@@ -1,12 +1,12 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
675 Mass Ave, Cambridge, MA 02139, USA
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
@@ -15,7 +15,7 @@ software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
@@ -55,8 +55,8 @@ patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
@@ -110,7 +110,7 @@ above, provided that you also meet all of these conditions:
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
@@ -168,7 +168,7 @@ access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
@@ -225,7 +225,7 @@ impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
@@ -255,7 +255,7 @@ make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
@@ -277,9 +277,9 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Appendix: How to Apply These Terms to Your New Programs
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
@@ -291,7 +291,7 @@ convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) 19yy <name of author>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -303,16 +303,16 @@ the "copyright" line and a pointer to where the full notice is found.
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) 19yy name of author
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
@@ -335,5 +335,6 @@ necessary. Here is a sample; alter the names:
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
|
||||
|
||||
428
raid/mktables.c
Normal file
428
raid/mktables.c
Normal file
@@ -0,0 +1,428 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Andrea Mazzoleni
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* Multiplication a*b in GF(2^8).
|
||||
*/
|
||||
static uint8_t gfmul(uint8_t a, uint8_t b)
|
||||
{
|
||||
uint8_t v;
|
||||
|
||||
v = 0;
|
||||
while (b) {
|
||||
if ((b & 1) != 0)
|
||||
v ^= a;
|
||||
|
||||
if ((a & 0x80) != 0) {
|
||||
a <<= 1;
|
||||
a ^= 0x1d;
|
||||
} else {
|
||||
a <<= 1;
|
||||
}
|
||||
|
||||
b >>= 1;
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inversion (1/a) in GF(2^8).
|
||||
*/
|
||||
uint8_t gfinv[256];
|
||||
|
||||
/**
|
||||
* Number of parities.
|
||||
* This is the number of rows of the generator matrix.
|
||||
*/
|
||||
#define PARITY 6
|
||||
|
||||
/**
|
||||
* Number of disks.
|
||||
* This is the number of columns of the generator matrix.
|
||||
*/
|
||||
#define DISK (257 - PARITY)
|
||||
|
||||
/**
|
||||
* Setup the Cauchy matrix used to generate the parity.
|
||||
*/
|
||||
static void set_cauchy(uint8_t *matrix)
|
||||
{
|
||||
int i, j;
|
||||
uint8_t inv_x, y;
|
||||
|
||||
/*
|
||||
* The first row of the generator matrix is formed by all 1.
|
||||
*
|
||||
* The generator matrix is an Extended Cauchy matrix built from
|
||||
* a Cauchy matrix adding at the top a row of all 1.
|
||||
*
|
||||
* Extending a Cauchy matrix in this way maintains the MDS property
|
||||
* of the matrix.
|
||||
*
|
||||
* For example, considering a generator matrix of 4x6 we have now:
|
||||
*
|
||||
* 1 1 1 1 1 1
|
||||
* - - - - - -
|
||||
* - - - - - -
|
||||
* - - - - - -
|
||||
*/
|
||||
for (i = 0; i < DISK; ++i)
|
||||
matrix[0 * DISK + i] = 1;
|
||||
|
||||
/*
|
||||
* Second row is formed with powers 2^i, and it's the first
|
||||
* row of the Cauchy matrix.
|
||||
*
|
||||
* Each element of the Cauchy matrix is in the form 1/(x_i + y_j)
|
||||
* where all x_i and y_j must be different for any i and j.
|
||||
*
|
||||
* For the first row with j=0, we choose x_i = 2^-i and y_0 = 0
|
||||
* and we obtain a first row formed as:
|
||||
*
|
||||
* 1/(x_i + y_0) = 1/(2^-i + 0) = 2^i
|
||||
*
|
||||
* with 2^-i != 0 for any i
|
||||
*
|
||||
* In the example we get:
|
||||
*
|
||||
* x_0 = 1
|
||||
* x_1 = 142
|
||||
* x_2 = 71
|
||||
* x_3 = 173
|
||||
* x_4 = 216
|
||||
* x_5 = 108
|
||||
* y_0 = 0
|
||||
*
|
||||
* with the matrix:
|
||||
*
|
||||
* 1 1 1 1 1 1
|
||||
* 1 2 4 8 16 32
|
||||
* - - - - - -
|
||||
* - - - - - -
|
||||
*/
|
||||
inv_x = 1;
|
||||
for (i = 0; i < DISK; ++i) {
|
||||
matrix[1 * DISK + i] = inv_x;
|
||||
inv_x = gfmul(2, inv_x);
|
||||
}
|
||||
|
||||
/*
|
||||
* The rest of the Cauchy matrix is formed choosing for each row j
|
||||
* a new y_j = 2^j and reusing the x_i already assigned in the first
|
||||
* row obtaining :
|
||||
*
|
||||
* 1/(x_i + y_j) = 1/(2^-i + 2^j)
|
||||
*
|
||||
* with 2^-i + 2^j != 0 for any i,j with i>=0,j>=1,i+j<255
|
||||
*
|
||||
* In the example we get:
|
||||
*
|
||||
* y_1 = 2
|
||||
* y_2 = 4
|
||||
*
|
||||
* with the matrix:
|
||||
*
|
||||
* 1 1 1 1 1 1
|
||||
* 1 2 4 8 16 32
|
||||
* 244 83 78 183 118 47
|
||||
* 167 39 213 59 153 82
|
||||
*/
|
||||
y = 2;
|
||||
for (j = 0; j < PARITY - 2; ++j) {
|
||||
inv_x = 1;
|
||||
for (i = 0; i < DISK; ++i) {
|
||||
uint8_t x = gfinv[inv_x];
|
||||
|
||||
matrix[(j + 2) * DISK + i] = gfinv[y ^ x];
|
||||
inv_x = gfmul(2, inv_x);
|
||||
}
|
||||
|
||||
y = gfmul(2, y);
|
||||
}
|
||||
|
||||
/*
|
||||
* Finally we adjust the matrix multiplying each row for
|
||||
* the inverse of the first element in the row.
|
||||
*
|
||||
* Also this operation maintains the MDS property of the matrix.
|
||||
*
|
||||
* Resulting in:
|
||||
*
|
||||
* 1 1 1 1 1 1
|
||||
* 1 2 4 8 16 32
|
||||
* 1 245 210 196 154 113
|
||||
* 1 187 166 215 7 106
|
||||
*/
|
||||
for (j = 0; j < PARITY - 2; ++j) {
|
||||
uint8_t f = gfinv[matrix[(j + 2) * DISK]];
|
||||
|
||||
for (i = 0; i < DISK; ++i)
|
||||
matrix[(j + 2) * DISK + i] = gfmul(matrix[(j + 2) * DISK + i], f);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the Power matrix used to generate the parity.
|
||||
*/
|
||||
static void set_power(uint8_t *matrix)
|
||||
{
|
||||
unsigned i;
|
||||
uint8_t v;
|
||||
|
||||
v = 1;
|
||||
for (i = 0; i < DISK; ++i)
|
||||
matrix[0 * DISK + i] = v;
|
||||
|
||||
v = 1;
|
||||
for (i = 0; i < DISK; ++i) {
|
||||
matrix[1 * DISK + i] = v;
|
||||
v = gfmul(2, v);
|
||||
}
|
||||
|
||||
v = 1;
|
||||
for (i = 0; i < DISK; ++i) {
|
||||
matrix[2 * DISK + i] = v;
|
||||
v = gfmul(0x8e, v);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Next power of 2.
|
||||
*/
|
||||
static 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)
|
||||
{
|
||||
uint8_t v;
|
||||
int i, j, k, p;
|
||||
uint8_t matrix[PARITY * 256];
|
||||
|
||||
printf("/*\n");
|
||||
printf(" * Copyright (C) 2013 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("\n");
|
||||
|
||||
printf("#include \"internal.h\"\n");
|
||||
printf("\n");
|
||||
|
||||
/* a*b */
|
||||
printf("const uint8_t __aligned(256) raid_gfmul[256][256] =\n");
|
||||
printf("{\n");
|
||||
for (i = 0; i < 256; ++i) {
|
||||
printf("\t{\n");
|
||||
for (j = 0; j < 256; ++j) {
|
||||
if (j % 8 == 0)
|
||||
printf("\t\t");
|
||||
v = gfmul(i, j);
|
||||
if (v == 1)
|
||||
gfinv[i] = j;
|
||||
printf("0x%02x,", (unsigned)v);
|
||||
if (j % 8 == 7)
|
||||
printf("\n");
|
||||
else
|
||||
printf(" ");
|
||||
}
|
||||
printf("\t},\n");
|
||||
}
|
||||
printf("};\n\n");
|
||||
|
||||
/* 2^a */
|
||||
printf("const uint8_t __aligned(256) raid_gfexp[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, 2);
|
||||
if (i % 8 == 7)
|
||||
printf("\n");
|
||||
else
|
||||
printf(" ");
|
||||
}
|
||||
printf("};\n\n");
|
||||
|
||||
/* 1/a */
|
||||
printf("const uint8_t __aligned(256) raid_gfinv[256] =\n");
|
||||
printf("{\n");
|
||||
printf("\t/* note that the first element is not significative */\n");
|
||||
for (i = 0; i < 256; ++i) {
|
||||
if (i % 8 == 0)
|
||||
printf("\t");
|
||||
if (i == 0)
|
||||
v = 0;
|
||||
else
|
||||
v = gfinv[i];
|
||||
printf("0x%02x,", v);
|
||||
if (i % 8 == 7)
|
||||
printf("\n");
|
||||
else
|
||||
printf(" ");
|
||||
}
|
||||
printf("};\n\n");
|
||||
|
||||
/* power matrix */
|
||||
set_power(matrix);
|
||||
|
||||
printf("/**\n");
|
||||
printf(" * Power matrix used to generate parity.\n");
|
||||
printf(" * This matrix is valid for up to %u parity with %u data disks.\n", 3, DISK);
|
||||
printf(" *\n");
|
||||
for (p = 0; p < 3; ++p) {
|
||||
printf(" *");
|
||||
for (i = 0; i < DISK; ++i)
|
||||
printf(" %02x", matrix[p * DISK + i]);
|
||||
printf("\n");
|
||||
}
|
||||
printf(" */\n");
|
||||
printf("const uint8_t __aligned(256) raid_gfvandermonde[%u][256] =\n", 3);
|
||||
printf("{\n");
|
||||
for (p = 0; p < 3; ++p) {
|
||||
printf("\t{\n");
|
||||
for (i = 0; i < DISK; ++i) {
|
||||
if (i % 8 == 0)
|
||||
printf("\t\t");
|
||||
printf("0x%02x,", matrix[p * DISK + i]);
|
||||
if (i != DISK - 1) {
|
||||
if (i % 8 == 7)
|
||||
printf("\n");
|
||||
else
|
||||
printf(" ");
|
||||
}
|
||||
}
|
||||
printf("\n\t},\n");
|
||||
}
|
||||
printf("};\n\n");
|
||||
|
||||
/* cauchy matrix */
|
||||
set_cauchy(matrix);
|
||||
|
||||
printf("/**\n");
|
||||
printf(" * Cauchy matrix used to generate parity.\n");
|
||||
printf(" * This matrix is valid for up to %u parity with %u data disks.\n", PARITY, DISK);
|
||||
printf(" *\n");
|
||||
for (p = 0; p < PARITY; ++p) {
|
||||
printf(" *");
|
||||
for (i = 0; i < DISK; ++i)
|
||||
printf(" %02x", matrix[p * DISK + i]);
|
||||
printf("\n");
|
||||
}
|
||||
printf(" */\n");
|
||||
printf("const uint8_t __aligned(256) raid_gfcauchy[%u][256] =\n", PARITY);
|
||||
printf("{\n");
|
||||
for (p = 0; p < PARITY; ++p) {
|
||||
printf("\t{\n");
|
||||
for (i = 0; i < DISK; ++i) {
|
||||
if (i % 8 == 0)
|
||||
printf("\t\t");
|
||||
printf("0x%02x,", matrix[p * DISK + i]);
|
||||
if (i != DISK - 1) {
|
||||
if (i % 8 == 7)
|
||||
printf("\n");
|
||||
else
|
||||
printf(" ");
|
||||
}
|
||||
}
|
||||
printf("\n\t},\n");
|
||||
}
|
||||
printf("};\n\n");
|
||||
|
||||
printf("#ifdef CONFIG_X86\n");
|
||||
printf("/**\n");
|
||||
printf(" * PSHUFB tables for the Cauchy matrix.\n");
|
||||
printf(" *\n");
|
||||
printf(" * Indexes are [DISK][PARITY - 2][LH].\n");
|
||||
printf(" * Where DISK is from 0 to %u, PARITY from 2 to %u, LH from 0 to 1.\n", DISK - 1, PARITY - 1);
|
||||
printf(" */\n");
|
||||
printf("const uint8_t __aligned(256) raid_gfcauchypshufb[%u][%u][2][16] =\n", DISK, np(PARITY - 2));
|
||||
printf("{\n");
|
||||
for (i = 0; i < DISK; ++i) {
|
||||
printf("\t{\n");
|
||||
for (p = 2; p < 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 * 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");
|
||||
|
||||
printf("#ifdef CONFIG_X86\n");
|
||||
printf("/**\n");
|
||||
printf(" * PSHUFB tables for generic multiplication.\n");
|
||||
printf(" *\n");
|
||||
printf(" * Indexes are [MULTIPLIER][LH].\n");
|
||||
printf(" * Where MULTIPLIER is from 0 to 255, LH from 0 to 1.\n");
|
||||
printf(" */\n");
|
||||
printf("const uint8_t __aligned(256) raid_gfmulpshufb[256][2][16] =\n");
|
||||
printf("{\n");
|
||||
for (i = 0; i < 256; ++i) {
|
||||
printf("\t{\n");
|
||||
for (j = 0; j < 2; ++j) {
|
||||
printf("\t\t{ ");
|
||||
for (k = 0; k < 16; ++k) {
|
||||
v = gfmul(i, k);
|
||||
if (j == 1)
|
||||
v = gfmul(v, 16);
|
||||
printf("0x%02x", (unsigned)v);
|
||||
if (k != 15)
|
||||
printf(", ");
|
||||
}
|
||||
printf(" },\n");
|
||||
}
|
||||
printf("\t},\n");
|
||||
}
|
||||
printf("};\n");
|
||||
printf("#endif\n\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
70
raid/raid.c
70
raid/raid.c
@@ -20,50 +20,50 @@
|
||||
* the primitive polynomial x^8 + x^4 + x^3 + x^2 + 1 (285 decimal), and
|
||||
* supporting up to six parity levels.
|
||||
*
|
||||
* For RAID5 and RAID6 it works as as described in the H. Peter Anvin's
|
||||
* For RAID5 and RAID6, it works as described in H. Peter Anvin's
|
||||
* paper "The mathematics of RAID-6" [1]. Please refer to this paper for a
|
||||
* complete explanation.
|
||||
*
|
||||
* To support triple parity, it was first evaluated and then dropped, an
|
||||
* To support triple parity, it was first evaluated and then dropped; an
|
||||
* extension of the same approach, with additional parity coefficients set
|
||||
* as powers of 2^-1, with equations:
|
||||
*
|
||||
* P = sum(Di)
|
||||
* Q = sum(2^i * Di)
|
||||
* R = sum(2^-i * Di) with 0<=i<N
|
||||
* R = sum(2^-i * Di) with 0 <= i < N
|
||||
*
|
||||
* This approach works well for triple parity and it's very efficient,
|
||||
* This approach works well for triple parity and is very efficient
|
||||
* because we can implement very fast parallel multiplications and
|
||||
* divisions by 2 in GF(2^8).
|
||||
*
|
||||
* It's also similar at the approach used by ZFS RAIDZ3, with the
|
||||
* It is also similar to the approach used by ZFS RAIDZ3, with the
|
||||
* difference that ZFS uses powers of 4 instead of 2^-1.
|
||||
*
|
||||
* Unfortunately it doesn't work beyond triple parity, because whatever
|
||||
* Unfortunately, it doesn't work beyond triple parity because whatever
|
||||
* value we choose to generate the power coefficients to compute other
|
||||
* parities, the resulting equations are not solvable for some
|
||||
* combinations of missing disks.
|
||||
*
|
||||
* This is expected, because the Vandermonde matrix used to compute the
|
||||
* This is expected because the Vandermonde matrix used to compute the
|
||||
* parity has no guarantee to have all submatrices not singular
|
||||
* [2, Chap 11, Problem 7] and this is a requirement to have
|
||||
* a MDS (Maximum Distance Separable) code [2, Chap 11, Theorem 8].
|
||||
* [2, Chap 11, Problem 7], and this is a requirement to have
|
||||
* an MDS (Maximum Distance Separable) code [2, Chap 11, Theorem 8].
|
||||
*
|
||||
* To overcome this limitation, we use a Cauchy matrix [3][4] to compute
|
||||
* the parity. A Cauchy matrix has the property to have all the square
|
||||
* submatrices not singular, resulting in always solvable equations,
|
||||
* the parity. A Cauchy matrix has the property of having all square
|
||||
* submatrices not singular, resulting in always solvable equations
|
||||
* for any combination of missing disks.
|
||||
*
|
||||
* The problem of this approach is that it requires the use of
|
||||
* The problem with this approach is that it requires the use of
|
||||
* generic multiplications, and not only by 2 or 2^-1, potentially
|
||||
* affecting badly the performance.
|
||||
* affecting performance negatively.
|
||||
*
|
||||
* Hopefully there is a method to implement parallel multiplications
|
||||
* using SSSE3 or AVX2 instructions [1][5]. Method competitive with the
|
||||
* Hopefully, there is a method to implement parallel multiplications
|
||||
* using SSSE3 or AVX2 instructions [1][5], a method competitive with the
|
||||
* computation of triple parity using power coefficients.
|
||||
*
|
||||
* Another important property of the Cauchy matrix is that we can setup
|
||||
* the first two rows with coefficients equal at the RAID5 and RAID6 approach
|
||||
* Another important property of the Cauchy matrix is that we can set up
|
||||
* the first two rows with coefficients equal to the RAID5 and RAID6 approach
|
||||
* described, resulting in a compatible extension, and requiring SSSE3
|
||||
* or AVX2 instructions only if triple parity or beyond is used.
|
||||
*
|
||||
@@ -71,7 +71,7 @@
|
||||
* to make the first column of all 1, to optimize the computation for
|
||||
* the first disk.
|
||||
*
|
||||
* This results in the matrix A[row,col] defined as:
|
||||
* This results in the matrix A[row, col] defined as:
|
||||
*
|
||||
* 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01...
|
||||
* 01 02 04 08 10 20 40 80 1d 3a 74 e8 cd 87 13 26 4c 98 2d 5a b4 75...
|
||||
@@ -80,25 +80,25 @@
|
||||
* 01 97 7f 9c 7c 18 bd a2 58 1a da 74 70 a3 e5 47 29 07 f5 80 23 e9...
|
||||
* 01 2b 3f cf 73 2c d6 ed cb 74 15 78 8a c1 17 c9 89 68 21 ab 76 3b...
|
||||
*
|
||||
* This matrix supports 6 level of parity, one for each row, for up to 251
|
||||
* This matrix supports 6 levels of parity, one for each row, for up to 251
|
||||
* data disks, one for each column, with all the 377,342,351,231 square
|
||||
* submatrices not singular, verified also with brute-force.
|
||||
* submatrices not singular, verified also with brute force.
|
||||
*
|
||||
* This matrix can be extended to support any number of parities, just
|
||||
* adding additional rows, and removing one column for each new row.
|
||||
* (see mktables.c for more details in how the matrix is generated)
|
||||
* adding additional rows and removing one column for each new row.
|
||||
* (see mktables.c for more details on how the matrix is generated)
|
||||
*
|
||||
* In details, parity is computed as:
|
||||
* In detail, parity is computed as:
|
||||
*
|
||||
* P = sum(Di)
|
||||
* Q = sum(2^i * Di)
|
||||
* Q = sum(2^i * Di)
|
||||
* R = sum(A[2,i] * Di)
|
||||
* S = sum(A[3,i] * Di)
|
||||
* T = sum(A[4,i] * Di)
|
||||
* U = sum(A[5,i] * Di) with 0<=i<N
|
||||
* U = sum(A[5,i] * Di) with 0 <= i < N
|
||||
*
|
||||
* To recover from a failure of six disks at indexes x,y,z,h,v,w,
|
||||
* with 0<=x<y<z<h<v<w<N, we compute the parity of the available N-6
|
||||
* To recover from a failure of six disks at indexes x, y, z, h, v, w,
|
||||
* with 0 <= x < y < z < h < v < w < N, we compute the parity of the available N-6
|
||||
* disks as:
|
||||
*
|
||||
* Pa = sum(Di)
|
||||
@@ -106,7 +106,7 @@
|
||||
* Ra = sum(A[2,i] * Di)
|
||||
* Sa = sum(A[3,i] * Di)
|
||||
* Ta = sum(A[4,i] * Di)
|
||||
* Ua = sum(A[5,i] * Di) with 0<=i<N,i!=x,i!=y,i!=z,i!=h,i!=v,i!=w.
|
||||
* Ua = sum(A[5,i] * Di) with 0 <= i < N, i != x, i != y, i != z, i != h, i != v, i != w.
|
||||
*
|
||||
* And if we define:
|
||||
*
|
||||
@@ -126,13 +126,13 @@
|
||||
* Td = A[4,x] * Dx + A[4,y] * Dy + A[4,z] * Dz + A[4,h] * Dh + A[4,v] * Dv + A[4,w] * Dw
|
||||
* Ud = A[5,x] * Dx + A[5,y] * Dy + A[5,z] * Dz + A[5,h] * Dh + A[5,v] * Dv + A[5,w] * Dw
|
||||
*
|
||||
* A linear system always solvable because the coefficients matrix is
|
||||
* always not singular due the properties of the matrix A[].
|
||||
* A linear system is always solvable because the coefficients matrix is
|
||||
* always not singular due to the properties of the matrix A[].
|
||||
*
|
||||
* Resulting speed in x64, with 8 data disks, using a stripe of 256 KiB,
|
||||
* The resulting speed in x64, with 8 data disks, using a stripe of 256 KiB,
|
||||
* for a Core i5-4670K Haswell Quad-Core 3.4GHz is:
|
||||
*
|
||||
* int8 int32 int64 sse2 ssse3 avx2
|
||||
* int8 int32 int64 sse2 ssse3 avx2
|
||||
* gen1 13339 25438 45438 50588
|
||||
* gen2 4115 6514 21840 32201
|
||||
* gen3 814 10154 18613
|
||||
@@ -143,18 +143,18 @@
|
||||
* Values are in MiB/s of data processed by a single thread, not counting
|
||||
* generated parity.
|
||||
*
|
||||
* You can replicate these results in your machine using the
|
||||
* You can replicate these results on your machine using the
|
||||
* "raid/test/speedtest.c" program.
|
||||
*
|
||||
* For comparison, the triple parity computation using the power
|
||||
* coefficients "1,2,2^-1" is only a little faster than the one based on
|
||||
* the Cauchy matrix if SSSE3 or AVX2 is present.
|
||||
*
|
||||
* int8 int32 int64 sse2 ssse3 avx2
|
||||
* int8 int32 int64 sse2 ssse3 avx2
|
||||
* genz 2337 2874 10920 18944
|
||||
*
|
||||
* In conclusion, the use of power coefficients, and specifically powers
|
||||
* of 1,2,2^-1, is the best option to implement triple parity in CPUs
|
||||
* of 1, 2, 2^-1, is the best option to implement triple parity in CPUs
|
||||
* without SSSE3 and AVX2.
|
||||
* But if a modern CPU with SSSE3 or AVX2 is available, the Cauchy
|
||||
* matrix is the best option because it provides a fast and general
|
||||
|
||||
106
raid/tag.c
106
raid/tag.c
@@ -14,76 +14,78 @@
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
typedef void (void_f)(void);
|
||||
|
||||
static struct raid_func {
|
||||
const char *name;
|
||||
void (*p)();
|
||||
void_f* func;
|
||||
} RAID_FUNC[] = {
|
||||
{ "int8", raid_gen3_int8 },
|
||||
{ "int8", raid_gen4_int8 },
|
||||
{ "int8", raid_gen5_int8 },
|
||||
{ "int8", raid_gen6_int8 },
|
||||
{ "int32", raid_gen1_int32 },
|
||||
{ "int64", raid_gen1_int64 },
|
||||
{ "int32", raid_gen2_int32 },
|
||||
{ "int64", raid_gen2_int64 },
|
||||
{ "int32", raid_genz_int32 },
|
||||
{ "int64", raid_genz_int64 },
|
||||
{ "int8", raid_rec1_int8 },
|
||||
{ "int8", raid_rec2_int8 },
|
||||
{ "int8", raid_recX_int8 },
|
||||
{ "int8", (void_f*)raid_gen3_int8 },
|
||||
{ "int8", (void_f*)raid_gen4_int8 },
|
||||
{ "int8", (void_f*)raid_gen5_int8 },
|
||||
{ "int8", (void_f*)raid_gen6_int8 },
|
||||
{ "int32", (void_f*)raid_gen1_int32 },
|
||||
{ "int64", (void_f*)raid_gen1_int64 },
|
||||
{ "int32", (void_f*)raid_gen2_int32 },
|
||||
{ "int64", (void_f*)raid_gen2_int64 },
|
||||
{ "int32", (void_f*)raid_genz_int32 },
|
||||
{ "int64", (void_f*)raid_genz_int64 },
|
||||
{ "int8", (void_f*)raid_rec1_int8 },
|
||||
{ "int8", (void_f*)raid_rec2_int8 },
|
||||
{ "int8", (void_f*)raid_recX_int8 },
|
||||
|
||||
#ifdef CONFIG_X86
|
||||
#ifdef CONFIG_SSE2
|
||||
{ "sse2", raid_gen1_sse2 },
|
||||
{ "sse2", raid_gen2_sse2 },
|
||||
{ "sse2", raid_genz_sse2 },
|
||||
{ "sse2", (void_f*)raid_gen1_sse2 },
|
||||
{ "sse2", (void_f*)raid_gen2_sse2 },
|
||||
{ "sse2", (void_f*)raid_genz_sse2 },
|
||||
#endif
|
||||
#ifdef CONFIG_SSSE3
|
||||
{ "ssse3", raid_gen3_ssse3 },
|
||||
{ "ssse3", raid_gen4_ssse3 },
|
||||
{ "ssse3", raid_gen5_ssse3 },
|
||||
{ "ssse3", raid_gen6_ssse3 },
|
||||
{ "ssse3", raid_rec1_ssse3 },
|
||||
{ "ssse3", raid_rec2_ssse3 },
|
||||
{ "ssse3", raid_recX_ssse3 },
|
||||
{ "ssse3", (void_f*)raid_gen3_ssse3 },
|
||||
{ "ssse3", (void_f*)raid_gen4_ssse3 },
|
||||
{ "ssse3", (void_f*)raid_gen5_ssse3 },
|
||||
{ "ssse3", (void_f*)raid_gen6_ssse3 },
|
||||
{ "ssse3", (void_f*)raid_rec1_ssse3 },
|
||||
{ "ssse3", (void_f*)raid_rec2_ssse3 },
|
||||
{ "ssse3", (void_f*)raid_recX_ssse3 },
|
||||
#endif
|
||||
#ifdef CONFIG_AVX2
|
||||
{ "avx2", raid_gen1_avx2 },
|
||||
{ "avx2", raid_gen2_avx2 },
|
||||
{ "avx2", raid_rec1_avx2 },
|
||||
{ "avx2", raid_rec2_avx2 },
|
||||
{ "avx2", raid_recX_avx2 },
|
||||
{ "avx2", (void_f*)raid_gen1_avx2 },
|
||||
{ "avx2", (void_f*)raid_gen2_avx2 },
|
||||
{ "avx2", (void_f*)raid_rec1_avx2 },
|
||||
{ "avx2", (void_f*)raid_rec2_avx2 },
|
||||
{ "avx2", (void_f*)raid_recX_avx2 },
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
#ifdef CONFIG_SSE2
|
||||
{ "sse2e", raid_gen2_sse2ext },
|
||||
{ "sse2e", raid_genz_sse2ext },
|
||||
{ "sse2e", (void_f*)raid_gen2_sse2ext },
|
||||
{ "sse2e", (void_f*)raid_genz_sse2ext },
|
||||
#endif
|
||||
#ifdef CONFIG_SSSE3
|
||||
{ "ssse3e", raid_gen3_ssse3ext },
|
||||
{ "ssse3e", raid_gen4_ssse3ext },
|
||||
{ "ssse3e", raid_gen5_ssse3ext },
|
||||
{ "ssse3e", raid_gen6_ssse3ext },
|
||||
{ "ssse3e", (void_f*)raid_gen3_ssse3ext },
|
||||
{ "ssse3e", (void_f*)raid_gen4_ssse3ext },
|
||||
{ "ssse3e", (void_f*)raid_gen5_ssse3ext },
|
||||
{ "ssse3e", (void_f*)raid_gen6_ssse3ext },
|
||||
#endif
|
||||
#ifdef CONFIG_AVX2
|
||||
{ "avx2e", raid_gen3_avx2ext },
|
||||
{ "avx2e", raid_genz_avx2ext },
|
||||
{ "avx2e", raid_gen4_avx2ext },
|
||||
{ "avx2e", raid_gen5_avx2ext },
|
||||
{ "avx2e", raid_gen6_avx2ext },
|
||||
{ "avx2e", (void_f*)raid_gen3_avx2ext },
|
||||
{ "avx2e", (void_f*)raid_genz_avx2ext },
|
||||
{ "avx2e", (void_f*)raid_gen4_avx2ext },
|
||||
{ "avx2e", (void_f*)raid_gen5_avx2ext },
|
||||
{ "avx2e", (void_f*)raid_gen6_avx2ext },
|
||||
#endif
|
||||
#endif
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static const char *raid_tag(void (*func)())
|
||||
static const char *raid_tag(void_f* func)
|
||||
{
|
||||
struct raid_func *i = RAID_FUNC;
|
||||
|
||||
while (i->name != 0) {
|
||||
if (i->p == func)
|
||||
if (i->func == func)
|
||||
return i->name;
|
||||
++i;
|
||||
}
|
||||
@@ -95,51 +97,51 @@ static const char *raid_tag(void (*func)())
|
||||
|
||||
const char *raid_gen1_tag(void)
|
||||
{
|
||||
return raid_tag(raid_gen_ptr[0]);
|
||||
return raid_tag((void_f*)raid_gen_ptr[0]);
|
||||
}
|
||||
|
||||
const char *raid_gen2_tag(void)
|
||||
{
|
||||
return raid_tag(raid_gen_ptr[1]);
|
||||
return raid_tag((void_f*)raid_gen_ptr[1]);
|
||||
}
|
||||
|
||||
const char *raid_genz_tag(void)
|
||||
{
|
||||
return raid_tag(raid_genz_ptr);
|
||||
return raid_tag((void_f*)raid_genz_ptr);
|
||||
}
|
||||
|
||||
const char *raid_gen3_tag(void)
|
||||
{
|
||||
return raid_tag(raid_gen_ptr[2]);
|
||||
return raid_tag((void_f*)raid_gen_ptr[2]);
|
||||
}
|
||||
|
||||
const char *raid_gen4_tag(void)
|
||||
{
|
||||
return raid_tag(raid_gen_ptr[3]);
|
||||
return raid_tag((void_f*)raid_gen_ptr[3]);
|
||||
}
|
||||
|
||||
const char *raid_gen5_tag(void)
|
||||
{
|
||||
return raid_tag(raid_gen_ptr[4]);
|
||||
return raid_tag((void_f*)raid_gen_ptr[4]);
|
||||
}
|
||||
|
||||
const char *raid_gen6_tag(void)
|
||||
{
|
||||
return raid_tag(raid_gen_ptr[5]);
|
||||
return raid_tag((void_f*)raid_gen_ptr[5]);
|
||||
}
|
||||
|
||||
const char *raid_rec1_tag(void)
|
||||
{
|
||||
return raid_tag(raid_rec_ptr[0]);
|
||||
return raid_tag((void_f*)raid_rec_ptr[0]);
|
||||
}
|
||||
|
||||
const char *raid_rec2_tag(void)
|
||||
{
|
||||
return raid_tag(raid_rec_ptr[1]);
|
||||
return raid_tag((void_f*)raid_rec_ptr[1]);
|
||||
}
|
||||
|
||||
const char *raid_recX_tag(void)
|
||||
{
|
||||
return raid_tag(raid_rec_ptr[2]);
|
||||
return raid_tag((void_f*)raid_rec_ptr[2]);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user