mirror of
https://github.com/amadvance/snapraid.git
synced 2026-10-26 19:01:57 -04:00
Adds complete Cauchy RAID support and removes the mixed Power RAID.
This commit is contained in:
parent
136af37e96
commit
9a5978eb22
20 changed files with 6111 additions and 72023 deletions
20
HISTORY
20
HISTORY
|
|
@ -1,23 +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).
|
||||
For Quad Parity, and only for Quad Parity, there is a limitation of
|
||||
using no more than 21 data disks. This is a conseguence of the
|
||||
high performant parity generator matrix used.
|
||||
Extensions supporting more disks and more parities are possible,
|
||||
but not yet implemented.
|
||||
* Faster parity computation for SSSE3 and AVX CPUs.
|
||||
* Faster parity computation for ARM 64 bit CPUs.
|
||||
* Added support for RAIDTP (Triple Parity), RAIDQP (Quad Parity),
|
||||
RAIDPP (Penta Parity) and RAIDHP (Hexa parity).
|
||||
Take cate that to get good performance you need a CPU with
|
||||
SSSE3 support.
|
||||
* Faster RAID5 and RAID6 computation for ARM 64 bit CPUs.
|
||||
* In sync, if a silent error is found, directly mark the block as bad
|
||||
like in scrub, and continue with the sync process.
|
||||
* Sort files by inode when listing the directory. This improves
|
||||
|
|
|
|||
72
Makefile.am
72
Makefile.am
|
|
@ -1,6 +1,6 @@
|
|||
bin_PROGRAMS = snapraid
|
||||
check_PROGRAMS = mktest
|
||||
EXTRA_PROGRAMS = mktables
|
||||
EXTRA_PROGRAMS = mktables mkcombos
|
||||
|
||||
snapraid_SOURCES = \
|
||||
snapraid.c \
|
||||
|
|
@ -31,6 +31,9 @@ snapraid_SOURCES = \
|
|||
mktables_SOURCES = \
|
||||
mktables.c
|
||||
|
||||
mkcombos_SOURCES = \
|
||||
mkcombos.c
|
||||
|
||||
noinst_HEADERS = \
|
||||
portable.h \
|
||||
snapraid.h \
|
||||
|
|
@ -63,6 +66,7 @@ noinst_HEADERS = \
|
|||
cpu.h \
|
||||
raid.h \
|
||||
tables.h \
|
||||
combos.h \
|
||||
import.h \
|
||||
mingw.h \
|
||||
unix.h
|
||||
|
|
@ -76,7 +80,7 @@ EXTRA_DIST = \
|
|||
noautomake.sh \
|
||||
README AUTHORS HISTORY INSTALL COPYING TODO TEST INSTALL.windows \
|
||||
snapraid.d snapraid.1 snapraid.txt \
|
||||
test-raid5.conf test-raid6.conf test-raidTP.conf test-raidQP.conf test-raidQP-hole.conf \
|
||||
test-raid5.conf test-raid6.conf test-raidTP.conf test-raidQP.conf test-raidPP.conf test-raidHP.conf test-raidHP-hole.conf \
|
||||
snapraid.conf.example \
|
||||
configure.windows-x86 configure.windows-x64 snapraid.conf.example.windows \
|
||||
acinclude.m4
|
||||
|
|
@ -100,12 +104,14 @@ maintainer-clean-local:
|
|||
CHECKFLAGS = --test-skip-device --test-skip-self
|
||||
CHECKCOUNT = 2000
|
||||
CHECKSIZE = 4000
|
||||
CONF = $(srcdir)/test-raidQP.conf
|
||||
HOLE = $(srcdir)/test-raidQP-hole.conf
|
||||
CONF = $(srcdir)/test-raidHP.conf
|
||||
HOLE = $(srcdir)/test-raidHP-hole.conf
|
||||
RAID5 = $(srcdir)/test-raid5.conf
|
||||
RAID6 = $(srcdir)/test-raid6.conf
|
||||
RAIDTP = $(srcdir)/test-raidTP.conf
|
||||
RAIDQP = $(srcdir)/test-raidQP.conf
|
||||
RAIDPP = $(srcdir)/test-raidPP.conf
|
||||
RAIDHP = $(srcdir)/test-raidHP.conf
|
||||
|
||||
check-local:
|
||||
rm -rf test
|
||||
|
|
@ -116,6 +122,7 @@ check-local:
|
|||
mkdir test/disk3
|
||||
mkdir test/disk4
|
||||
mkdir test/disk5
|
||||
mkdir test/disk6
|
||||
mkdir test/pool
|
||||
echo --- Help
|
||||
$(TESTENV) ./snapraid$(EXEEXT) --test-skip-device -h
|
||||
|
|
@ -133,7 +140,7 @@ endif
|
|||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) check
|
||||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) -a check
|
||||
echo --- Create some files, sync and check in RAID5/6/TP
|
||||
$(TESTENV) ./mktest$(EXEEXT) generate 1 5 $(CHECKCOUNT) $(CHECKSIZE)
|
||||
$(TESTENV) ./mktest$(EXEEXT) generate 1 6 $(CHECKCOUNT) $(CHECKSIZE)
|
||||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -v -c $(CONF) diff > output.log
|
||||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -v -c $(CONF) diff -G > output.log
|
||||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) --test-force-order-physical sync
|
||||
|
|
@ -149,7 +156,7 @@ endif
|
|||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) check
|
||||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) -a check
|
||||
echo --- Create some more files, hardlinks and empty directories, sync RAID5 and check
|
||||
$(TESTENV) ./mktest$(EXEEXT) generate 2 5 $(CHECKCOUNT) $(CHECKSIZE)
|
||||
$(TESTENV) ./mktest$(EXEEXT) generate 2 6 $(CHECKCOUNT) $(CHECKSIZE)
|
||||
mkdir test/disk1/empty1
|
||||
mkdir test/disk2/empty2
|
||||
mkdir test/disk3/empty3a
|
||||
|
|
@ -174,7 +181,7 @@ endif
|
|||
if HAVE_SYMLINK
|
||||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(RAID5) pool
|
||||
endif
|
||||
echo --- Extend RAID5 to RAIDQP with fix and check
|
||||
echo --- Extend RAID5 to max parity with fix and check
|
||||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-expect-recoverable -c $(CONF) check -l test.log
|
||||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) fix -l test.log
|
||||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(RAID5) check
|
||||
|
|
@ -224,7 +231,7 @@ endif
|
|||
rm test/disk2/2*
|
||||
rm test/disk3/3*
|
||||
rm test/disk4/4*
|
||||
$(TESTENV) ./mktest$(EXEEXT) generate 3 5 $(CHECKCOUNT) $(CHECKSIZE)
|
||||
$(TESTENV) ./mktest$(EXEEXT) generate 3 6 $(CHECKCOUNT) $(CHECKSIZE)
|
||||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) sync
|
||||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) check
|
||||
echo --- Move some files, sync and check
|
||||
|
|
@ -240,9 +247,7 @@ endif
|
|||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-expect-recoverable -c $(RAID5) check -l test.log
|
||||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(RAID5) fix -l test.log
|
||||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) check
|
||||
echo --- Sync after all the fixes with an empty drive to test --force-empty
|
||||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --force-empty -c $(CONF) sync
|
||||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) check
|
||||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) sync
|
||||
echo --- Delete two disks, fix and check with RAID6
|
||||
rm -r test/disk1
|
||||
mkdir test/disk1
|
||||
|
|
@ -260,13 +265,42 @@ endif
|
|||
mkdir test/disk2
|
||||
rm -r test/disk3
|
||||
mkdir test/disk3
|
||||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-expect-unrecoverable -c $(RAID5) fix -l test.log
|
||||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-expect-unrecoverable -c $(RAID6) fix -l test.log
|
||||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-expect-recoverable -c $(RAIDTP) check -l test.log
|
||||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(RAIDTP) fix -l test.log
|
||||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) check
|
||||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) sync
|
||||
echo --- Delete four disks, fix and check with RAIDQP
|
||||
rm -r test/disk3
|
||||
mkdir test/disk3
|
||||
rm -r test/disk4
|
||||
mkdir test/disk4
|
||||
rm -r test/disk5
|
||||
mkdir test/disk5
|
||||
rm -r test/disk6
|
||||
mkdir test/disk6
|
||||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-expect-unrecoverable -c $(RAIDTP) fix -l test.log
|
||||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-expect-recoverable -c $(RAIDQP) check -l test.log
|
||||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(RAIDQP) fix -l test.log
|
||||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) check
|
||||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) sync
|
||||
echo --- Delete five disks, fix and check with RAIDPP
|
||||
rm -r test/disk1
|
||||
mkdir test/disk1
|
||||
rm -r test/disk2
|
||||
mkdir test/disk2
|
||||
rm -r test/disk3
|
||||
mkdir test/disk3
|
||||
rm -r test/disk5
|
||||
mkdir test/disk5
|
||||
rm -r test/disk6
|
||||
mkdir test/disk6
|
||||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-expect-unrecoverable -c $(RAIDQP) fix -l test.log
|
||||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-expect-recoverable -c $(RAIDPP) check -l test.log
|
||||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(RAIDPP) fix -l test.log
|
||||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) check
|
||||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) sync
|
||||
echo --- Delete six disks, fix and check with RAIDHP
|
||||
rm -r test/disk1
|
||||
mkdir test/disk1
|
||||
rm -r test/disk2
|
||||
|
|
@ -275,11 +309,13 @@ endif
|
|||
mkdir test/disk3
|
||||
rm -r test/disk4
|
||||
mkdir test/disk4
|
||||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-expect-unrecoverable -c $(RAID5) fix -l test.log
|
||||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-expect-unrecoverable -c $(RAID6) fix -l test.log
|
||||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-expect-unrecoverable -c $(RAIDTP) fix -l test.log
|
||||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-expect-recoverable -c $(RAIDQP) check -l test.log
|
||||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(RAIDQP) fix -l test.log
|
||||
rm -r test/disk5
|
||||
mkdir test/disk5
|
||||
rm -r test/disk6
|
||||
mkdir test/disk6
|
||||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-expect-unrecoverable -c $(RAIDPP) fix -l test.log
|
||||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-expect-recoverable -c $(RAIDHP) check -l test.log
|
||||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(RAIDHP) fix -l test.log
|
||||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) check
|
||||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) sync
|
||||
echo --- Delete some files and create some new, sync and check in multiple steps using text content
|
||||
|
|
@ -293,7 +329,7 @@ endif
|
|||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) --test-force-content-text test-rewrite
|
||||
cmp test/content test/content.txt
|
||||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) check -l test.log
|
||||
$(TESTENV) ./mktest$(EXEEXT) generate 4 5 $(CHECKCOUNT) $(CHECKSIZE)
|
||||
$(TESTENV) ./mktest$(EXEEXT) generate 4 6 $(CHECKCOUNT) $(CHECKSIZE)
|
||||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) -t 100 sync --test-force-content-text
|
||||
cp test/content test/content.txt
|
||||
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) test-rewrite
|
||||
|
|
|
|||
294
check.c
294
check.c
|
|
@ -24,6 +24,7 @@
|
|||
#include "parity.h"
|
||||
#include "handle.h"
|
||||
#include "raid.h"
|
||||
#include "combos.h"
|
||||
|
||||
/****************************************************************************/
|
||||
/* check */
|
||||
|
|
@ -89,59 +90,6 @@ static int blockcmp(struct snapraid_state* state, int rehash, struct snapraid_bl
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Combinations of 1 of 4 elements.
|
||||
*/
|
||||
static const struct combo1 {
|
||||
int a;
|
||||
} COMBO1[] = {
|
||||
{ 0 },
|
||||
{ 1 },
|
||||
{ 2 },
|
||||
{ 3 },
|
||||
};
|
||||
|
||||
/**
|
||||
* Combinations of 2 of 4 elements.
|
||||
*/
|
||||
static const struct combo2 {
|
||||
int a;
|
||||
int b;
|
||||
} COMBO2[] = {
|
||||
{ 0, 1 },
|
||||
{ 0, 2 },
|
||||
{ 0, 3 },
|
||||
{ 1, 2 },
|
||||
{ 1, 3 },
|
||||
{ 2, 3 }
|
||||
};
|
||||
|
||||
/**
|
||||
* Combinations of 3 of 4 elements.
|
||||
*/
|
||||
static const struct combo3 {
|
||||
int a;
|
||||
int b;
|
||||
int c;
|
||||
} COMBO3[] = {
|
||||
{ 0, 1, 2 },
|
||||
{ 0, 1, 3 },
|
||||
{ 0, 2, 3 },
|
||||
{ 1, 2, 3 }
|
||||
};
|
||||
|
||||
/**
|
||||
* Combinations of 4 of 4 elements.
|
||||
*/
|
||||
static const struct combo4 {
|
||||
int a;
|
||||
int b;
|
||||
int c;
|
||||
int d;
|
||||
} COMBO4[] = {
|
||||
{ 0, 1, 2, 3 },
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if the hash of at least one failed block is now matching.
|
||||
*/
|
||||
|
|
@ -164,7 +112,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(RAID_POWER, state->level, buffer, diskmax, state->block_size);
|
||||
raid_gen(state->level, buffer, diskmax, state->block_size);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -177,12 +125,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(RAID_POWER, i + 1, buffer, diskmax, state->block_size);
|
||||
raid_gen(i + 1, buffer, diskmax, state->block_size);
|
||||
|
||||
/* if the recovered parity block matches */
|
||||
if (memcmp(buffer[diskmax+i], buffer_recov[i], state->block_size) == 0) {
|
||||
/* recompute all the redundancy information */
|
||||
raid_gen(RAID_POWER, state->level, buffer, diskmax, state->block_size);
|
||||
raid_gen(state->level, buffer, diskmax, state->block_size);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -192,24 +140,33 @@ static int is_parity_matching(struct snapraid_state* state, unsigned diskmax, un
|
|||
/**
|
||||
* Repair errors.
|
||||
* Returns <0 if failure for missing strategy, >0 if data is wrong and we cannot rebuild correctly, 0 on success.
|
||||
* If success, the parity and qarity are computed in the buffer variable.
|
||||
* If success, the parity are computed in the buffer variable.
|
||||
*/
|
||||
static int repair_step(struct snapraid_state* state, int rehash, unsigned pos, unsigned diskmax, struct failed_struct* failed, unsigned* failed_map, unsigned failed_count, unsigned char** buffer, unsigned char** buffer_recov, unsigned char* buffer_zero)
|
||||
{
|
||||
unsigned i, j;
|
||||
int error;
|
||||
int has_hash;
|
||||
int kind = RAID_POWER;
|
||||
int d[LEV_MAX];
|
||||
|
||||
/* no fix required */
|
||||
if (failed_count == 0) {
|
||||
/* recompute only parity and qarity */
|
||||
raid_gen(kind, state->level, buffer, diskmax, state->block_size);
|
||||
/* recompute only the parity */
|
||||
raid_gen(state->level, buffer, diskmax, state->block_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* if too many error, we don't have any strategy */
|
||||
if (failed_count > state->level) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
error = 0;
|
||||
|
||||
/* setup vector of failed disk indexes */
|
||||
for(i=0;i<failed_count;++i)
|
||||
d[i] = failed[failed_map[i]].index;
|
||||
|
||||
/* check if there is at least a failed block that can be checked for correctness using the hash */
|
||||
/* if there isn't, we have to sacrifice a parity block to check that the result is correct */
|
||||
has_hash = 0;
|
||||
|
|
@ -218,158 +175,79 @@ static int repair_step(struct snapraid_state* state, int rehash, unsigned pos, u
|
|||
has_hash = 1;
|
||||
}
|
||||
|
||||
/* recover one block with hash */
|
||||
if (failed_count == 1 && has_hash) {
|
||||
for(i=0;i<sizeof(COMBO1)/sizeof(COMBO1[0]);++i) {
|
||||
/* if we don't have an hash, but we have an extra parity */
|
||||
if (!has_hash && failed_count < LEV_MAX) {
|
||||
/* number of parity to use, the last one is used for checking and not for recovering */
|
||||
unsigned l = failed_count + 1;
|
||||
for(i=0;combo[l-1][i][0]>=0;++i) {
|
||||
int* c = combo[l-1][i];
|
||||
|
||||
/* if parity is missing, do nothing */
|
||||
if (buffer_recov[COMBO1[i].a] == 0)
|
||||
for(j=0;j<l;++j) {
|
||||
if (buffer_recov[c[j]] == 0)
|
||||
break;
|
||||
}
|
||||
if (j != l)
|
||||
continue;
|
||||
|
||||
/* copy the redundancy to use */
|
||||
memcpy(buffer[diskmax+COMBO1[i].a], buffer_recov[COMBO1[i].a], state->block_size);
|
||||
/* copy the parity to use, one less because the last is used for checking */
|
||||
for(j=0;j<l-1;++j) {
|
||||
memcpy(buffer[diskmax+c[j]], buffer_recov[c[j]], state->block_size);
|
||||
}
|
||||
|
||||
/* recover data */
|
||||
raid_recov_1data(kind, failed[failed_map[0]].index, COMBO1[i].a, buffer, diskmax, buffer_zero, state->block_size);
|
||||
/* recover using one less parity */
|
||||
raid_recov(l-1, d, c, buffer, diskmax, buffer_zero, state->block_size);
|
||||
|
||||
/* use the remaining parity to check the result */
|
||||
if (is_parity_matching(state, diskmax, c[l-1], buffer, buffer_recov))
|
||||
return 0;
|
||||
|
||||
/* log */
|
||||
fprintf(stdlog, "parity_error:%u:", pos);
|
||||
for(j=0;j<l;++j) {
|
||||
if (j != 0)
|
||||
fprintf(stdlog, "/");
|
||||
fprintf(stdlog, "%s", lev_config_name(c[j]));
|
||||
}
|
||||
fprintf(stdlog, ": Data error\n");
|
||||
++error;
|
||||
}
|
||||
}
|
||||
|
||||
if (has_hash && failed_count <= LEV_MAX) {
|
||||
/* number of parities to use */
|
||||
unsigned l = failed_count;
|
||||
for(i=0;combo[l-1][i][0]>=0;++i) {
|
||||
int* c = combo[l-1][i];
|
||||
|
||||
/* if parity is missing, do nothing */
|
||||
for(j=0;j<l;++j) {
|
||||
if (buffer_recov[c[j]] == 0)
|
||||
break;
|
||||
}
|
||||
if (j != l)
|
||||
continue;
|
||||
|
||||
/* copy the parity to use */
|
||||
for(j=0;j<l;++j) {
|
||||
memcpy(buffer[diskmax+c[j]], buffer_recov[c[j]], state->block_size);
|
||||
}
|
||||
|
||||
/* recover */
|
||||
raid_recov(l, d, c, buffer, diskmax, buffer_zero, state->block_size);
|
||||
|
||||
/* use the hash to check the result */
|
||||
if (is_hash_matching(state, rehash, diskmax, failed, failed_map, failed_count, buffer, buffer_zero))
|
||||
return 0;
|
||||
|
||||
fprintf(stdlog, "parity_error:%u:%s: Data error\n", pos, lev_config_name(COMBO1[i].a));
|
||||
++error;
|
||||
}
|
||||
}
|
||||
|
||||
/* recover one block without hash */
|
||||
if (failed_count == 1 && !has_hash) {
|
||||
for(i=0;i<sizeof(COMBO2)/sizeof(COMBO2[0]);++i) {
|
||||
/* if parity is missing, do nothing */
|
||||
if (buffer_recov[COMBO2[i].a] == 0 || buffer_recov[COMBO2[i].b] == 0)
|
||||
continue;
|
||||
|
||||
/* copy the redundancy to use */
|
||||
memcpy(buffer[diskmax+COMBO2[i].a], buffer_recov[COMBO2[i].a], state->block_size);
|
||||
|
||||
/* recover data */
|
||||
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;
|
||||
|
||||
fprintf(stdlog, "parity_error:%u:%s/%s: Data error\n", pos, lev_config_name(COMBO2[i].a), lev_config_name(COMBO2[i].b));
|
||||
++error;
|
||||
}
|
||||
}
|
||||
|
||||
/* recover two blocks with hash */
|
||||
if (failed_count == 2 && has_hash) {
|
||||
for(i=0;i<sizeof(COMBO2)/sizeof(COMBO2[0]);++i) {
|
||||
/* if parity is missing, do nothing */
|
||||
if (buffer_recov[COMBO2[i].a] == 0 || buffer_recov[COMBO2[i].b] == 0)
|
||||
continue;
|
||||
|
||||
/* copy the redundancy to use */
|
||||
memcpy(buffer[diskmax+COMBO2[i].a], buffer_recov[COMBO2[i].a], state->block_size);
|
||||
memcpy(buffer[diskmax+COMBO2[i].b], buffer_recov[COMBO2[i].b], state->block_size);
|
||||
|
||||
/* recover data */
|
||||
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;
|
||||
|
||||
fprintf(stdlog, "parity_error:%u:%s/%s: Data error\n", pos, lev_config_name(COMBO2[i].a), lev_config_name(COMBO2[i].b));
|
||||
++error;
|
||||
}
|
||||
}
|
||||
|
||||
/* recover two blocks without hash */
|
||||
if (failed_count == 2 && !has_hash) {
|
||||
for(i=0;i<sizeof(COMBO3)/sizeof(COMBO3[0]);++i) {
|
||||
/* if parity is missing, do nothing */
|
||||
if (buffer_recov[COMBO3[i].a] == 0 || buffer_recov[COMBO3[i].b] == 0 || buffer_recov[COMBO3[i].c] == 0)
|
||||
continue;
|
||||
|
||||
/* copy the redundancy to use */
|
||||
memcpy(buffer[diskmax+COMBO3[i].a], buffer_recov[COMBO3[i].a], state->block_size);
|
||||
memcpy(buffer[diskmax+COMBO3[i].b], buffer_recov[COMBO3[i].b], state->block_size);
|
||||
|
||||
/* recover data */
|
||||
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;
|
||||
|
||||
fprintf(stdlog, "parity_error:%u:%s/%s/%s: Data error\n", pos, lev_config_name(COMBO3[i].a), lev_config_name(COMBO3[i].b), lev_config_name(COMBO3[i].c));
|
||||
++error;
|
||||
}
|
||||
}
|
||||
|
||||
/* recover three blocks with hash */
|
||||
if (failed_count == 3 && has_hash) {
|
||||
for(i=0;i<sizeof(COMBO3)/sizeof(COMBO3[0]);++i) {
|
||||
/* if parity is missing, do nothing */
|
||||
if (buffer_recov[COMBO3[i].a] == 0 || buffer_recov[COMBO3[i].b] == 0 || buffer_recov[COMBO3[i].c] == 0)
|
||||
continue;
|
||||
|
||||
/* copy the redundancy to use */
|
||||
memcpy(buffer[diskmax+COMBO3[i].a], buffer_recov[COMBO3[i].a], state->block_size);
|
||||
memcpy(buffer[diskmax+COMBO3[i].b], buffer_recov[COMBO3[i].b], state->block_size);
|
||||
memcpy(buffer[diskmax+COMBO3[i].c], buffer_recov[COMBO3[i].c], state->block_size);
|
||||
|
||||
/* recover data */
|
||||
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;
|
||||
|
||||
fprintf(stdlog, "parity_error:%u:%s/%s/%s: Data error\n", pos, lev_config_name(COMBO3[i].a), lev_config_name(COMBO3[i].b), lev_config_name(COMBO3[i].c));
|
||||
++error;
|
||||
}
|
||||
}
|
||||
|
||||
/* recover three blocks without hash */
|
||||
if (failed_count == 3 && !has_hash) {
|
||||
for(i=0;i<sizeof(COMBO4)/sizeof(COMBO4[0]);++i) {
|
||||
/* if parity is missing, do nothing */
|
||||
if (buffer_recov[COMBO4[i].a] == 0 || buffer_recov[COMBO4[i].b] == 0 || buffer_recov[COMBO4[i].c] == 0 || buffer_recov[COMBO4[i].d] == 0)
|
||||
continue;
|
||||
|
||||
/* copy the redundancy to use */
|
||||
memcpy(buffer[diskmax+COMBO4[i].a], buffer_recov[COMBO4[i].a], state->block_size);
|
||||
memcpy(buffer[diskmax+COMBO4[i].b], buffer_recov[COMBO4[i].b], state->block_size);
|
||||
memcpy(buffer[diskmax+COMBO4[i].c], buffer_recov[COMBO4[i].c], state->block_size);
|
||||
|
||||
/* recover data */
|
||||
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;
|
||||
|
||||
fprintf(stdlog, "parity_error:%u:%s/%s/%s/%s: Data error\n", pos, lev_config_name(COMBO4[i].a), lev_config_name(COMBO4[i].b), lev_config_name(COMBO4[i].c), lev_config_name(COMBO4[i].d));
|
||||
++error;
|
||||
}
|
||||
}
|
||||
|
||||
/* recover four blocks with hash */
|
||||
if (failed_count == 4 && has_hash) {
|
||||
for(i=0;i<sizeof(COMBO4)/sizeof(COMBO4[0]);++i) {
|
||||
/* if parity is missing, do nothing */
|
||||
if (buffer_recov[COMBO4[i].a] == 0 || buffer_recov[COMBO4[i].b] == 0 || buffer_recov[COMBO4[i].c] == 0 || buffer_recov[COMBO4[i].d] == 0)
|
||||
continue;
|
||||
|
||||
/* copy the redundancy to use */
|
||||
memcpy(buffer[diskmax+COMBO4[i].a], buffer_recov[COMBO4[i].a], state->block_size);
|
||||
memcpy(buffer[diskmax+COMBO4[i].b], buffer_recov[COMBO4[i].b], state->block_size);
|
||||
memcpy(buffer[diskmax+COMBO4[i].c], buffer_recov[COMBO4[i].c], state->block_size);
|
||||
memcpy(buffer[diskmax+COMBO4[i].d], buffer_recov[COMBO4[i].d], state->block_size);
|
||||
|
||||
/* recover data */
|
||||
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;
|
||||
|
||||
fprintf(stdlog, "parity_error:%u:%s/%s/%s/%s: Data error\n", pos, lev_config_name(COMBO4[i].a), lev_config_name(COMBO4[i].b), lev_config_name(COMBO4[i].c), lev_config_name(COMBO4[i].d));
|
||||
/* log */
|
||||
fprintf(stdlog, "parity_error:%u:", pos);
|
||||
for(j=0;j<l;++j) {
|
||||
if (j != 0)
|
||||
fprintf(stdlog, "/");
|
||||
fprintf(stdlog, "%s", lev_config_name(c[j]));
|
||||
}
|
||||
fprintf(stdlog, ": Data error\n");
|
||||
++error;
|
||||
}
|
||||
}
|
||||
|
|
@ -440,8 +318,8 @@ 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(RAID_POWER, state->level, buffer, diskmax, state->block_size);
|
||||
/* recompute only the parity */
|
||||
raid_gen(state->level, buffer, diskmax, state->block_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -686,8 +564,10 @@ static int state_check_process(struct snapraid_state* state, int check, int fix,
|
|||
/* keep track of the number of failed blocks */
|
||||
failed_count = 0;
|
||||
|
||||
/* if we have to use the old hash */
|
||||
/* get block specific info */
|
||||
info = info_get(&state->infoarr, i);
|
||||
|
||||
/* if we have to use the old hash */
|
||||
rehash = info_get_rehash(info);
|
||||
|
||||
/* for each disk, process the block */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
dnl Process this file with autoconf to produce a configure script.
|
||||
AC_PREREQ([2.65])
|
||||
AC_INIT([snapraid], [6.0], [], [], [http://snapraid.sourceforge.net])
|
||||
AC_INIT([snapraid], [5.0], [], [], [http://snapraid.sourceforge.net])
|
||||
AM_INIT_AUTOMAKE([foreign no-dependencies -Wall])
|
||||
AC_CONFIG_SRCDIR([snapraid.c])
|
||||
AC_CONFIG_HEADER([config.h])
|
||||
|
|
|
|||
1
elem.h
1
elem.h
|
|
@ -828,7 +828,6 @@ static inline snapraid_info info_set_bad(snapraid_info info)
|
|||
return info | 0x1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Marks the block address as with rehash.
|
||||
*/
|
||||
|
|
|
|||
285
mktables.c
285
mktables.c
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2011 Andrea Mazzoleni
|
||||
* 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
|
||||
|
|
@ -17,6 +17,9 @@
|
|||
|
||||
#include <stdio.h>
|
||||
|
||||
/**
|
||||
* Multiplication in GF(2^8).
|
||||
*/
|
||||
unsigned char gfmul(unsigned char a, unsigned char b)
|
||||
{
|
||||
unsigned char v;
|
||||
|
|
@ -39,72 +42,96 @@ unsigned char gfmul(unsigned char a, unsigned char b)
|
|||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inversion table in GF(2^8).
|
||||
*/
|
||||
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.
|
||||
* Number of parity.
|
||||
* This is the number of rows of the generation matrix.
|
||||
*/
|
||||
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))
|
||||
#define PARITY 6
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* Number of disks.
|
||||
* This is the number of columns of the generation matrix.
|
||||
*/
|
||||
#define DISK (257-PARITY)
|
||||
|
||||
/**
|
||||
* Setup the Normalized Extended Cauchy matrix used to generate the parity.
|
||||
*/
|
||||
void set_cauchy(unsigned char* matrix)
|
||||
{
|
||||
int i, j;
|
||||
unsigned char cv, rv;
|
||||
unsigned char inv_x, y;
|
||||
|
||||
/* first row all 1, this is an Extended Cauchy matrix */
|
||||
for(i=0;i<CAUCHY_DISK;++i) {
|
||||
matrix[0*CAUCHY_DISK+i] = 1;
|
||||
/*
|
||||
* First row is formed by all 1.
|
||||
*
|
||||
* This is an Extended Cauchy matrix built from a Cauchy matrix
|
||||
* adding the first row of all 1.
|
||||
*/
|
||||
for(i=0;i<DISK;++i) {
|
||||
matrix[0*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);
|
||||
/*
|
||||
* Second row is formed by power of 2^i.
|
||||
*
|
||||
* This is the first row of the Cauchy matrix.
|
||||
*
|
||||
* Each element of the Cauchy matrix is in the form 1/(xi+yj)
|
||||
* where all xi, and yj must be different.
|
||||
*
|
||||
* Choosing xi = 2^-i and y0 = 0, we obtain for the first row:
|
||||
*
|
||||
* 1/(xi+y0) = 1/(2^-i + 0) = 2^i
|
||||
*
|
||||
* with 2^-i != 0 for any i
|
||||
*/
|
||||
inv_x = 1;
|
||||
for(i=0;i<DISK;++i) {
|
||||
matrix[1*DISK+i] = inv_x;
|
||||
inv_x = gfmul(2, inv_x);
|
||||
}
|
||||
|
||||
/* other rows using a Cauchy matrix */
|
||||
rv = 2;
|
||||
for(j=0;j<CAUCHY_PARITY-2;++j) {
|
||||
unsigned char ce;
|
||||
/*
|
||||
* Next rows of the Cauchy matrix.
|
||||
*
|
||||
* We continue forming the Cauchy matrix with yj = 2^j obtaining :
|
||||
*
|
||||
* 1/(xi+yj) = 1/(2^-i + 2^j)
|
||||
*
|
||||
* with xi != yj for any i,j with i>=0,j>=1,i+j<256
|
||||
*/
|
||||
y = 2;
|
||||
for(j=0;j<PARITY-2;++j) {
|
||||
|
||||
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);
|
||||
inv_x = 1;
|
||||
for(i=0;i<DISK;++i) {
|
||||
unsigned char x = gfinv[inv_x];
|
||||
matrix[(j+2)*DISK+i] = gfinv[y ^ x];
|
||||
inv_x = gfmul(2, inv_x);
|
||||
}
|
||||
|
||||
rv = gfmul(2, rv);
|
||||
y = gfmul(2, y);
|
||||
}
|
||||
|
||||
/*
|
||||
* Normalizes the matrix multipling each row for
|
||||
* the inverse of the first element in the row.
|
||||
*
|
||||
* This operation doesn't invalidate the property that all the square
|
||||
* submatrices are not singular.
|
||||
*/
|
||||
for(j=0;j<PARITY-2;++j) {
|
||||
unsigned char f = gfinv[matrix[(j+2)*DISK]];
|
||||
|
||||
for(i=0;i<DISK;++i) {
|
||||
matrix[(j+2)*DISK+i] = gfmul(matrix[(j+2)*DISK+i], f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -128,10 +155,10 @@ int main(void)
|
|||
{
|
||||
unsigned char v;
|
||||
int i, j, k, p;
|
||||
unsigned char matrix[8 * 256];
|
||||
unsigned char matrix[PARITY * 256];
|
||||
|
||||
printf("/*\n");
|
||||
printf(" * Copyright (C) 2011 Andrea Mazzoleni\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");
|
||||
|
|
@ -185,22 +212,6 @@ int main(void)
|
|||
}
|
||||
printf("};\n\n");
|
||||
|
||||
/* 4^a */
|
||||
printf("const unsigned char __attribute__((aligned(256))) gfexp4[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, 4);
|
||||
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");
|
||||
|
|
@ -220,115 +231,29 @@ int main(void)
|
|||
}
|
||||
printf("};\n\n");
|
||||
|
||||
/* x4l */
|
||||
printf("#define GFX4L { ");
|
||||
for(i=0;i<16;++i) {
|
||||
v = gfmul(0x4, i);
|
||||
printf("0x%02x", (unsigned)v);
|
||||
if (i != 15)
|
||||
printf(", ");
|
||||
}
|
||||
printf(" }\n");
|
||||
|
||||
/* x4h */
|
||||
printf("#define GFX4H { ");
|
||||
for(i=0;i<16;++i) {
|
||||
v = gfmul(0x40, i);
|
||||
printf("0x%02x", (unsigned)v);
|
||||
if (i != 15)
|
||||
printf(", ");
|
||||
}
|
||||
printf(" }\n");
|
||||
|
||||
/* x8l */
|
||||
printf("#define GFX8L { ");
|
||||
for(i=0;i<16;++i) {
|
||||
v = gfmul(0x8, i);
|
||||
printf("0x%02x", (unsigned)v);
|
||||
if (i != 15)
|
||||
printf(", ");
|
||||
}
|
||||
printf(" }\n");
|
||||
|
||||
/* x8h */
|
||||
printf("#define GFX8H { ");
|
||||
for(i=0;i<16;++i) {
|
||||
v = gfmul(0x80, i);
|
||||
printf("0x%02x", (unsigned)v);
|
||||
if (i != 15)
|
||||
printf(", ");
|
||||
}
|
||||
printf(" }\n");
|
||||
|
||||
/* poly */
|
||||
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 */
|
||||
/* cauchy 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(" * This matrix is valid for up to %u parity with %u data disks.\n", PARITY, DISK);
|
||||
printf(" *\n");
|
||||
for(p=0;p<CAUCHY_PARITY;++p) {
|
||||
for(p=0;p<PARITY;++p) {
|
||||
printf(" * ");
|
||||
for(i=0;i<CAUCHY_DISK;++i) {
|
||||
printf("%02x ", matrix[p*CAUCHY_DISK+i]);
|
||||
for(i=0;i<DISK;++i) {
|
||||
printf("%02x ", matrix[p*DISK+i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
printf(" */\n");
|
||||
printf("const unsigned char __attribute__((aligned(256))) gfmatrix_cauchy[%u][256] =\n", CAUCHY_PARITY);
|
||||
printf("const unsigned char __attribute__((aligned(256))) gfmatrix[%u][256] =\n", PARITY);
|
||||
printf("{\n");
|
||||
for(p=0;p<CAUCHY_PARITY;++p) {
|
||||
for(p=0;p<PARITY;++p) {
|
||||
printf("\t{\n");
|
||||
for(i=0;i<CAUCHY_DISK;++i) {
|
||||
for(i=0;i<DISK;++i) {
|
||||
if (i % 8 == 0)
|
||||
printf("\t\t");
|
||||
printf("0x%02x,", matrix[p*CAUCHY_DISK+i]);
|
||||
printf("0x%02x,", matrix[p*DISK+i]);
|
||||
if (i % 8 == 7)
|
||||
printf("\n");
|
||||
else
|
||||
|
|
@ -338,47 +263,23 @@ int main(void)
|
|||
}
|
||||
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(" * 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 unsigned char __attribute__((aligned(256))) gfcauchy_pshufb[%u][%u][2][16] =\n", CAUCHY_DISK, np(CAUCHY_PARITY - 2));
|
||||
printf("const unsigned char __attribute__((aligned(256))) gfpshufb[%u][%u][2][16] =\n", DISK, np(PARITY - 2));
|
||||
printf("{\n");
|
||||
for(i=0;i<CAUCHY_DISK;++i) {
|
||||
for(i=0;i<DISK;++i) {
|
||||
printf("\t{\n");
|
||||
for(p=2;p<CAUCHY_PARITY;++p) {
|
||||
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*CAUCHY_DISK+i], k);
|
||||
v = gfmul(matrix[p*DISK+i], k);
|
||||
if (j == 1)
|
||||
v = gfmul(v, 16);
|
||||
printf("0x%02x", (unsigned)v);
|
||||
|
|
|
|||
99
raid.h
99
raid.h
|
|
@ -22,25 +22,9 @@
|
|||
/* raid */
|
||||
|
||||
/**
|
||||
* Kind of generator matrix used.
|
||||
* Max number of data disks.
|
||||
*/
|
||||
#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 RAID_POWER for up to TripleParity.
|
||||
*/
|
||||
#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
|
||||
#define RAID_DATA_LIMIT 251
|
||||
|
||||
/**
|
||||
* Initializes the RAID system.
|
||||
|
|
@ -48,61 +32,42 @@
|
|||
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.
|
||||
* Computes the parity.
|
||||
* \param level Number of parities level to compute. Starting from 1.
|
||||
* \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 kind, unsigned level, unsigned char** vbuf, unsigned data, unsigned size);
|
||||
void raid_gen(unsigned level, unsigned char** vbuf, unsigned data, unsigned size);
|
||||
|
||||
/*
|
||||
* Recovers failure of one data block x using parity i.
|
||||
* Note that only the data block is recovered. The full parity is instead destroyed.
|
||||
* \param x Index of the data disk to recover. Starting from 0.
|
||||
* \param i Index of the parity to use for the recovering. Starting from 0.
|
||||
/**
|
||||
* Recovers failures of data disks using the specified parities.
|
||||
* Note that only the data blocks are recovered. The parity is destroyed.
|
||||
* \param level Number of failed disks. Starting from 1.
|
||||
* \param d[] Vector of indexes of the data disk to recover. Starting from 0.
|
||||
* \param p[] Vector of indexes of the parity to use for the recovering. Starting from 0.
|
||||
* \param vbuf Vector of pointers to the blocks for disks and parities.
|
||||
* It has (::data + ::i + 1) elements. Each element points to a buffer of ::size bytes.
|
||||
* It has (::data + ::level) elements. Each element points to a buffer of ::size bytes.
|
||||
* \param data Number of data disks.
|
||||
* \param zero Buffer filled with 0 of ::size bytes.
|
||||
* This buffer is not modified.
|
||||
* \param zero Buffer filled with 0 of ::size bytes. This buffer is not modified.
|
||||
* \param size Size of the blocks pointed by vbuf.
|
||||
*/
|
||||
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(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(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(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);
|
||||
void raid_recov(unsigned level, int* d, int* p, unsigned char** vbuf, unsigned data, unsigned char* zero, unsigned size);
|
||||
|
||||
/**
|
||||
* Gets the name of the selected function to compute parity.
|
||||
* Only for testing.
|
||||
*/
|
||||
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);
|
||||
const char* raidPP_tag(void);
|
||||
const char* raidHP_tag(void);
|
||||
|
||||
/**
|
||||
* Internal specialized parity computation.
|
||||
* Specialized parity computation.
|
||||
* Only for testing.
|
||||
*/
|
||||
void raid5_int32(unsigned char** vbuf, unsigned data, unsigned size);
|
||||
|
|
@ -114,30 +79,18 @@ void raid6_int64(unsigned char** vbuf, unsigned data, unsigned size);
|
|||
void raid6_mmx(unsigned char** vbuf, unsigned data, unsigned size);
|
||||
void raid6_sse2(unsigned char** vbuf, unsigned data, unsigned size);
|
||||
void raid6_sse2ext(unsigned char** vbuf, unsigned data, unsigned size);
|
||||
void raidTP_int32(unsigned char** vbuf, unsigned data, unsigned size);
|
||||
void raidTP_int64(unsigned char** vbuf, unsigned data, unsigned size);
|
||||
void raidTP_mmx(unsigned char** vbuf, unsigned data, unsigned size);
|
||||
void raidTP_sse2(unsigned char** vbuf, unsigned data, unsigned size);
|
||||
void raidTP_sse2ext(unsigned char** vbuf, unsigned data, unsigned size);
|
||||
void raidTP_int8(unsigned char** vbuf, unsigned data, unsigned size);
|
||||
void raidTP_ssse3(unsigned char** vbuf, unsigned data, unsigned size);
|
||||
void raidTP_ssse3ext(unsigned char** vbuf, unsigned data, unsigned size);
|
||||
void raidQP_int32(unsigned char** vbuf, unsigned data, unsigned size);
|
||||
void raidQP_int64(unsigned char** vbuf, unsigned data, unsigned size);
|
||||
void raidQP_mmx(unsigned char** vbuf, unsigned data, unsigned size);
|
||||
void raidQP_sse2(unsigned char** vbuf, unsigned data, unsigned size);
|
||||
void raidQP_sse2ext(unsigned char** vbuf, unsigned data, unsigned size);
|
||||
void raidQP_int8(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);
|
||||
void raidPP_int8(unsigned char** vbuf, unsigned data, unsigned size);
|
||||
void raidPP_ssse3(unsigned char** vbuf, unsigned data, unsigned size);
|
||||
void raidPP_ssse3ext(unsigned char** vbuf, unsigned data, unsigned size);
|
||||
void raidHP_int8(unsigned char** vbuf, unsigned data, unsigned size);
|
||||
void raidHP_ssse3(unsigned char** vbuf, unsigned data, unsigned size);
|
||||
void raidHP_ssse3ext(unsigned char** vbuf, unsigned data, unsigned size);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
4
scrub.c
4
scrub.c
|
|
@ -315,7 +315,7 @@ static int state_scrub_process(struct snapraid_state* state, struct snapraid_par
|
|||
}
|
||||
|
||||
/* compute the parity */
|
||||
raid_gen(RAID_POWER, state->level, buffer, diskmax, state->block_size);
|
||||
raid_gen(state->level, buffer, diskmax, state->block_size);
|
||||
|
||||
/* compare the parity */
|
||||
for(l=0;l<state->level;++l) {
|
||||
|
|
@ -341,7 +341,7 @@ static int state_scrub_process(struct snapraid_state* state, struct snapraid_par
|
|||
/* do nothing, as this is a generic error */
|
||||
/* likely caused by a not synched array */
|
||||
} else {
|
||||
/* if rehash is neeed */
|
||||
/* if rehash is needed */
|
||||
if (rehash) {
|
||||
/* store all the new hash already computed */
|
||||
for(j=0;j<diskmax;++j) {
|
||||
|
|
|
|||
589
selftest.c
589
selftest.c
|
|
@ -23,6 +23,7 @@
|
|||
#include "cpu.h"
|
||||
#include "elem.h"
|
||||
#include "state.h"
|
||||
#include "combos.h"
|
||||
|
||||
struct hash_test_vector {
|
||||
const char* data;
|
||||
|
|
@ -46,280 +47,276 @@ static struct hash_test_vector TEST_SPOOKY2[] = {
|
|||
{ 0, 0, { 0 } }
|
||||
};
|
||||
|
||||
static void recovtest(unsigned kind, unsigned diskmax, unsigned block_size)
|
||||
static void recovtest(int diskmax, unsigned block_size)
|
||||
{
|
||||
void* buffer_alloc;
|
||||
unsigned char** buffer;
|
||||
unsigned char* buffer_test0;
|
||||
unsigned char* buffer_test1;
|
||||
unsigned char* buffer_test2;
|
||||
unsigned char* buffer_test3;
|
||||
unsigned char* buffer_zero;
|
||||
unsigned char* buffer_bad;
|
||||
unsigned char** data;
|
||||
unsigned char** parity;
|
||||
unsigned char** test;
|
||||
unsigned char* data_save[LEV_MAX];
|
||||
unsigned char* parity_save[LEV_MAX];
|
||||
unsigned char* zero;
|
||||
unsigned char* waste;
|
||||
unsigned buffermax;
|
||||
unsigned level;
|
||||
unsigned i, j, k, l;
|
||||
unsigned n;
|
||||
int d[LEV_MAX];
|
||||
int i;
|
||||
unsigned j;
|
||||
|
||||
struct combo1 {
|
||||
int ignore[3];
|
||||
int use;
|
||||
} COMBO1[] = {
|
||||
{ { 1, 2, 3 }, 0 },
|
||||
{ { 0, 2, 3 }, 1 },
|
||||
{ { 0, 1, 3 }, 2 },
|
||||
{ { 0, 1, 2 }, 3 }
|
||||
};
|
||||
|
||||
struct combo2 {
|
||||
int ignore[2];
|
||||
int use[2];
|
||||
} COMBO2[] = {
|
||||
{ { 0, 1 }, { 2, 3 } },
|
||||
{ { 0, 2 }, { 1, 3 } },
|
||||
{ { 0, 3 }, { 1, 2 } },
|
||||
{ { 1, 2 }, { 0, 3 } },
|
||||
{ { 1, 3 }, { 0, 2 } },
|
||||
{ { 2, 3 }, { 0, 1 } }
|
||||
};
|
||||
|
||||
struct combo3 {
|
||||
int ignore;
|
||||
int use[3];
|
||||
} COMBO3[] = {
|
||||
{ 0, { 1, 2, 3 } },
|
||||
{ 1, { 0, 2, 3 } },
|
||||
{ 2, { 0, 1, 3 } },
|
||||
{ 3, { 0, 1, 2 } }
|
||||
};
|
||||
|
||||
if (kind == RAID_POWER) {
|
||||
level = 4;
|
||||
} else {
|
||||
level = 4; /* TODO preliminary support limited to 4 parity */
|
||||
}
|
||||
|
||||
buffermax = diskmax + level * 2 + 1 + 1;
|
||||
buffermax = diskmax + LEV_MAX * 2 + 2;
|
||||
|
||||
buffer = malloc_nofail_vector_align(buffermax, block_size, &buffer_alloc);
|
||||
|
||||
buffer_test0 = buffer[buffermax-6];
|
||||
buffer_test1 = buffer[buffermax-5];
|
||||
buffer_test2 = buffer[buffermax-4];
|
||||
buffer_test3 = buffer[buffermax-3];
|
||||
buffer_zero = buffer[buffermax-2];
|
||||
buffer_bad = buffer[buffermax-1];
|
||||
memset(buffer_zero, 0, block_size);
|
||||
memset(buffer_bad, 0xA5, block_size);
|
||||
data = buffer;
|
||||
parity = buffer + diskmax;
|
||||
test = buffer + diskmax + LEV_MAX;
|
||||
|
||||
/* fill with random */
|
||||
for(i=0;i<LEV_MAX;++i)
|
||||
parity_save[i] = parity[i];
|
||||
|
||||
zero = buffer[buffermax-2];
|
||||
memset(zero, 0, block_size);
|
||||
|
||||
waste = buffer[buffermax-1];
|
||||
|
||||
/* fill data disk with random */
|
||||
for(i=0;i<diskmax;++i) {
|
||||
for(j=0;j<block_size;++j)
|
||||
buffer[i][j] = rand();
|
||||
data[i][j] = rand();
|
||||
}
|
||||
|
||||
/* compute the parity */
|
||||
raid_gen(kind, level, buffer, diskmax, block_size);
|
||||
raid_gen(LEV_MAX, buffer, diskmax, block_size);
|
||||
|
||||
/* check 4data */
|
||||
for(i=0;i<diskmax;++i) {
|
||||
for(j=i+1;j<diskmax;++j) {
|
||||
for(k=j+1;k<diskmax;++k) {
|
||||
for(l=k+1;l<diskmax;++l) {
|
||||
unsigned char* a;
|
||||
unsigned char* b;
|
||||
unsigned char* c;
|
||||
unsigned char* d;
|
||||
/* set all the parity to the waste buffer */
|
||||
for(i=0;i<LEV_MAX;++i)
|
||||
parity[i] = waste;
|
||||
|
||||
/* enforce the limit */
|
||||
if (kind == RAID_POWER && diskmax > RAID_POWER_QP_DATA_LIMIT && l >= 3)
|
||||
continue;
|
||||
|
||||
/* save */
|
||||
a = buffer[i];
|
||||
b = buffer[j];
|
||||
c = buffer[k];
|
||||
d = buffer[l];
|
||||
|
||||
/* damage */
|
||||
buffer[i] = buffer_test0;
|
||||
buffer[j] = buffer_test1;
|
||||
buffer[k] = buffer_test2;
|
||||
buffer[l] = buffer_test3;
|
||||
|
||||
/* recover */
|
||||
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
|
||||
|| memcmp(buffer_test1, b, block_size) != 0
|
||||
|| memcmp(buffer_test2, c, block_size) != 0
|
||||
|| memcmp(buffer_test3, d, block_size) != 0
|
||||
) {
|
||||
fprintf(stderr, "Failed RAID test\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* restore */
|
||||
buffer[i] = a;
|
||||
buffer[j] = b;
|
||||
buffer[k] = c;
|
||||
buffer[l] = d;
|
||||
}
|
||||
/* check 6data */
|
||||
for(d[0]=0;d[0]<diskmax;++d[0]) {
|
||||
for(d[1]=d[0]+1;d[1]<diskmax;++d[1]) {
|
||||
for(d[2]=d[1]+1;d[2]<diskmax;++d[2]) {
|
||||
for(d[3]=d[2]+1;d[3]<diskmax;++d[3]) {
|
||||
for(d[4]=d[3]+1;d[4]<diskmax;++d[4]) {
|
||||
for(d[5]=d[4]+1;d[5]<diskmax;++d[5]) {
|
||||
for(i=0;combo[5][i][0]>=0;++i) {
|
||||
/* set */
|
||||
for(j=0;j<6;++j) {
|
||||
/* remove the missing data */
|
||||
data_save[j] = data[d[j]];
|
||||
data[d[j]] = test[j];
|
||||
/* set the parity to use */
|
||||
parity[combo[5][i][j]] = parity_save[combo[5][i][j]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* check 3data */
|
||||
for(i=0;i<diskmax;++i) {
|
||||
for(j=i+1;j<diskmax;++j) {
|
||||
for(k=j+1;k<diskmax;++k) {
|
||||
for(n=0;n<sizeof(COMBO3)/sizeof(COMBO3[0]);++n) {
|
||||
unsigned char* a;
|
||||
unsigned char* b;
|
||||
unsigned char* c;
|
||||
unsigned char* p;
|
||||
/* recover */
|
||||
raid_recov(6, d, combo[5][i], buffer, diskmax, zero, block_size);
|
||||
|
||||
/* 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 */
|
||||
a = buffer[i];
|
||||
b = buffer[j];
|
||||
c = buffer[k];
|
||||
|
||||
/* damage */
|
||||
buffer[i] = buffer_test0;
|
||||
buffer[j] = buffer_test1;
|
||||
buffer[k] = buffer_test2;
|
||||
|
||||
/* ignore parity */
|
||||
l = diskmax + COMBO3[n].ignore;
|
||||
p = buffer[l];
|
||||
buffer[l] = buffer_bad;
|
||||
|
||||
/* recover ignoring p */
|
||||
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
|
||||
|| memcmp(buffer_test1, b, block_size) != 0
|
||||
|| memcmp(buffer_test2, c, block_size) != 0
|
||||
) {
|
||||
fprintf(stderr, "Failed RAID test\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* restore parity */
|
||||
buffer[l] = p;
|
||||
|
||||
/* restore */
|
||||
buffer[i] = a;
|
||||
buffer[j] = b;
|
||||
buffer[k] = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* check 2data */
|
||||
for(i=0;i<diskmax;++i) {
|
||||
for(j=i+1;j<diskmax;++j) {
|
||||
for(n=0;n<sizeof(COMBO2)/sizeof(COMBO2[0]);++n) {
|
||||
unsigned char* a;
|
||||
unsigned char* b;
|
||||
unsigned char* p;
|
||||
unsigned char* q;
|
||||
|
||||
/* 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];
|
||||
|
||||
/* damage */
|
||||
buffer[i] = buffer_test0;
|
||||
buffer[j] = buffer_test1;
|
||||
|
||||
/* ignore parity */
|
||||
k = diskmax + COMBO2[n].ignore[0];
|
||||
l = diskmax + COMBO2[n].ignore[1];
|
||||
p = buffer[k];
|
||||
q = buffer[l];
|
||||
buffer[k] = buffer_bad;
|
||||
buffer[l] = buffer_bad;
|
||||
|
||||
/* recover */
|
||||
raid_recov_2data(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
|
||||
|| memcmp(buffer_test1, b, block_size) != 0
|
||||
) {
|
||||
/* check */
|
||||
for(j=0;j<6;++j) {
|
||||
if (memcmp(test[j], data_save[j], block_size) != 0) {
|
||||
fprintf(stderr, "Failed RAID test\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/* restore parity */
|
||||
buffer[k] = p;
|
||||
buffer[l] = q;
|
||||
|
||||
/* restore */
|
||||
buffer[i] = a;
|
||||
buffer[j] = b;
|
||||
/* restore */
|
||||
for(j=0;j<6;++j) {
|
||||
/* restore the data */
|
||||
data[d[j]] = data_save[j];
|
||||
/* restore the parity */
|
||||
parity[combo[5][i][j]] = waste;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* check 1data */
|
||||
for(n=0;n<sizeof(COMBO1)/sizeof(COMBO1[0]);++n) {
|
||||
for(i=0;i<diskmax;++i) {
|
||||
unsigned char* a;
|
||||
unsigned char* p;
|
||||
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];
|
||||
|
||||
/* damage */
|
||||
buffer[i] = buffer_test0;
|
||||
|
||||
/* ignore parity */
|
||||
j = diskmax + COMBO1[n].ignore[0];
|
||||
k = diskmax + COMBO1[n].ignore[1];
|
||||
l = diskmax + COMBO1[n].ignore[2];
|
||||
p = buffer[j];
|
||||
q = buffer[k];
|
||||
r = buffer[l];
|
||||
buffer[j] = buffer_bad;
|
||||
buffer[k] = buffer_bad;
|
||||
buffer[l] = buffer_bad;
|
||||
|
||||
/* recover */
|
||||
raid_recov_1data(kind, i, COMBO1[n].use, buffer, diskmax, buffer_zero, block_size);
|
||||
|
||||
/* check */
|
||||
if (memcmp(buffer_test0, a, block_size) != 0) {
|
||||
fprintf(stderr, "Failed RAID test\n");
|
||||
exit(EXIT_FAILURE);
|
||||
/* check 5data */
|
||||
for(d[0]=0;d[0]<diskmax;++d[0]) {
|
||||
for(d[1]=d[0]+1;d[1]<diskmax;++d[1]) {
|
||||
for(d[2]=d[1]+1;d[2]<diskmax;++d[2]) {
|
||||
for(d[3]=d[2]+1;d[3]<diskmax;++d[3]) {
|
||||
for(d[4]=d[3]+1;d[4]<diskmax;++d[4]) {
|
||||
for(i=0;combo[4][i][0]>=0;++i) {
|
||||
/* set */
|
||||
for(j=0;j<5;++j) {
|
||||
/* remove the missing data */
|
||||
data_save[j] = data[d[j]];
|
||||
data[d[j]] = test[j];
|
||||
/* set the parity to use */
|
||||
parity[combo[4][i][j]] = parity_save[combo[4][i][j]];
|
||||
}
|
||||
|
||||
/* restore parity */
|
||||
buffer[j] = p;
|
||||
buffer[k] = q;
|
||||
buffer[l] = r;
|
||||
/* recover */
|
||||
raid_recov(5, d, combo[4][i], buffer, diskmax, zero, block_size);
|
||||
|
||||
/* check */
|
||||
for(j=0;j<5;++j) {
|
||||
if (memcmp(test[j], data_save[j], block_size) != 0) {
|
||||
fprintf(stderr, "Failed RAID test\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/* restore */
|
||||
buffer[i] = a;
|
||||
for(j=0;j<5;++j) {
|
||||
/* restore the data */
|
||||
data[d[j]] = data_save[j];
|
||||
/* restore the parity */
|
||||
parity[combo[4][i][j]] = waste;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* check 4data */
|
||||
for(d[0]=0;d[0]<diskmax;++d[0]) {
|
||||
for(d[1]=d[0]+1;d[1]<diskmax;++d[1]) {
|
||||
for(d[2]=d[1]+1;d[2]<diskmax;++d[2]) {
|
||||
for(d[3]=d[2]+1;d[3]<diskmax;++d[3]) {
|
||||
for(i=0;combo[3][i][0]>=0;++i) {
|
||||
/* set */
|
||||
for(j=0;j<4;++j) {
|
||||
/* remove the missing data */
|
||||
data_save[j] = data[d[j]];
|
||||
data[d[j]] = test[j];
|
||||
/* set the parity to use */
|
||||
parity[combo[3][i][j]] = parity_save[combo[3][i][j]];
|
||||
}
|
||||
|
||||
/* recover */
|
||||
raid_recov(4, d, combo[3][i], buffer, diskmax, zero, block_size);
|
||||
|
||||
/* check */
|
||||
for(j=0;j<4;++j) {
|
||||
if (memcmp(test[j], data_save[j], block_size) != 0) {
|
||||
fprintf(stderr, "Failed RAID test\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/* restore */
|
||||
for(j=0;j<4;++j) {
|
||||
/* restore the data */
|
||||
data[d[j]] = data_save[j];
|
||||
/* restore the parity */
|
||||
parity[combo[3][i][j]] = waste;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* check 3data */
|
||||
for(d[0]=0;d[0]<diskmax;++d[0]) {
|
||||
for(d[1]=d[0]+1;d[1]<diskmax;++d[1]) {
|
||||
for(d[2]=d[1]+1;d[2]<diskmax;++d[2]) {
|
||||
for(i=0;combo[2][i][0]>=0;++i) {
|
||||
/* set */
|
||||
for(j=0;j<3;++j) {
|
||||
/* remove the missing data */
|
||||
data_save[j] = data[d[j]];
|
||||
data[d[j]] = test[j];
|
||||
/* set the parity to use */
|
||||
parity[combo[2][i][j]] = parity_save[combo[2][i][j]];
|
||||
}
|
||||
|
||||
/* recover */
|
||||
raid_recov(3, d, combo[2][i], buffer, diskmax, zero, block_size);
|
||||
|
||||
/* check */
|
||||
for(j=0;j<3;++j) {
|
||||
if (memcmp(test[j], data_save[j], block_size) != 0) {
|
||||
fprintf(stderr, "Failed RAID test\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/* restore */
|
||||
for(j=0;j<3;++j) {
|
||||
/* restore the data */
|
||||
data[d[j]] = data_save[j];
|
||||
/* restore the parity */
|
||||
parity[combo[2][i][j]] = waste;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* check 2data */
|
||||
for(d[0]=0;d[0]<diskmax;++d[0]) {
|
||||
for(d[1]=d[0]+1;d[1]<diskmax;++d[1]) {
|
||||
for(i=0;combo[1][i][0]>=0;++i) {
|
||||
/* set */
|
||||
for(j=0;j<2;++j) {
|
||||
/* remove the missing data */
|
||||
data_save[j] = data[d[j]];
|
||||
data[d[j]] = test[j];
|
||||
/* set the parity to use */
|
||||
parity[combo[1][i][j]] = parity_save[combo[1][i][j]];
|
||||
}
|
||||
|
||||
/* recover */
|
||||
raid_recov(2, d, combo[1][i], buffer, diskmax, zero, block_size);
|
||||
|
||||
/* check */
|
||||
for(j=0;j<2;++j) {
|
||||
if (memcmp(test[j], data_save[j], block_size) != 0) {
|
||||
fprintf(stderr, "Failed RAID test\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/* restore */
|
||||
for(j=0;j<2;++j) {
|
||||
/* restore the data */
|
||||
data[d[j]] = data_save[j];
|
||||
/* restore the parity */
|
||||
parity[combo[1][i][j]] = waste;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* check 1data */
|
||||
for(d[0]=0;d[0]<diskmax;++d[0]) {
|
||||
for(i=0;combo[0][i][0]>=0;++i) {
|
||||
/* set */
|
||||
for(j=0;j<1;++j) {
|
||||
/* remove the missing data */
|
||||
data_save[j] = data[d[j]];
|
||||
data[d[j]] = test[j];
|
||||
/* set the parity to use */
|
||||
parity[combo[0][i][j]] = parity_save[combo[0][i][j]];
|
||||
}
|
||||
|
||||
/* recover */
|
||||
raid_recov(1, d, combo[0][i], buffer, diskmax, zero, block_size);
|
||||
|
||||
/* check */
|
||||
for(j=0;j<1;++j) {
|
||||
if (memcmp(test[j], data_save[j], block_size) != 0) {
|
||||
fprintf(stderr, "Failed RAID test\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/* restore */
|
||||
for(j=0;j<1;++j) {
|
||||
/* restore the data */
|
||||
data[d[j]] = data_save[j];
|
||||
/* restore the parity */
|
||||
parity[combo[0][i][j]] = waste;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -327,7 +324,7 @@ static void recovtest(unsigned kind, unsigned diskmax, unsigned block_size)
|
|||
free(buffer);
|
||||
}
|
||||
|
||||
static void gentest(unsigned kind, unsigned diskmax, unsigned block_size)
|
||||
static void gentest(unsigned diskmax, unsigned block_size)
|
||||
{
|
||||
void* buffer_alloc;
|
||||
unsigned char** buffer;
|
||||
|
|
@ -335,15 +332,8 @@ static void gentest(unsigned kind, unsigned diskmax, unsigned block_size)
|
|||
unsigned i, j;
|
||||
void (*map[64])(unsigned char** buffer, unsigned diskmax, unsigned size);
|
||||
unsigned mac;
|
||||
unsigned level;
|
||||
|
||||
if (kind == RAID_POWER) {
|
||||
level = 4;
|
||||
} else {
|
||||
level = LEV_MAX;
|
||||
}
|
||||
|
||||
buffermax = diskmax + level * 2;
|
||||
buffermax = diskmax + LEV_MAX * 2;
|
||||
|
||||
buffer = malloc_nofail_vector_align(buffermax, block_size, &buffer_alloc);
|
||||
|
||||
|
|
@ -354,82 +344,49 @@ static void gentest(unsigned kind, unsigned diskmax, unsigned block_size)
|
|||
}
|
||||
|
||||
/* compute the parity */
|
||||
raid_gen(kind, level, buffer, diskmax, block_size);
|
||||
raid_gen(LEV_MAX, buffer, diskmax, block_size);
|
||||
|
||||
/* copy in back buffers */
|
||||
for(i=0;i<level;++i)
|
||||
memcpy(buffer[diskmax + level + i], buffer[diskmax + i], block_size);
|
||||
for(i=0;i<LEV_MAX;++i)
|
||||
memcpy(buffer[diskmax + LEV_MAX + i], buffer[diskmax + i], block_size);
|
||||
|
||||
/* load all the available functions */
|
||||
mac = 0;
|
||||
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;
|
||||
}
|
||||
|
||||
map[mac++] = raidTP_int8;
|
||||
map[mac++] = raidQP_int8;
|
||||
map[mac++] = raidPP_int8;
|
||||
map[mac++] = raidHP_int8;
|
||||
|
||||
map[mac++] = raid5_int32;
|
||||
map[mac++] = raid5_int64;
|
||||
map[mac++] = raid6_int32;
|
||||
map[mac++] = raid6_int64;
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
if (cpu_has_mmx()) {
|
||||
if (kind == RAID_POWER) {
|
||||
map[mac++] = raid5_mmx;
|
||||
map[mac++] = raid6_mmx;
|
||||
map[mac++] = raidQP_mmx;
|
||||
map[mac++] = raidTP_mmx;
|
||||
}
|
||||
map[mac++] = raid5_mmx;
|
||||
map[mac++] = raid6_mmx;
|
||||
}
|
||||
|
||||
if (cpu_has_sse2()) {
|
||||
if (kind == RAID_POWER) {
|
||||
map[mac++] = raid5_sse2;
|
||||
map[mac++] = raid6_sse2;
|
||||
map[mac++] = raidTP_sse2;
|
||||
map[mac++] = raidQP_sse2;
|
||||
map[mac++] = raid5_sse2;
|
||||
map[mac++] = raid6_sse2;
|
||||
#if defined(__x86_64__)
|
||||
map[mac++] = raid6_sse2ext;
|
||||
map[mac++] = raidTP_sse2ext;
|
||||
map[mac++] = raidQP_sse2ext;
|
||||
map[mac++] = raid6_sse2ext;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (cpu_has_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;
|
||||
}
|
||||
map[mac++] = raidTP_ssse3;
|
||||
map[mac++] = raidQP_ssse3;
|
||||
map[mac++] = raidPP_ssse3;
|
||||
map[mac++] = raidHP_ssse3;
|
||||
#if defined(__x86_64__)
|
||||
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__)
|
||||
if (kind == RAID_POWER) {
|
||||
map[mac++] = raidQP_avxext;
|
||||
}
|
||||
map[mac++] = raidTP_ssse3ext;
|
||||
map[mac++] = raidQP_ssse3ext;
|
||||
map[mac++] = raidPP_ssse3ext;
|
||||
map[mac++] = raidHP_ssse3ext;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
|
@ -440,8 +397,8 @@ static void gentest(unsigned kind, unsigned diskmax, unsigned block_size)
|
|||
map[j](buffer, diskmax, block_size);
|
||||
|
||||
/* check it */
|
||||
for(i=0;i<level;++i) {
|
||||
if (memcmp(buffer[diskmax + level + i], buffer[diskmax + i], block_size) != 0) {
|
||||
for(i=0;i<LEV_MAX;++i) {
|
||||
if (memcmp(buffer[diskmax + LEV_MAX + i], buffer[diskmax + i], block_size) != 0) {
|
||||
fprintf(stderr, "Failed RAID test\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
|
@ -565,9 +522,7 @@ void selftest()
|
|||
|
||||
hashtest();
|
||||
crc32ctest();
|
||||
gentest(RAID_POWER, 24, 256 * 1024);
|
||||
gentest(RAID_CAUCHY, 32, 256 * 1024);
|
||||
recovtest(RAID_POWER, 24, 2048);
|
||||
recovtest(RAID_CAUCHY, 32, 2048);
|
||||
gentest(64, 256);
|
||||
recovtest(16, 64);
|
||||
}
|
||||
|
||||
|
|
|
|||
322
speed.c
322
speed.c
|
|
@ -121,35 +121,12 @@ void speed(void)
|
|||
|
||||
printf("\n");
|
||||
|
||||
printf("Expected fastest hash is ");
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
if (sizeof(void*) == 4 && !cpu_has_slowmult())
|
||||
printf("murmur3");
|
||||
else
|
||||
printf("spooky2");
|
||||
#else
|
||||
if (sizeof(void*) == 4)
|
||||
printf("murmur3");
|
||||
else
|
||||
printf("spooky2");
|
||||
#endif
|
||||
printf("\n");
|
||||
|
||||
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");
|
||||
|
||||
printf("\n");
|
||||
|
||||
printf("Speed test using %d buffers of %u bytes, for a total of %u KiB.\n", diskmax, block_size, (diskmax + 3) * block_size / 1024);
|
||||
printf("All values are in MiB/s.\n");
|
||||
printf("Speed test using %u buffers of %u bytes, for a total of %u KiB.\n", diskmax, block_size, diskmax * block_size / 1024);
|
||||
printf("All values are in MiB/s of data processed, not counting written parity.\n");
|
||||
printf("\n");
|
||||
|
||||
printf("Memory write speed using the C memset() function:\n");
|
||||
printf("%10s", "memset");
|
||||
printf("%8s", "memset");
|
||||
fflush(stdout);
|
||||
|
||||
SPEED_START {
|
||||
|
|
@ -158,14 +135,14 @@ void speed(void)
|
|||
}
|
||||
} SPEED_STOP
|
||||
|
||||
printf(" %6"PRIu64, ds / dt);
|
||||
printf("%7"PRIu64, ds / dt);
|
||||
printf("\n");
|
||||
printf("\n");
|
||||
|
||||
/* crc table */
|
||||
printf("CRC used to check the content file integrity:\n");
|
||||
|
||||
printf("%10s", "table");
|
||||
printf("%8s", "table");
|
||||
fflush(stdout);
|
||||
|
||||
SPEED_START {
|
||||
|
|
@ -174,10 +151,10 @@ void speed(void)
|
|||
}
|
||||
} SPEED_STOP
|
||||
|
||||
printf(" %6"PRIu64, ds / dt);
|
||||
printf("%7"PRIu64, ds / dt);
|
||||
printf("\n");
|
||||
|
||||
printf("%10s", "intel");
|
||||
printf("%8s", "intel");
|
||||
fflush(stdout);
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
|
|
@ -188,7 +165,7 @@ void speed(void)
|
|||
}
|
||||
} SPEED_STOP
|
||||
|
||||
printf(" %6"PRIu64, ds / dt);
|
||||
printf("%7"PRIu64, ds / dt);
|
||||
}
|
||||
#endif
|
||||
printf("\n");
|
||||
|
|
@ -197,7 +174,24 @@ void speed(void)
|
|||
/* hash table */
|
||||
printf("Hash used to check the data blocks integrity:\n");
|
||||
|
||||
printf("%10s", "murmur3");
|
||||
printf("%8s", "");
|
||||
printf("%8s", "best");
|
||||
printf("%8s", "murmur3");
|
||||
printf("%8s", "spooky2");
|
||||
printf("\n");
|
||||
|
||||
printf("%8s", "hash");
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
if (sizeof(void*) == 4 && !cpu_has_slowmult())
|
||||
printf("%8s", "murmur3");
|
||||
else
|
||||
printf("%8s", "spooky2");
|
||||
#else
|
||||
if (sizeof(void*) == 4)
|
||||
printf("%8s", "murmur3");
|
||||
else
|
||||
printf("%8s", "spooky2");
|
||||
#endif
|
||||
fflush(stdout);
|
||||
|
||||
SPEED_START {
|
||||
|
|
@ -206,9 +200,7 @@ void speed(void)
|
|||
}
|
||||
} SPEED_STOP
|
||||
|
||||
printf(" %6"PRIu64, ds / dt);
|
||||
printf("\n");
|
||||
printf("%10s", "spooky2");
|
||||
printf("%8"PRIu64, ds / dt);
|
||||
fflush(stdout);
|
||||
|
||||
SPEED_START {
|
||||
|
|
@ -217,48 +209,49 @@ void speed(void)
|
|||
}
|
||||
} SPEED_STOP
|
||||
|
||||
printf(" %6"PRIu64, ds / dt);
|
||||
printf("%8"PRIu64, ds / dt);
|
||||
printf("\n");
|
||||
printf("\n");
|
||||
|
||||
/* RAID table */
|
||||
printf("RAID functions used to compute the parity:\n");
|
||||
printf("%10s", "");
|
||||
printf(" %6s", "int8");
|
||||
printf(" %6s", "int32");
|
||||
printf(" %6s", "int64");
|
||||
printf("%8s", "");
|
||||
printf("%7s", "best");
|
||||
printf("%7s", "int8");
|
||||
printf("%7s", "int32");
|
||||
printf("%7s", "int64");
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
printf(" %6s", "mmx");
|
||||
printf(" %6s", "sse2");
|
||||
printf("%7s", "mmx");
|
||||
printf("%7s", "sse2");
|
||||
#if defined(__x86_64__)
|
||||
printf(" %6s", "sse2ext");
|
||||
printf("%7s", "sse2e");
|
||||
#endif
|
||||
printf(" %6s", "ssse3");
|
||||
printf("%7s", "ssse3");
|
||||
#if defined(__x86_64__)
|
||||
printf(" %6s", "ssse3ext");
|
||||
printf(" %6s", "avxext");
|
||||
printf("%7s", "ssse3e");
|
||||
#endif
|
||||
#endif
|
||||
printf("\n");
|
||||
|
||||
/* RAID5 */
|
||||
printf("%10s", "power5");
|
||||
printf("%8s", "raid5");
|
||||
printf("%7s", raid5_tag());
|
||||
fflush(stdout);
|
||||
|
||||
printf(" %6s", "");
|
||||
printf("%7s", "");
|
||||
|
||||
SPEED_START {
|
||||
raid5_int32(buffer, diskmax, block_size);
|
||||
} SPEED_STOP
|
||||
|
||||
printf(" %6"PRIu64, ds / dt);
|
||||
printf("%7"PRIu64, ds / dt);
|
||||
fflush(stdout);
|
||||
|
||||
SPEED_START {
|
||||
raid5_int64(buffer, diskmax, block_size);
|
||||
} SPEED_STOP
|
||||
|
||||
printf(" %6"PRIu64, ds / dt);
|
||||
printf("%7"PRIu64, ds / dt);
|
||||
fflush(stdout);
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
|
|
@ -267,7 +260,7 @@ void speed(void)
|
|||
raid5_mmx(buffer, diskmax, block_size);
|
||||
} SPEED_STOP
|
||||
|
||||
printf(" %6"PRIu64, ds / dt);
|
||||
printf("%7"PRIu64, ds / dt);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
|
|
@ -276,30 +269,31 @@ void speed(void)
|
|||
raid5_sse2(buffer, diskmax, block_size);
|
||||
} SPEED_STOP
|
||||
|
||||
printf(" %6"PRIu64, ds / dt);
|
||||
printf("%7"PRIu64, ds / dt);
|
||||
fflush(stdout);
|
||||
}
|
||||
#endif
|
||||
printf("\n");
|
||||
|
||||
/* RAID6 */
|
||||
printf("%10s", "power6");
|
||||
printf("%8s", "raid6");
|
||||
printf("%7s", raid6_tag());
|
||||
fflush(stdout);
|
||||
|
||||
printf(" %6s", "");
|
||||
printf("%7s", "");
|
||||
|
||||
SPEED_START {
|
||||
raid6_int32(buffer, diskmax, block_size);
|
||||
} SPEED_STOP
|
||||
|
||||
printf(" %6"PRIu64, ds / dt);
|
||||
printf("%7"PRIu64, ds / dt);
|
||||
fflush(stdout);
|
||||
|
||||
SPEED_START {
|
||||
raid6_int64(buffer, diskmax, block_size);
|
||||
} SPEED_STOP
|
||||
|
||||
printf(" %6"PRIu64, ds / dt);
|
||||
printf("%7"PRIu64, ds / dt);
|
||||
fflush(stdout);
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
|
|
@ -308,7 +302,7 @@ void speed(void)
|
|||
raid6_mmx(buffer, diskmax, block_size);
|
||||
} SPEED_STOP
|
||||
|
||||
printf(" %6"PRIu64, ds / dt);
|
||||
printf("%7"PRIu64, ds / dt);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
|
|
@ -317,7 +311,7 @@ void speed(void)
|
|||
raid6_sse2(buffer, diskmax, block_size);
|
||||
} SPEED_STOP
|
||||
|
||||
printf(" %6"PRIu64, ds / dt);
|
||||
printf("%7"PRIu64, ds / dt);
|
||||
fflush(stdout);
|
||||
|
||||
#if defined(__x86_64__)
|
||||
|
|
@ -325,7 +319,7 @@ void speed(void)
|
|||
raid6_sse2ext(buffer, diskmax, block_size);
|
||||
} SPEED_STOP
|
||||
|
||||
printf(" %6"PRIu64, ds / dt);
|
||||
printf("%7"PRIu64, ds / dt);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
}
|
||||
|
|
@ -333,59 +327,39 @@ void speed(void)
|
|||
printf("\n");
|
||||
|
||||
/* RAIDTP */
|
||||
printf("%10s", "powerTP");
|
||||
fflush(stdout);
|
||||
|
||||
printf(" %6s", "");
|
||||
|
||||
SPEED_START {
|
||||
raidTP_int32(buffer, diskmax, block_size);
|
||||
} SPEED_STOP
|
||||
|
||||
printf(" %6"PRIu64, ds / dt);
|
||||
printf("%8s", "raidTP");
|
||||
printf("%7s", raidTP_tag());
|
||||
fflush(stdout);
|
||||
|
||||
SPEED_START {
|
||||
raidTP_int64(buffer, diskmax, block_size);
|
||||
raidTP_int8(buffer, diskmax, block_size);
|
||||
} SPEED_STOP
|
||||
|
||||
printf(" %6"PRIu64, ds / dt);
|
||||
printf("%7"PRIu64, ds / dt);
|
||||
fflush(stdout);
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
printf("%7s", "");
|
||||
printf("%7s", "");
|
||||
|
||||
if (cpu_has_mmx()) {
|
||||
SPEED_START {
|
||||
raidTP_mmx(buffer, diskmax, block_size);
|
||||
} SPEED_STOP
|
||||
|
||||
printf(" %6"PRIu64, ds / dt);
|
||||
fflush(stdout);
|
||||
printf("%7s", "");
|
||||
}
|
||||
|
||||
if (cpu_has_sse2()) {
|
||||
SPEED_START {
|
||||
raidTP_sse2(buffer, diskmax, block_size);
|
||||
} SPEED_STOP
|
||||
|
||||
printf(" %6"PRIu64, ds / dt);
|
||||
fflush(stdout);
|
||||
printf("%7s", "");
|
||||
|
||||
#if defined(__x86_64__)
|
||||
SPEED_START {
|
||||
raidTP_sse2ext(buffer, diskmax, block_size);
|
||||
} SPEED_STOP
|
||||
|
||||
printf(" %6"PRIu64, ds / dt);
|
||||
fflush(stdout);
|
||||
printf("%7s", "");
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
if (cpu_has_ssse3()) {
|
||||
SPEED_START {
|
||||
raidTP_ssse3(buffer, diskmax, block_size);
|
||||
} SPEED_STOP
|
||||
|
||||
printf(" %6"PRIu64, ds / dt);
|
||||
printf("%7"PRIu64, ds / dt);
|
||||
fflush(stdout);
|
||||
|
||||
#if defined(__x86_64__)
|
||||
|
|
@ -393,7 +367,7 @@ void speed(void)
|
|||
raidTP_ssse3ext(buffer, diskmax, block_size);
|
||||
} SPEED_STOP
|
||||
|
||||
printf(" %6"PRIu64, ds / dt);
|
||||
printf("%7"PRIu64, ds / dt);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
}
|
||||
|
|
@ -401,59 +375,39 @@ void speed(void)
|
|||
printf("\n");
|
||||
|
||||
/* RAIDQP */
|
||||
printf("%10s", "powerQP");
|
||||
fflush(stdout);
|
||||
|
||||
printf(" %6s", "");
|
||||
|
||||
SPEED_START {
|
||||
raidQP_int32(buffer, diskmax, block_size);
|
||||
} SPEED_STOP
|
||||
|
||||
printf(" %6"PRIu64, ds / dt);
|
||||
printf("%8s", "raidQP");
|
||||
printf("%7s", raidQP_tag());
|
||||
fflush(stdout);
|
||||
|
||||
SPEED_START {
|
||||
raidQP_int64(buffer, diskmax, block_size);
|
||||
raidQP_int8(buffer, diskmax, block_size);
|
||||
} SPEED_STOP
|
||||
|
||||
printf(" %6"PRIu64, ds / dt);
|
||||
printf("%7"PRIu64, ds / dt);
|
||||
fflush(stdout);
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
printf("%7s", "");
|
||||
printf("%7s", "");
|
||||
|
||||
if (cpu_has_mmx()) {
|
||||
SPEED_START {
|
||||
raidQP_mmx(buffer, diskmax, block_size);
|
||||
} SPEED_STOP
|
||||
|
||||
printf(" %6"PRIu64, ds / dt);
|
||||
fflush(stdout);
|
||||
printf("%7s", "");
|
||||
}
|
||||
|
||||
if (cpu_has_sse2()) {
|
||||
SPEED_START {
|
||||
raidQP_sse2(buffer, diskmax, block_size);
|
||||
} SPEED_STOP
|
||||
|
||||
printf(" %6"PRIu64, ds / dt);
|
||||
fflush(stdout);
|
||||
printf("%7s", "");
|
||||
|
||||
#if defined(__x86_64__)
|
||||
SPEED_START {
|
||||
raidQP_sse2ext(buffer, diskmax, block_size);
|
||||
} SPEED_STOP
|
||||
|
||||
printf(" %6"PRIu64, ds / dt);
|
||||
fflush(stdout);
|
||||
printf("%7s", "");
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
if (cpu_has_ssse3()) {
|
||||
SPEED_START {
|
||||
raidQP_ssse3(buffer, diskmax, block_size);
|
||||
} SPEED_STOP
|
||||
|
||||
printf(" %6"PRIu64, ds / dt);
|
||||
printf("%7"PRIu64, ds / dt);
|
||||
fflush(stdout);
|
||||
|
||||
#if defined(__x86_64__)
|
||||
|
|
@ -461,159 +415,103 @@ void speed(void)
|
|||
raidQP_ssse3ext(buffer, diskmax, block_size);
|
||||
} SPEED_STOP
|
||||
|
||||
printf(" %6"PRIu64, ds / dt);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (cpu_has_avx()) {
|
||||
#if defined(__x86_64__)
|
||||
SPEED_START {
|
||||
raidQP_avxext(buffer, diskmax, block_size);
|
||||
} SPEED_STOP
|
||||
|
||||
printf(" %6"PRIu64, ds / dt);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
}
|
||||
#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);
|
||||
printf("%7"PRIu64, ds / dt);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
printf("\n");
|
||||
|
||||
/* CAUCHYPP */
|
||||
printf("%10s", "cauchyPP");
|
||||
/* RAIDPP */
|
||||
printf("%8s", "raidPP");
|
||||
printf("%7s", raidPP_tag());
|
||||
fflush(stdout);
|
||||
|
||||
SPEED_START {
|
||||
cauchyPP_int8(buffer, diskmax, block_size);
|
||||
raidPP_int8(buffer, diskmax, block_size);
|
||||
} SPEED_STOP
|
||||
|
||||
printf(" %6"PRIu64, ds / dt);
|
||||
printf("%7"PRIu64, ds / dt);
|
||||
fflush(stdout);
|
||||
|
||||
printf(" %6s", "");
|
||||
printf(" %6s", "");
|
||||
printf("%7s", "");
|
||||
printf("%7s", "");
|
||||
|
||||
if (cpu_has_mmx()) {
|
||||
printf(" %6s", "");
|
||||
printf("%7s", "");
|
||||
}
|
||||
|
||||
if (cpu_has_sse2()) {
|
||||
printf(" %6s", "");
|
||||
printf("%7s", "");
|
||||
|
||||
#if defined(__x86_64__)
|
||||
printf(" %6s", "");
|
||||
printf("%7s", "");
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
if (cpu_has_ssse3()) {
|
||||
SPEED_START {
|
||||
cauchyPP_ssse3(buffer, diskmax, block_size);
|
||||
raidPP_ssse3(buffer, diskmax, block_size);
|
||||
} SPEED_STOP
|
||||
|
||||
printf(" %6"PRIu64, ds / dt);
|
||||
printf("%7"PRIu64, ds / dt);
|
||||
fflush(stdout);
|
||||
|
||||
#if defined(__x86_64__)
|
||||
SPEED_START {
|
||||
cauchyPP_ssse3ext(buffer, diskmax, block_size);
|
||||
raidPP_ssse3ext(buffer, diskmax, block_size);
|
||||
} SPEED_STOP
|
||||
|
||||
printf(" %6"PRIu64, ds / dt);
|
||||
printf("%7"PRIu64, ds / dt);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
printf("\n");
|
||||
|
||||
/* CAUCHYHP */
|
||||
printf("%10s", "cauchyHP");
|
||||
|
||||
/* RAIDHP */
|
||||
printf("%8s", "raidHP");
|
||||
printf("%7s", raidHP_tag());
|
||||
fflush(stdout);
|
||||
|
||||
SPEED_START {
|
||||
cauchyHP_int8(buffer, diskmax, block_size);
|
||||
raidHP_int8(buffer, diskmax, block_size);
|
||||
} SPEED_STOP
|
||||
|
||||
printf(" %6"PRIu64, ds / dt);
|
||||
printf("%7"PRIu64, ds / dt);
|
||||
fflush(stdout);
|
||||
|
||||
printf(" %6s", "");
|
||||
printf(" %6s", "");
|
||||
printf("%7s", "");
|
||||
printf("%7s", "");
|
||||
|
||||
if (cpu_has_mmx()) {
|
||||
printf(" %6s", "");
|
||||
printf("%7s", "");
|
||||
}
|
||||
|
||||
if (cpu_has_sse2()) {
|
||||
printf(" %6s", "");
|
||||
printf("%7s", "");
|
||||
|
||||
#if defined(__x86_64__)
|
||||
printf(" %6s", "");
|
||||
printf("%7s", "");
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
if (cpu_has_ssse3()) {
|
||||
SPEED_START {
|
||||
cauchyHP_ssse3(buffer, diskmax, block_size);
|
||||
raidHP_ssse3(buffer, diskmax, block_size);
|
||||
} SPEED_STOP
|
||||
|
||||
printf(" %6"PRIu64, ds / dt);
|
||||
printf("%7"PRIu64, ds / dt);
|
||||
fflush(stdout);
|
||||
|
||||
#if defined(__x86_64__)
|
||||
SPEED_START {
|
||||
cauchyHP_ssse3ext(buffer, diskmax, block_size);
|
||||
raidHP_ssse3ext(buffer, diskmax, block_size);
|
||||
} SPEED_STOP
|
||||
|
||||
printf(" %6"PRIu64, ds / dt);
|
||||
printf("%7"PRIu64, ds / dt);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
}
|
||||
|
|
@ -621,6 +519,10 @@ void speed(void)
|
|||
printf("\n");
|
||||
printf("\n");
|
||||
|
||||
printf("If the 'best' expectations are wrong, please report it in the SnapRAID forum\n");
|
||||
|
||||
printf("\n");
|
||||
|
||||
free(buffer_alloc);
|
||||
free(buffer);
|
||||
}
|
||||
|
|
|
|||
67
state.c
67
state.c
|
|
@ -53,6 +53,20 @@ const char* lev_config_name(unsigned l)
|
|||
return 0;
|
||||
}
|
||||
|
||||
const char* lev_raid_name(unsigned n)
|
||||
{
|
||||
switch (n) {
|
||||
case 1 : return "raid5";
|
||||
case 2 : return "raid6";
|
||||
case 3 : return "raidTP";
|
||||
case 4 : return "raidQP";
|
||||
case 5 : return "raidPP";
|
||||
case 6 : return "raidHP";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void state_init(struct snapraid_state* state)
|
||||
{
|
||||
unsigned l;
|
||||
|
|
@ -183,17 +197,6 @@ static void state_config_check(struct snapraid_state* state, const char* path)
|
|||
++diskcount;
|
||||
}
|
||||
|
||||
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", RAID_POWER_DATA_LIMIT);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
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", RAID_POWER_QP_DATA_LIMIT);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
for(l=0;l<state->level;++l) {
|
||||
if (state->parity_device[l] == 0) {
|
||||
|
|
@ -267,6 +270,13 @@ static void state_config_check(struct snapraid_state* state, const char* path)
|
|||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
if (!cpu_has_ssse3())
|
||||
#endif
|
||||
if (state->level > 2) {
|
||||
fprintf(stderr, "WARNING! Your CPU doesn't have a fast implementation beyond RAID6.\n");
|
||||
}
|
||||
}
|
||||
|
||||
void state_config(struct snapraid_state* state, const char* path, const char* command, struct snapraid_option* opt)
|
||||
|
|
@ -341,7 +351,13 @@ void state_config(struct snapraid_state* state, const char* path, const char* co
|
|||
exit(EXIT_FAILURE);
|
||||
}
|
||||
state->block_size *= 1024;
|
||||
} else if (strcmp(tag, "parity") == 0 || strcmp(tag, "q-parity") == 0 || strcmp(tag, "r-parity") == 0 || strcmp(tag, "s-parity") == 0) {
|
||||
} else if (strcmp(tag, "parity") == 0
|
||||
|| strcmp(tag, "q-parity") == 0
|
||||
|| strcmp(tag, "r-parity") == 0
|
||||
|| strcmp(tag, "s-parity") == 0
|
||||
|| strcmp(tag, "t-parity") == 0
|
||||
|| strcmp(tag, "u-parity") == 0
|
||||
) {
|
||||
char device[PATH_MAX];
|
||||
char* slash;
|
||||
struct stat st;
|
||||
|
|
@ -352,6 +368,8 @@ void state_config(struct snapraid_state* state, const char* path, const char* co
|
|||
case 'q' : l = 1; break;
|
||||
case 'r' : l = 2; break;
|
||||
case 's' : l = 3; break;
|
||||
case 't' : l = 4; break;
|
||||
case 'u' : l = 5; break;
|
||||
default:
|
||||
fprintf(stderr, "Invalid '%s' specification in '%s' at line %u\n", tag, path, line);
|
||||
exit(EXIT_FAILURE);
|
||||
|
|
@ -652,16 +670,9 @@ void state_config(struct snapraid_state* state, const char* path, const char* co
|
|||
fprintf(stdlog, "disk:%s:%s\n", disk->name, disk->dir);
|
||||
}
|
||||
|
||||
switch (state->level) {
|
||||
case 1 : fprintf(stdlog, "mode:raid5\n"); break;
|
||||
case 2 : fprintf(stdlog, "mode:raid6\n"); break;
|
||||
case 3 : fprintf(stdlog, "mode:raidTP\n"); break;
|
||||
case 4 : fprintf(stdlog, "mode:raidQP\n"); break;
|
||||
}
|
||||
|
||||
for(l=0;l<state->level;++l) {
|
||||
fprintf(stdlog, "mode:%s\n", lev_raid_name(state->level));
|
||||
for(l=0;l<state->level;++l)
|
||||
fprintf(stdlog, "%s:%s\n", lev_config_name(l), state->parity_path[l]);
|
||||
}
|
||||
if (state->pool[0] != 0)
|
||||
fprintf(stdlog, "pool:%s\n", state->pool);
|
||||
fflush(stdlog);
|
||||
|
|
@ -675,6 +686,7 @@ static void state_map(struct snapraid_state* state)
|
|||
unsigned hole;
|
||||
tommy_node* i;
|
||||
unsigned uuid_mismatch;
|
||||
unsigned diskcount;
|
||||
|
||||
/* removes all the mapping without a disk */
|
||||
/* this happens when a disk is removed from the configuration file */
|
||||
|
|
@ -805,6 +817,19 @@ static void state_map(struct snapraid_state* state)
|
|||
fprintf(stderr, "and you have to restore the mount points at the state of the latest sync.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* count the number of data disks, including holes left after removing some */
|
||||
diskcount = 0;
|
||||
for(i=state->maplist;i!=0;i=i->next) {
|
||||
struct snapraid_map* map = i->data;
|
||||
|
||||
if (map->position + 1 > diskcount)
|
||||
diskcount = map->position + 1;
|
||||
}
|
||||
if (diskcount > RAID_DATA_LIMIT) {
|
||||
fprintf(stderr, "Too many datadisks. No more than %u.\n", RAID_DATA_LIMIT);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
1
status.c
1
status.c
|
|
@ -134,7 +134,6 @@ int state_status(struct snapraid_state* state)
|
|||
count = 0;
|
||||
rehash = 0;
|
||||
unsynched_blocks = 0;
|
||||
|
||||
for(i=0;i<blockmax;++i) {
|
||||
int one_invalid;
|
||||
int one_valid;
|
||||
|
|
|
|||
8
sync.c
8
sync.c
|
|
@ -175,8 +175,10 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari
|
|||
error_on_this_block = 0;
|
||||
silent_error_on_this_block = 0;
|
||||
|
||||
/* if we have to use the old hash */
|
||||
/* get block specific info */
|
||||
info = info_get(&state->infoarr, i);
|
||||
|
||||
/* if we have to use the old hash */
|
||||
rehash = info_get_rehash(info);
|
||||
|
||||
/* it could happens that all the blocks are EMPTY/BLK and CHG but with the hash */
|
||||
|
|
@ -374,7 +376,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(RAID_POWER, state->level, buffer, diskmax, state->block_size);
|
||||
raid_gen(state->level, buffer, diskmax, state->block_size);
|
||||
|
||||
/* write the parity */
|
||||
for(l=0;l<state->level;++l) {
|
||||
|
|
@ -430,7 +432,7 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari
|
|||
info_set(&state->infoarr, i, info_make(now, 0, 0));
|
||||
}
|
||||
} else if (silent_error_on_this_block) {
|
||||
/* set the error status keeping the existing time and hash */
|
||||
/* set the error status keeping the other info */
|
||||
info_set(&state->infoarr, i, info_set_bad(info));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ disk disk2 test/disk2/
|
|||
disk disk3 test/disk3/
|
||||
disk disk4 test/disk4/
|
||||
disk disk5 test/disk5/
|
||||
disk disk6 test/disk6/
|
||||
include *.hidden
|
||||
exclude *.unrecoverable
|
||||
pool test/pool
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ disk disk2 test/disk2/
|
|||
disk disk3 test/disk3/
|
||||
disk disk4 test/disk4/
|
||||
disk disk5 test/disk5/
|
||||
disk disk6 test/disk6/
|
||||
include *.hidden
|
||||
exclude *.unrecoverable
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +0,0 @@
|
|||
block_size 1
|
||||
parity test/parity
|
||||
q-parity test/q-parity
|
||||
r-parity test/r-parity
|
||||
s-parity test/s-parity
|
||||
content test/content
|
||||
content test/p-content
|
||||
content test/q-content
|
||||
content test/r-content
|
||||
disk disk1 test/disk1/
|
||||
disk disk3 test/disk3/
|
||||
disk disk4 test/disk4/
|
||||
disk disk5 test/disk5/
|
||||
include *.hidden
|
||||
exclude *.unrecoverable
|
||||
|
||||
|
|
@ -7,11 +7,13 @@ content test/content
|
|||
content test/p-content
|
||||
content test/q-content
|
||||
content test/r-content
|
||||
content test/s-content
|
||||
disk disk1 test/disk1/
|
||||
disk disk2 test/disk2/
|
||||
disk disk3 test/disk3/
|
||||
disk disk4 test/disk4/
|
||||
disk disk5 test/disk5/
|
||||
disk disk6 test/disk6/
|
||||
include *.hidden
|
||||
exclude *.unrecoverable
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ disk disk2 test/disk2/
|
|||
disk disk3 test/disk3/
|
||||
disk disk4 test/disk4/
|
||||
disk disk5 test/disk5/
|
||||
disk disk6 test/disk6/
|
||||
include *.hidden
|
||||
exclude *.unrecoverable
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue