mirror of
https://github.com/amadvance/snapraid.git
synced 2026-10-26 10:51:54 -04:00
Adds recovering at RAID6 support.
Adds selftesting of RAID5 and RAID5.
This commit is contained in:
parent
08831c6641
commit
f855424082
11 changed files with 546 additions and 200 deletions
149
Makefile.am
149
Makefile.am
|
|
@ -41,7 +41,8 @@ noinst_HEADERS = \
|
|||
tommylist.c \
|
||||
fnmatch.h \
|
||||
cpu.h \
|
||||
raid.h
|
||||
raid.h \
|
||||
tables.h
|
||||
|
||||
mktest_SOURCES = \
|
||||
mktest.c
|
||||
|
|
@ -51,7 +52,8 @@ EXTRA_DIST = \
|
|||
noautomake.sh \
|
||||
README AUTHORS HISTORY INSTALL COPYING TODO \
|
||||
snapraid.d snapraid.1 snapraid.txt \
|
||||
test.conf \
|
||||
test-raid5.conf \
|
||||
test-raid6.conf \
|
||||
snapraid.conf.example \
|
||||
acinclude.m4
|
||||
|
||||
|
|
@ -73,83 +75,126 @@ check-local:
|
|||
mkdir test/disk2
|
||||
mkdir test/disk3
|
||||
echo --- As empty, sync and check
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -v -c $(srcdir)/test.conf sync
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test.conf check
|
||||
echo --- Create some files, sync and check
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -v -c $(srcdir)/test-raid6.conf sync
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test-raid6.conf check
|
||||
echo --- Create some files, sync raid6 and check
|
||||
$(TESTENV) ./mktest$(EXEEXT) generate 1 3 1000 4000
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -v -c $(srcdir)/test.conf sync
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test.conf check
|
||||
echo --- Create some more files, sync and check
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -v -c $(srcdir)/test-raid6.conf sync
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test-raid5.conf check
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test-raid6.conf check
|
||||
echo --- Create some more files, sync raid5 and check
|
||||
$(TESTENV) ./mktest$(EXEEXT) generate 2 3 1000 4000
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -v -c $(srcdir)/test.conf sync
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test.conf check
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -v -c $(srcdir)/test-raid5.conf sync
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test-raid5.conf check
|
||||
echo --- Extend raid5 to raid6 with fix and check
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -R -c $(srcdir)/test-raid6.conf check 2>/dev/null
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test-raid6.conf fix 2>/dev/null
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test-raid5.conf check
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test-raid6.conf check
|
||||
echo --- Dry
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test.conf dry
|
||||
echo --- Delete some files and create some new, sync and check
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test-raid5.conf dry
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test-raid6.conf dry
|
||||
echo --- Delete some files, create some new, sync and check
|
||||
rm test/disk1/1*
|
||||
rm test/disk2/2*
|
||||
rm test/disk3/3*
|
||||
$(TESTENV) ./mktest$(EXEEXT) generate 3 3 100 4000
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -v -c $(srcdir)/test.conf sync
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test.conf check
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -v -c $(srcdir)/test-raid6.conf sync
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test-raid6.conf check
|
||||
echo --- Move some files, sync and check
|
||||
mv test/disk1/7* test/disk1/_a/
|
||||
mv test/disk2/7* test/disk2/_a/
|
||||
mv test/disk3/7* test/disk3/_a/
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -v -c $(srcdir)/test.conf sync
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test.conf check
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -v -c $(srcdir)/test-raid6.conf sync
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test-raid6.conf check
|
||||
echo --- Delete one disk, fix and check with raid5
|
||||
rm -r test/disk3
|
||||
mkdir test/disk3
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -R -c $(srcdir)/test-raid5.conf check 2>/dev/null
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test-raid5.conf fix 2>/dev/null
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test-raid6.conf check
|
||||
echo --- Delete two disks, fix and check with raid6
|
||||
rm -r test/disk1
|
||||
mkdir test/disk1
|
||||
rm -r test/disk2
|
||||
mkdir test/disk2
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -U -c $(srcdir)/test-raid5.conf check 2>/dev/null
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -R -c $(srcdir)/test-raid6.conf check 2>/dev/null
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test-raid6.conf fix 2>/dev/null
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test-raid6.conf check
|
||||
echo --- Sync after all the fixes with an empty drive to test -E
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -v -E -c $(srcdir)/test-raid6.conf sync
|
||||
echo --- Delete some files and create some new, sync and check in multiple steps
|
||||
rm test/disk1/4*
|
||||
rm test/disk2/5*
|
||||
rm test/disk3/6*
|
||||
$(TESTENV) ./mktest$(EXEEXT) generate 4 3 100 4000
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -v -c $(srcdir)/test.conf -t 7 sync
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -R -c $(srcdir)/test.conf check 2>/dev/null
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -v -c $(srcdir)/test.conf -t 11 sync
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -R -c $(srcdir)/test.conf check 2>/dev/null
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -v -c $(srcdir)/test.conf sync
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test.conf check
|
||||
echo --- Delete some files, fix and check
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -v -c $(srcdir)/test-raid6.conf -t 7 sync
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -R -c $(srcdir)/test-raid6.conf check 2>/dev/null
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -v -c $(srcdir)/test-raid6.conf -t 11 sync
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -R -c $(srcdir)/test-raid6.conf check 2>/dev/null
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -v -c $(srcdir)/test-raid6.conf sync
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test-raid6.conf check
|
||||
echo --- Delete some files, fix and check with raid5
|
||||
rm test/disk1/1*
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -R -c $(srcdir)/test.conf check 2>/dev/null
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test.conf fix 2>/dev/null
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test.conf check
|
||||
echo --- Delete some dirs, fix and check
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -R -c $(srcdir)/test-raid5.conf check 2>/dev/null
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test-raid5.conf fix 2>/dev/null
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test-raid6.conf check
|
||||
echo --- Delete some dirs, fix and check with raid5
|
||||
rm -r test/disk2/_a
|
||||
rm -r test/disk2/_b
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -R -c $(srcdir)/test.conf check 2>/dev/null
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test.conf fix 2>/dev/null
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test.conf check
|
||||
echo --- Delete a whole disk, fix and check
|
||||
rm -r test/disk3
|
||||
mkdir test/disk3
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -R -c $(srcdir)/test.conf check 2>/dev/null
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test.conf fix 2>/dev/null
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test.conf check
|
||||
echo --- Sync after all the fixes with an empty drive
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -v -E -c $(srcdir)/test.conf sync
|
||||
echo --- Delete the parity, fix and check
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -R -c $(srcdir)/test-raid5.conf check 2>/dev/null
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test-raid5.conf fix 2>/dev/null
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test-raid6.conf check
|
||||
echo --- Delete some dirs, fix and check with raid6
|
||||
rm -r test/disk2/_a
|
||||
rm -r test/disk2/_b
|
||||
rm -r test/disk3/_a
|
||||
rm -r test/disk3/_b
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -U -c $(srcdir)/test-raid5.conf check 2>/dev/null
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -R -c $(srcdir)/test-raid6.conf check 2>/dev/null
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test-raid6.conf fix 2>/dev/null
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test-raid6.conf check
|
||||
echo --- Delete the parity, fix and check with raid5
|
||||
rm test/parity
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test.conf check 2>/dev/null
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test.conf fix 2>/dev/null
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test.conf check
|
||||
echo --- Corrupt the parity, fix and check
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test-raid5.conf check 2>/dev/null
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test-raid5.conf fix 2>/dev/null
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test-raid6.conf check
|
||||
echo --- Delete the parity and the q-parity, fix and check with raid6
|
||||
rm test/parity
|
||||
rm test/q-parity
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test-raid6.conf fix 2>/dev/null
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test-raid6.conf check
|
||||
echo --- Delete the parity and a disk, fix and check with raid6
|
||||
rm test/parity
|
||||
rm -r test/disk2/_a
|
||||
rm -r test/disk2/_b
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test-raid6.conf fix 2>/dev/null
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test-raid6.conf check
|
||||
echo --- Delete the q-parity and a disk, fix and check with raid6
|
||||
rm test/q-parity
|
||||
rm -r test/disk3/_a
|
||||
rm -r test/disk3/_b
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test-raid6.conf fix 2>/dev/null
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test-raid6.conf check
|
||||
echo --- Corrupt the parity, fix and check with raid5
|
||||
$(TESTENV) ./mktest$(EXEEXT) damage 1 10 10000 test/parity
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -R -c $(srcdir)/test.conf check 2>/dev/null
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test.conf fix 2>/dev/null
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test.conf check
|
||||
echo --- Corrupt some files, fix and check
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -R -c $(srcdir)/test-raid5.conf check 2>/dev/null
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test-raid5.conf fix 2>/dev/null
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test-raid6.conf check
|
||||
echo --- Corrupt some files, fix and check with raid5
|
||||
$(TESTENV) ./mktest$(EXEEXT) damage 1 1 500 test/disk2/b*
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -R -c $(srcdir)/test.conf check 2>/dev/null
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test.conf fix 2>/dev/null
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test.conf check
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -R -c $(srcdir)/test-raid5.conf check 2>/dev/null
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test-raid5.conf fix 2>/dev/null
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test-raid6.conf check
|
||||
echo --- Sync after all the fixes
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -v -c $(srcdir)/test.conf sync
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -v -c $(srcdir)/test-raid6.conf sync
|
||||
$(TESTENV) ./snapraid$(EXEEXT) -c $(srcdir)/test-raid6.conf check
|
||||
echo Success!
|
||||
|
||||
# Manual testing
|
||||
|
||||
CHECK = ./snapraid -v -c test.conf sync
|
||||
CHECK = ./snapraid -v -c test-raid5.conf sync
|
||||
|
||||
valgrind:
|
||||
valgrind \
|
||||
|
|
|
|||
12
TODO
12
TODO
|
|
@ -14,21 +14,9 @@ completely restored.
|
|||
|
||||
* Provide an "include" logic in filtering.
|
||||
|
||||
* Add RAID6 redundancy support. There is the very good raid6 library from
|
||||
H. Peter Anvin (hpa) in the Linux Kernel ready to use. See:
|
||||
http://kernel.org/pub/linux/kernel/people/hpa/raid6.pdf
|
||||
http://lxr.linux.no/#linux+v2.6.38/lib/raid6
|
||||
|
||||
* Recognize that a file is moved from one disk to another, and if the parity
|
||||
data doesn't overlap, do not recompute it.
|
||||
|
||||
* Go multithread to speed up the MD5 computation. We can do it when syncing and
|
||||
checking.
|
||||
|
||||
* Evaluate the new MurmorHash3 to use instead of MD5. It should be faster,
|
||||
but unsure of it's reliability. In fact, in MurmorHash2 was found a serious
|
||||
issue that suggests to wait some time before using it.
|
||||
|
||||
* Use the O_NOATIME flag if run as 'root'. Anyway a better solution is to
|
||||
mount the disk with the "noatime" and "nodiratime" options.
|
||||
|
||||
|
|
|
|||
147
check.c
147
check.c
|
|
@ -38,66 +38,115 @@ struct failed_struct {
|
|||
* Returns <0 if failure for missing stratey, >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.
|
||||
*/
|
||||
static int repair(struct snapraid_state* state, unsigned i, unsigned diskmax, struct failed_struct* failed, unsigned failed_count, unsigned char** buffer, unsigned char* buffer_parity, unsigned char* buffer_qarity)
|
||||
static int repair(struct snapraid_state* state, unsigned i, unsigned diskmax, struct failed_struct* failed, unsigned failed_count, unsigned char** buffer, unsigned char* buffer_parity, unsigned char* buffer_qarity, unsigned char* buffer_zero)
|
||||
{
|
||||
unsigned char hash[HASH_SIZE];
|
||||
unsigned size;
|
||||
unsigned j;
|
||||
int error = 0;
|
||||
|
||||
/* no fix required */
|
||||
if (failed_count == 0) {
|
||||
/* compute parity and qarity to check it */
|
||||
if (state->level == 1) {
|
||||
raid5_gen(buffer, diskmax + state->level, state->block_size);
|
||||
} else {
|
||||
raid6_gen(buffer, diskmax + state->level, state->block_size);
|
||||
}
|
||||
|
||||
raid_gen(state->level, buffer, diskmax, state->block_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* fix with RAID5 */
|
||||
if (failed_count == 1 && buffer_parity != 0) {
|
||||
unsigned char hash[HASH_SIZE];
|
||||
unsigned size;
|
||||
unsigned j;
|
||||
/* copy the redundancy to use */
|
||||
memcpy(buffer[diskmax], buffer_parity, state->block_size);
|
||||
|
||||
/* recompute the block */
|
||||
memcpy(buffer[failed[0].index], buffer_parity, state->block_size);
|
||||
for(j=0;j<diskmax;++j) {
|
||||
if (j != failed[0].index) {
|
||||
memxor(buffer[failed[0].index], buffer[j], state->block_size);
|
||||
/* recover */
|
||||
raid5_recov_data(buffer, diskmax, state->block_size, failed[0].index);
|
||||
|
||||
for(j=0;j<1;++j) {
|
||||
size = block_file_size(failed[j].block, state->block_size);
|
||||
|
||||
/* now compute the hash */
|
||||
memhash(state->hash, hash, buffer[failed[j].index], size);
|
||||
|
||||
/* compare the hash */
|
||||
if (memcmp(hash, failed[j].block->hash, HASH_SIZE) != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
size = block_file_size(failed[0].block, state->block_size);
|
||||
|
||||
/* now compute the hash */
|
||||
memhash(state->hash, hash, buffer[failed[0].index], size);
|
||||
|
||||
/* compare the hash */
|
||||
if (memcmp(hash, failed[0].block->hash, HASH_SIZE) != 0) {
|
||||
fprintf(stderr, "%u: Parity data error\n", i);
|
||||
return 1;
|
||||
if (j==1) {
|
||||
/* compute parity and qarity to check it */
|
||||
/* we recompute everything because we may have used only a small part of the redundancy */
|
||||
raid_gen(state->level, buffer, diskmax, state->block_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* compute parity and qarity to check it */
|
||||
/* we recompute also the just used parity, because we may have used only a small part of it */
|
||||
if (state->level == 1) {
|
||||
raid5_gen(buffer, diskmax + state->level, state->block_size);
|
||||
} else {
|
||||
raid6_gen(buffer, diskmax + state->level, state->block_size);
|
||||
}
|
||||
|
||||
return 0;
|
||||
fprintf(stderr, "%u: Parity data error\n", i);
|
||||
++error;
|
||||
}
|
||||
|
||||
if (failed_count == 1 && buffer_qarity != 0) {
|
||||
/* TODO RAID6 */
|
||||
/* copy the redundancy to use */
|
||||
memcpy(buffer[diskmax+1], buffer_qarity, state->block_size);
|
||||
|
||||
raid6_recov_datap(buffer, diskmax, state->block_size, failed[0].index, buffer_zero);
|
||||
|
||||
for(j=0;j<1;++j) {
|
||||
size = block_file_size(failed[j].block, state->block_size);
|
||||
|
||||
/* now compute the hash */
|
||||
memhash(state->hash, hash, buffer[failed[j].index], size);
|
||||
|
||||
/* compare the hash */
|
||||
if (memcmp(hash, failed[j].block->hash, HASH_SIZE) != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (j==1) {
|
||||
/* compute parity and qarity to check it */
|
||||
/* we recompute everything because we may have used only a small part of the redundancy */
|
||||
raid_gen(state->level, buffer, diskmax, state->block_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fprintf(stderr, "%u: Q-Parity data error\n", i);
|
||||
++error;
|
||||
}
|
||||
|
||||
if (failed_count == 2 && buffer_parity != 0 && buffer_qarity != 0) {
|
||||
/* TODO RAID6 */
|
||||
/* copy the redundancy to use */
|
||||
memcpy(buffer[diskmax], buffer_parity, state->block_size);
|
||||
memcpy(buffer[diskmax+1], buffer_qarity, state->block_size);
|
||||
|
||||
/* recover */
|
||||
raid6_recov_2data(buffer, diskmax, state->block_size, failed[0].index, failed[1].index, buffer_zero);
|
||||
|
||||
for(j=0;j<2;++j) {
|
||||
size = block_file_size(failed[j].block, state->block_size);
|
||||
|
||||
/* now compute the hash */
|
||||
memhash(state->hash, hash, buffer[failed[j].index], size);
|
||||
|
||||
/* compare the hash */
|
||||
if (memcmp(hash, failed[j].block->hash, HASH_SIZE) != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (j==2) {
|
||||
/* compute parity and qarity to check it */
|
||||
/* we recompute everything because we may have used only a small part of the redundancy */
|
||||
raid_gen(state->level, buffer, diskmax, state->block_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fprintf(stderr, "%u: Parity/Q-Parity data error\n", i);
|
||||
++error;
|
||||
}
|
||||
|
||||
/* no more stragety to fix */
|
||||
return -1;
|
||||
if (error)
|
||||
return error;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int state_check_process(struct snapraid_state* state, int fix, int parity_f, int qarity_f, block_off_t blockstart, block_off_t blockmax)
|
||||
|
|
@ -120,14 +169,15 @@ static int state_check_process(struct snapraid_state* state, int fix, int parity
|
|||
unsigned unrecoverable_error;
|
||||
unsigned recovered_error;
|
||||
|
||||
/* we need disk + 2 for each parity level buffers */
|
||||
buffermax = diskmax + state->level * 2;
|
||||
/* we need disk + 2 for each parity level buffers + 1 zero buffer */
|
||||
buffermax = diskmax + state->level * 2 + 1;
|
||||
|
||||
buffer_aligned = malloc_nofail_align(buffermax * state->block_size, &buffer_alloc);
|
||||
buffer = malloc_nofail(buffermax * sizeof(void*));
|
||||
for(i=0;i<buffermax;++i) {
|
||||
buffer[i] = buffer_aligned + i * state->block_size;
|
||||
}
|
||||
memset(buffer[buffermax-1], 0, state->block_size);
|
||||
|
||||
handle = malloc_nofail(diskmax * sizeof(struct snapraid_handle));
|
||||
for(i=0;i<diskmax;++i) {
|
||||
|
|
@ -294,6 +344,7 @@ static int state_check_process(struct snapraid_state* state, int fix, int parity
|
|||
{
|
||||
unsigned char* buffer_parity;
|
||||
unsigned char* buffer_qarity;
|
||||
unsigned char* buffer_zero;
|
||||
|
||||
/* buffers for parity read and not computed */
|
||||
if (state->level == 1) {
|
||||
|
|
@ -303,7 +354,8 @@ static int state_check_process(struct snapraid_state* state, int fix, int parity
|
|||
buffer_parity = buffer[diskmax + 2];
|
||||
buffer_qarity = buffer[diskmax + 3];
|
||||
}
|
||||
|
||||
buffer_zero = buffer[buffermax-1];
|
||||
|
||||
/* read the parity */
|
||||
if (parity_f != -1) {
|
||||
ret = parity_read(state->parity, parity_f, i, buffer_parity, state->block_size);
|
||||
|
|
@ -332,7 +384,7 @@ static int state_check_process(struct snapraid_state* state, int fix, int parity
|
|||
}
|
||||
}
|
||||
|
||||
ret = repair(state, i, diskmax, failed, failed_count, buffer, buffer_parity, buffer_qarity);
|
||||
ret = repair(state, i, diskmax, failed, failed_count, buffer, buffer_parity, buffer_qarity, buffer_zero);
|
||||
if (ret != 0) {
|
||||
/* increment the number of errors */
|
||||
if (ret > 0)
|
||||
|
|
@ -402,10 +454,10 @@ static int state_check_process(struct snapraid_state* state, int fix, int parity
|
|||
++unrecoverable_error;
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "%u: Fixed Q-Parity error\n", i);
|
||||
++recovered_error;
|
||||
fprintf(stderr, "%u: Fixed Q-Parity error\n", i);
|
||||
++recovered_error;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -471,13 +523,10 @@ bail:
|
|||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (state->expect_unrecoverable && state->expect_recoverable) {
|
||||
if (error == 0 || unrecoverable_error == 0)
|
||||
return -1;
|
||||
} else if (state->expect_unrecoverable) {
|
||||
if (state->expect_unrecoverable) {
|
||||
if (unrecoverable_error == 0)
|
||||
return -1;
|
||||
} if (state->expect_recoverable) {
|
||||
} else if (state->expect_recoverable) {
|
||||
if (error == 0)
|
||||
return -1;
|
||||
} else {
|
||||
|
|
|
|||
214
raid.c
214
raid.c
|
|
@ -31,11 +31,16 @@
|
|||
|
||||
#include "raid.h"
|
||||
#include "cpu.h"
|
||||
#include "tables.h"
|
||||
|
||||
/* internal forwarder */
|
||||
static void (*raid5_gen)(unsigned char** buffer, unsigned diskmax, unsigned size);
|
||||
static void (*raid6_gen)(unsigned char** buffer, unsigned diskmax, unsigned size);
|
||||
|
||||
/*
|
||||
* 2-way unrolled portable integer math RAID-5 instruction set
|
||||
*/
|
||||
void raid5_int32r2(unsigned char** dptr, unsigned diskmax, unsigned block_size)
|
||||
void raid5_int32r2(unsigned char** buffer, unsigned diskmax, unsigned size)
|
||||
{
|
||||
unsigned char* p;
|
||||
int z, z0;
|
||||
|
|
@ -44,15 +49,15 @@ void raid5_int32r2(unsigned char** dptr, unsigned diskmax, unsigned block_size)
|
|||
uint32_t wp0;
|
||||
uint32_t wp1;
|
||||
|
||||
z0 = diskmax - 2; /* Highest data disk */
|
||||
p = dptr[z0+1]; /* XOR parity */
|
||||
z0 = diskmax - 1; /* Highest data disk */
|
||||
p = buffer[z0+1]; /* XOR parity */
|
||||
|
||||
for(d=0;d<block_size;d+=8) {
|
||||
wp0 = *(uint32_t *)&dptr[z0][d+0*4];
|
||||
wp1 = *(uint32_t *)&dptr[z0][d+1*4];
|
||||
for(d=0;d<size;d+=8) {
|
||||
wp0 = *(uint32_t *)&buffer[z0][d+0*4];
|
||||
wp1 = *(uint32_t *)&buffer[z0][d+1*4];
|
||||
for(z=z0-1;z>=0;--z) {
|
||||
wp0 ^= *(uint32_t *)&dptr[z][d+0*4];
|
||||
wp1 ^= *(uint32_t *)&dptr[z][d+1*4];
|
||||
wp0 ^= *(uint32_t *)&buffer[z][d+0*4];
|
||||
wp1 ^= *(uint32_t *)&buffer[z][d+1*4];
|
||||
}
|
||||
*(uint32_t *)&p[d+4*0] = wp0;
|
||||
*(uint32_t *)&p[d+4*1] = wp1;
|
||||
|
|
@ -62,21 +67,21 @@ void raid5_int32r2(unsigned char** dptr, unsigned diskmax, unsigned block_size)
|
|||
/*
|
||||
* Unrolled-by-2 MMX implementation
|
||||
*/
|
||||
void raid5_mmxr2(unsigned char** dptr, unsigned diskmax, unsigned block_size)
|
||||
void raid5_mmxr2(unsigned char** buffer, unsigned diskmax, unsigned size)
|
||||
{
|
||||
unsigned char* p;
|
||||
int z, z0;
|
||||
unsigned d;
|
||||
|
||||
z0 = diskmax - 2; /* Highest data disk */
|
||||
p = dptr[z0+1]; /* XOR parity */
|
||||
z0 = diskmax - 1; /* Highest data disk */
|
||||
p = buffer[z0+1]; /* XOR parity */
|
||||
|
||||
for(d=0;d<block_size;d+=16) {
|
||||
asm volatile("movq %0,%%mm2" : : "m" (dptr[z0][d]));
|
||||
asm volatile("movq %0,%%mm3" : : "m" (dptr[z0][d+8]));
|
||||
for(d=0;d<size;d+=16) {
|
||||
asm volatile("movq %0,%%mm2" : : "m" (buffer[z0][d]));
|
||||
asm volatile("movq %0,%%mm3" : : "m" (buffer[z0][d+8]));
|
||||
for(z=z0-1;z>=0;--z) {
|
||||
asm volatile("movq %0,%%mm5" : : "m" (dptr[z][d]));
|
||||
asm volatile("movq %0,%%mm7" : : "m" (dptr[z][d+8]));
|
||||
asm volatile("movq %0,%%mm5" : : "m" (buffer[z][d]));
|
||||
asm volatile("movq %0,%%mm7" : : "m" (buffer[z][d+8]));
|
||||
asm volatile("pxor %mm5,%mm2");
|
||||
asm volatile("pxor %mm7,%mm3");
|
||||
}
|
||||
|
|
@ -87,21 +92,21 @@ void raid5_mmxr2(unsigned char** dptr, unsigned diskmax, unsigned block_size)
|
|||
asm volatile("emms" : : : "memory");
|
||||
}
|
||||
|
||||
void raid5_sse2r2(unsigned char** dptr, unsigned diskmax, unsigned block_size)
|
||||
void raid5_sse2r2(unsigned char** buffer, unsigned diskmax, unsigned size)
|
||||
{
|
||||
unsigned char* p;
|
||||
int z, z0;
|
||||
unsigned d;
|
||||
|
||||
z0 = diskmax - 2; /* Highest data disk */
|
||||
p = dptr[z0+1]; /* XOR parity */
|
||||
z0 = diskmax - 1; /* Highest data disk */
|
||||
p = buffer[z0+1]; /* XOR parity */
|
||||
|
||||
for(d=0;d<block_size;d+=32) {
|
||||
asm volatile("movdqa %0,%%xmm2" : : "m" (dptr[z0][d]));
|
||||
asm volatile("movdqa %0,%%xmm3" : : "m" (dptr[z0][d+16]));
|
||||
for(d=0;d<size;d+=32) {
|
||||
asm volatile("movdqa %0,%%xmm2" : : "m" (buffer[z0][d]));
|
||||
asm volatile("movdqa %0,%%xmm3" : : "m" (buffer[z0][d+16]));
|
||||
for(z=z0-1;z>=0;--z) {
|
||||
asm volatile("movdqa %0,%%xmm5" : : "m" (dptr[z][d]));
|
||||
asm volatile("movdqa %0,%%xmm7" : : "m" (dptr[z][d+16]));
|
||||
asm volatile("movdqa %0,%%xmm5" : : "m" (buffer[z][d]));
|
||||
asm volatile("movdqa %0,%%xmm7" : : "m" (buffer[z][d+16]));
|
||||
asm volatile("pxor %xmm5,%xmm2");
|
||||
asm volatile("pxor %xmm7,%xmm3");
|
||||
}
|
||||
|
|
@ -150,7 +155,7 @@ static inline uint32_t MASK(uint32_t v)
|
|||
/*
|
||||
* 2-way unrolled portable integer math RAID-6 instruction set
|
||||
*/
|
||||
void raid6_int32r2(unsigned char** dptr, unsigned diskmax, unsigned block_size)
|
||||
void raid6_int32r2(unsigned char** buffer, unsigned diskmax, unsigned size)
|
||||
{
|
||||
unsigned char* p;
|
||||
unsigned char* q;
|
||||
|
|
@ -160,16 +165,16 @@ void raid6_int32r2(unsigned char** dptr, unsigned diskmax, unsigned block_size)
|
|||
uint32_t wd0, wq0, wp0, w10, w20;
|
||||
uint32_t wd1, wq1, wp1, w11, w21;
|
||||
|
||||
z0 = diskmax - 3; /* Highest data disk */
|
||||
p = dptr[z0+1]; /* XOR parity */
|
||||
q = dptr[z0+2]; /* RS qarity */
|
||||
z0 = diskmax - 1; /* Highest data disk */
|
||||
p = buffer[z0+1]; /* XOR parity */
|
||||
q = buffer[z0+2]; /* RS qarity */
|
||||
|
||||
for(d=0;d<block_size;d+=8) {
|
||||
wq0 = wp0 = *(uint32_t *)&dptr[z0][d+0*4];
|
||||
wq1 = wp1 = *(uint32_t *)&dptr[z0][d+1*4];
|
||||
for(d=0;d<size;d+=8) {
|
||||
wq0 = wp0 = *(uint32_t *)&buffer[z0][d+0*4];
|
||||
wq1 = wp1 = *(uint32_t *)&buffer[z0][d+1*4];
|
||||
for (z=z0-1;z>= 0;--z) {
|
||||
wd0 = *(uint32_t *)&dptr[z][d+0*4];
|
||||
wd1 = *(uint32_t *)&dptr[z][d+1*4];
|
||||
wd0 = *(uint32_t *)&buffer[z][d+0*4];
|
||||
wd1 = *(uint32_t *)&buffer[z][d+1*4];
|
||||
wp0 ^= wd0;
|
||||
wp1 ^= wd1;
|
||||
w20 = MASK(wq0);
|
||||
|
|
@ -201,24 +206,24 @@ static const struct raid6_mmx_constants {
|
|||
/*
|
||||
* Unrolled-by-2 MMX implementation
|
||||
*/
|
||||
void raid6_mmxr2(unsigned char** dptr, unsigned diskmax, unsigned block_size)
|
||||
void raid6_mmxr2(unsigned char** buffer, unsigned diskmax, unsigned size)
|
||||
{
|
||||
unsigned char* p;
|
||||
unsigned char* q;
|
||||
int z, z0;
|
||||
unsigned d;
|
||||
|
||||
z0 = diskmax - 3; /* Highest data disk */
|
||||
p = dptr[z0+1]; /* XOR parity */
|
||||
q = dptr[z0+2]; /* RS qarity */
|
||||
z0 = diskmax - 1; /* Highest data disk */
|
||||
p = buffer[z0+1]; /* XOR parity */
|
||||
q = buffer[z0+2]; /* RS qarity */
|
||||
|
||||
asm volatile("movq %0,%%mm0" : : "m" (raid6_mmx_constants.x1d));
|
||||
asm volatile("pxor %mm5,%mm5"); /* Zero temp */
|
||||
asm volatile("pxor %mm7,%mm7"); /* Zero temp */
|
||||
|
||||
for(d=0;d<block_size;d+=16) {
|
||||
asm volatile("movq %0,%%mm2" : : "m" (dptr[z0][d]));
|
||||
asm volatile("movq %0,%%mm3" : : "m" (dptr[z0][d+8]));
|
||||
for(d=0;d<size;d+=16) {
|
||||
asm volatile("movq %0,%%mm2" : : "m" (buffer[z0][d]));
|
||||
asm volatile("movq %0,%%mm3" : : "m" (buffer[z0][d+8]));
|
||||
asm volatile("movq %mm2,%mm4");
|
||||
asm volatile("movq %mm3,%mm6");
|
||||
for(z=z0-1;z>=0;--z) {
|
||||
|
|
@ -230,8 +235,8 @@ void raid6_mmxr2(unsigned char** dptr, unsigned diskmax, unsigned block_size)
|
|||
asm volatile("pand %mm0,%mm7");
|
||||
asm volatile("pxor %mm5,%mm4");
|
||||
asm volatile("pxor %mm7,%mm6");
|
||||
asm volatile("movq %0,%%mm5" : : "m" (dptr[z][d]));
|
||||
asm volatile("movq %0,%%mm7" : : "m" (dptr[z][d+8]));
|
||||
asm volatile("movq %0,%%mm5" : : "m" (buffer[z][d]));
|
||||
asm volatile("movq %0,%%mm7" : : "m" (buffer[z][d+8]));
|
||||
asm volatile("pxor %mm5,%mm2");
|
||||
asm volatile("pxor %mm7,%mm3");
|
||||
asm volatile("pxor %mm5,%mm4");
|
||||
|
|
@ -257,30 +262,30 @@ static const struct raid6_sse_constants {
|
|||
/*
|
||||
* Unrolled-by-2 SSE2 implementation
|
||||
*/
|
||||
void raid6_sse2r2(unsigned char** dptr, unsigned diskmax, unsigned block_size)
|
||||
void raid6_sse2r2(unsigned char** buffer, unsigned diskmax, unsigned size)
|
||||
{
|
||||
unsigned char* p;
|
||||
unsigned char* q;
|
||||
int z, z0;
|
||||
unsigned d;
|
||||
|
||||
z0 = diskmax - 3; /* Highest data disk */
|
||||
p = dptr[z0+1]; /* XOR parity */
|
||||
q = dptr[z0+2]; /* RS qarity */
|
||||
z0 = diskmax - 1; /* Highest data disk */
|
||||
p = buffer[z0+1]; /* XOR parity */
|
||||
q = buffer[z0+2]; /* RS qarity */
|
||||
|
||||
asm volatile("movdqa %0,%%xmm0" : : "m" (raid6_sse_constants.x1d[0]));
|
||||
asm volatile("pxor %xmm5,%xmm5"); /* Zero temp */
|
||||
asm volatile("pxor %xmm7,%xmm7"); /* Zero temp */
|
||||
|
||||
/* We uniformly assume a single prefetch covers at least 32 bytes */
|
||||
for(d=0;d<block_size;d+=32) {
|
||||
asm volatile("prefetchnta %0" : : "m" (dptr[z0][d]));
|
||||
asm volatile("movdqa %0,%%xmm2" : : "m" (dptr[z0][d])); /* P[0] */
|
||||
asm volatile("movdqa %0,%%xmm3" : : "m" (dptr[z0][d+16])); /* P[1] */
|
||||
for(d=0;d<size;d+=32) {
|
||||
asm volatile("prefetchnta %0" : : "m" (buffer[z0][d]));
|
||||
asm volatile("movdqa %0,%%xmm2" : : "m" (buffer[z0][d])); /* P[0] */
|
||||
asm volatile("movdqa %0,%%xmm3" : : "m" (buffer[z0][d+16])); /* P[1] */
|
||||
asm volatile("movdqa %xmm2,%xmm4"); /* Q[0] */
|
||||
asm volatile("movdqa %xmm3,%xmm6"); /* Q[1] */
|
||||
for(z=z0-1;z>=0;--z) {
|
||||
asm volatile("prefetchnta %0" : : "m" (dptr[z][d]));
|
||||
asm volatile("prefetchnta %0" : : "m" (buffer[z][d]));
|
||||
asm volatile("pcmpgtb %xmm4,%xmm5");
|
||||
asm volatile("pcmpgtb %xmm6,%xmm7");
|
||||
asm volatile("paddb %xmm4,%xmm4");
|
||||
|
|
@ -289,8 +294,8 @@ void raid6_sse2r2(unsigned char** dptr, unsigned diskmax, unsigned block_size)
|
|||
asm volatile("pand %xmm0,%xmm7");
|
||||
asm volatile("pxor %xmm5,%xmm4");
|
||||
asm volatile("pxor %xmm7,%xmm6");
|
||||
asm volatile("movdqa %0,%%xmm5" : : "m" (dptr[z][d]));
|
||||
asm volatile("movdqa %0,%%xmm7" : : "m" (dptr[z][d+16]));
|
||||
asm volatile("movdqa %0,%%xmm5" : : "m" (buffer[z][d]));
|
||||
asm volatile("movdqa %0,%%xmm7" : : "m" (buffer[z][d+16]));
|
||||
asm volatile("pxor %xmm5,%xmm2");
|
||||
asm volatile("pxor %xmm7,%xmm3");
|
||||
asm volatile("pxor %xmm5,%xmm4");
|
||||
|
|
@ -308,15 +313,111 @@ void raid6_sse2r2(unsigned char** dptr, unsigned diskmax, unsigned block_size)
|
|||
}
|
||||
#endif
|
||||
|
||||
void (*raid5_gen)(unsigned char** dptr, unsigned diskmax, unsigned block_size);
|
||||
void (*raid6_gen)(unsigned char** dptr, unsigned diskmax, unsigned block_size);
|
||||
void raid5_recov_data(unsigned char** dptrs, unsigned diskmax, unsigned size, int faila)
|
||||
{
|
||||
unsigned char *p, *d;
|
||||
|
||||
d = dptrs[faila];
|
||||
p = dptrs[diskmax];
|
||||
|
||||
/* Compute syndrome using parity for the missing data page. */
|
||||
dptrs[faila] = p;
|
||||
dptrs[diskmax] = d;
|
||||
|
||||
raid5_gen(dptrs, diskmax, size);
|
||||
|
||||
/* Restore pointer table */
|
||||
dptrs[faila] = d;
|
||||
dptrs[diskmax] = p;
|
||||
}
|
||||
|
||||
void raid6_recov_2data(unsigned char** dptrs, unsigned diskmax, unsigned size, int faila, int failb, unsigned char* zero)
|
||||
{
|
||||
unsigned char *p, *q, *dp, *dq;
|
||||
unsigned char px, qx, db;
|
||||
const unsigned char *pbmul; /* P multiplier table for B data */
|
||||
const unsigned char *qmul; /* Q multiplier table (for both) */
|
||||
|
||||
p = dptrs[diskmax];
|
||||
q = dptrs[diskmax+1];
|
||||
|
||||
/* Compute syndrome with zero for the missing data pages. */
|
||||
/* Use the dead data pages as temporary storage for delta p and delta q. */
|
||||
dp = dptrs[faila];
|
||||
dptrs[faila] = zero;
|
||||
dptrs[diskmax] = dp;
|
||||
dq = dptrs[failb];
|
||||
dptrs[failb] = zero;
|
||||
dptrs[diskmax+1] = dq;
|
||||
|
||||
raid6_gen(dptrs, diskmax, size);
|
||||
|
||||
/* Restore pointer table */
|
||||
dptrs[faila] = dp;
|
||||
dptrs[failb] = dq;
|
||||
dptrs[diskmax] = p;
|
||||
dptrs[diskmax+1] = q;
|
||||
|
||||
/* Now, pick the proper data tables */
|
||||
pbmul = raid6_gfmul[raid6_gfexi[failb-faila]];
|
||||
qmul = raid6_gfmul[raid6_gfinv[raid6_gfexp[faila]^raid6_gfexp[failb]]];
|
||||
|
||||
/* Now do it... */
|
||||
while (size--) {
|
||||
px = *p ^ *dp;
|
||||
qx = qmul[*q ^ *dq];
|
||||
*dq++ = db = pbmul[px] ^ qx; /* Reconstructed B */
|
||||
*dp++ = db ^ px; /* Reconstructed A */
|
||||
p++;
|
||||
q++;
|
||||
}
|
||||
}
|
||||
|
||||
void raid6_recov_datap(unsigned char** dptrs, unsigned diskmax, unsigned size, int faila, unsigned char* zero)
|
||||
{
|
||||
unsigned char *p, *q, *dq;
|
||||
const unsigned char* qmul; /* Q multiplier table */
|
||||
|
||||
p = dptrs[diskmax];
|
||||
q = dptrs[diskmax+1];
|
||||
|
||||
/* Compute syndrome with zero for the missing data page. */
|
||||
/* Use the dead data page as temporary storage for delta q. */
|
||||
dq = dptrs[faila];
|
||||
dptrs[faila] = zero;
|
||||
dptrs[diskmax+1] = dq;
|
||||
|
||||
raid6_gen(dptrs, diskmax, size);
|
||||
|
||||
/* Restore pointer table */
|
||||
dptrs[faila] = dq;
|
||||
dptrs[diskmax+1] = q;
|
||||
|
||||
/* Now, pick the proper data tables */
|
||||
qmul = raid6_gfmul[raid6_gfinv[raid6_gfexp[faila]]];
|
||||
|
||||
/* Now do it... */
|
||||
while (size--) {
|
||||
*p++ ^= *dq = qmul[*q ^ *dq];
|
||||
q++;
|
||||
dq++;
|
||||
}
|
||||
}
|
||||
|
||||
void raid_gen(unsigned level, unsigned char** buffer, unsigned diskmax, unsigned size)
|
||||
{
|
||||
if (level == 1) {
|
||||
raid5_gen(buffer, diskmax, size);
|
||||
} else {
|
||||
raid6_gen(buffer, diskmax, size);
|
||||
}
|
||||
}
|
||||
|
||||
void raid_init(void)
|
||||
{
|
||||
raid5_gen = raid5_int32r2;
|
||||
raid6_gen = raid6_int32r2;
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
/*
|
||||
if (cpu_has_mmx()) {
|
||||
raid5_gen = raid5_mmxr2;
|
||||
raid6_gen = raid6_mmxr2;
|
||||
|
|
@ -325,7 +426,6 @@ void raid_init(void)
|
|||
raid5_gen = raid5_sse2r2;
|
||||
raid6_gen = raid6_sse2r2;
|
||||
}
|
||||
*/
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
35
raid.h
35
raid.h
|
|
@ -21,21 +21,40 @@
|
|||
/****************************************************************************/
|
||||
/* raid */
|
||||
|
||||
void raid5_int32r2(unsigned char** dptr, unsigned diskmax, unsigned block_size);
|
||||
void raid5_mmxr2(unsigned char** dptr, unsigned diskmax, unsigned block_size);
|
||||
void raid5_sse2r2(unsigned char** dptr, unsigned diskmax, unsigned block_size);
|
||||
/**
|
||||
* Syndrome computation.
|
||||
*/
|
||||
void raid_gen(unsigned level, unsigned char** buffer, unsigned diskmax, unsigned size);
|
||||
|
||||
void raid6_int32r2(unsigned char** dptr, unsigned diskmax, unsigned block_size);
|
||||
void raid6_mmxr2(unsigned char** dptr, unsigned diskmax, unsigned block_size);
|
||||
void raid6_sse2r2(unsigned char** dptr, unsigned diskmax, unsigned block_size);
|
||||
/*
|
||||
* Recover failure of one data block.
|
||||
*/
|
||||
void raid5_recov_data(unsigned char** dptrs, unsigned diskmax, unsigned size, int faila);
|
||||
|
||||
extern void (*raid5_gen)(uint8_t** ptrs, unsigned disks, unsigned block_size);
|
||||
extern void (*raid6_gen)(uint8_t** ptrs, unsigned disks, unsigned block_size);
|
||||
/*
|
||||
* Recover two failed data blocks.
|
||||
*/
|
||||
void raid6_recov_2data(unsigned char** dptrs, unsigned diskmax, unsigned size, int faila, int failb, unsigned char* zero);
|
||||
|
||||
/*
|
||||
* Recover failure of one data block plus the P block.
|
||||
*/
|
||||
void raid6_recov_datap(unsigned char** dptrs, unsigned diskmax, unsigned size, int faila, unsigned char* zero);
|
||||
|
||||
/**
|
||||
* Initializes the RAID system.
|
||||
*/
|
||||
void raid_init(void);
|
||||
|
||||
/**
|
||||
* Internal specialized syndrome computation.
|
||||
*/
|
||||
void raid5_int32r2(unsigned char** dptr, unsigned diskmax, unsigned size);
|
||||
void raid5_mmxr2(unsigned char** dptr, unsigned diskmax, unsigned size);
|
||||
void raid5_sse2r2(unsigned char** dptr, unsigned diskmax, unsigned size);
|
||||
void raid6_int32r2(unsigned char** dptr, unsigned diskmax, unsigned size);
|
||||
void raid6_mmxr2(unsigned char** dptr, unsigned diskmax, unsigned size);
|
||||
void raid6_sse2r2(unsigned char** dptr, unsigned diskmax, unsigned size);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
159
selftest.c
159
selftest.c
|
|
@ -78,18 +78,139 @@ struct test_vector TEST_MURMUR3[] = {
|
|||
{ 0, { 0 } }
|
||||
};
|
||||
|
||||
void selftest(void)
|
||||
static void raid5test(unsigned diskmax, unsigned block_size)
|
||||
{
|
||||
void* buffer_alloc;
|
||||
unsigned char* buffer_aligned;
|
||||
unsigned char** buffer;
|
||||
unsigned char* buffer_save;
|
||||
unsigned buffermax;
|
||||
unsigned i, j;
|
||||
|
||||
buffermax = diskmax + 1 + 1;
|
||||
buffer_aligned = malloc_nofail_align(buffermax * block_size, &buffer_alloc);
|
||||
buffer = malloc_nofail(buffermax * sizeof(void*));
|
||||
for(i=0;i<buffermax;++i) {
|
||||
buffer[i] = buffer_aligned + i * block_size;
|
||||
}
|
||||
buffer_save = buffer[buffermax-1];
|
||||
|
||||
/* fill with random */
|
||||
for(i=0;i<diskmax;++i) {
|
||||
for(j=0;j<block_size;++j)
|
||||
buffer[i][j] = rand();
|
||||
}
|
||||
|
||||
raid_gen(1, buffer, diskmax, block_size);
|
||||
|
||||
for(i=0;i<diskmax;++i) {
|
||||
/* save the correct one */
|
||||
memcpy(buffer_save, buffer[i], block_size);
|
||||
|
||||
/* destroy it */
|
||||
memset(buffer[i], 0x55, block_size);
|
||||
|
||||
/* recover */
|
||||
raid5_recov_data(buffer, diskmax, block_size, i);
|
||||
|
||||
/* check */
|
||||
if (memcmp(buffer_save, buffer[i], block_size) != 0) {
|
||||
fprintf(stderr, "Failed RAID5 test\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
free(buffer_alloc);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
static void raid6test(unsigned diskmax, unsigned block_size)
|
||||
{
|
||||
void* buffer_alloc;
|
||||
unsigned char* buffer_aligned;
|
||||
unsigned char** buffer;
|
||||
unsigned char* buffer_save0;
|
||||
unsigned char* buffer_save1;
|
||||
unsigned char* buffer_zero;
|
||||
unsigned buffermax;
|
||||
unsigned i, j;
|
||||
|
||||
buffermax = diskmax + 2 + 2 + 1;
|
||||
buffer_aligned = malloc_nofail_align(buffermax * block_size, &buffer_alloc);
|
||||
buffer = malloc_nofail(buffermax * sizeof(void*));
|
||||
for(i=0;i<buffermax;++i) {
|
||||
buffer[i] = buffer_aligned + i * block_size;
|
||||
}
|
||||
buffer_save0 = buffer[buffermax-3];
|
||||
buffer_save1 = buffer[buffermax-2];
|
||||
buffer_zero = buffer[buffermax-1];
|
||||
memset(buffer_zero, 0, block_size);
|
||||
|
||||
/* fill with random */
|
||||
for(i=0;i<diskmax;++i) {
|
||||
for(j=0;j<block_size;++j)
|
||||
buffer[i][j] = rand();
|
||||
}
|
||||
|
||||
raid_gen(2, buffer, diskmax, block_size);
|
||||
|
||||
/* check 2data */
|
||||
for(i=0;i<diskmax;++i) {
|
||||
for(j=i+1;j<diskmax;++j) {
|
||||
/* save the correct ones */
|
||||
memcpy(buffer_save0, buffer[i], block_size);
|
||||
memcpy(buffer_save1, buffer[j], block_size);
|
||||
|
||||
/* destroy it */
|
||||
memset(buffer[i], 0x55, block_size);
|
||||
memset(buffer[j], 0x55, block_size);
|
||||
|
||||
/* recover */
|
||||
raid6_recov_2data(buffer, diskmax, block_size, i, j, buffer_zero);
|
||||
|
||||
/* check */
|
||||
if (memcmp(buffer_save0, buffer[i], block_size) != 0
|
||||
|| memcmp(buffer_save1, buffer[j], block_size) != 0
|
||||
) {
|
||||
fprintf(stderr, "Failed RAID6 test\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* check datap */
|
||||
for(i=0;i<diskmax;++i) {
|
||||
/* the other is the parity */
|
||||
j = diskmax;
|
||||
|
||||
/* save the correct ones */
|
||||
memcpy(buffer_save0, buffer[i], block_size);
|
||||
memcpy(buffer_save1, buffer[j], block_size);
|
||||
|
||||
/* destroy it */
|
||||
memset(buffer[i], 0x55, block_size);
|
||||
memset(buffer[j], 0x55, block_size);
|
||||
|
||||
/* recover */
|
||||
raid6_recov_datap(buffer, diskmax, block_size, i, buffer_zero);
|
||||
|
||||
/* check */
|
||||
if (memcmp(buffer_save0, buffer[i], block_size) != 0
|
||||
|| memcmp(buffer_save1, buffer[j], block_size) != 0
|
||||
) {
|
||||
fprintf(stderr, "Failed RAID6 test\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
free(buffer_alloc);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
static void hashtest(void)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
printf("Self test...\n");
|
||||
|
||||
/* large file check */
|
||||
if (sizeof(off_t) < sizeof(uint64_t)) {
|
||||
fprintf(stderr, "Missing support for large files\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
for(i=0;TEST_MD5[i].data;++i) {
|
||||
unsigned char digest[HASH_SIZE];
|
||||
memhash(HASH_MD5, digest, TEST_MD5[i].data, strlen(TEST_MD5[i].data));
|
||||
|
|
@ -109,3 +230,23 @@ void selftest(void)
|
|||
}
|
||||
}
|
||||
|
||||
void selftest(void)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
printf("Self test...\n");
|
||||
|
||||
/* large file check */
|
||||
if (sizeof(off_t) < sizeof(uint64_t)) {
|
||||
fprintf(stderr, "Missing support for large files\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
hashtest();
|
||||
|
||||
for(i=1;i<19;++i) {
|
||||
raid5test(i, 4096);
|
||||
raid6test(i, 4096);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -201,10 +201,10 @@ int main(int argc, char* argv[])
|
|||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
selftest();
|
||||
|
||||
raid_init();
|
||||
|
||||
selftest();
|
||||
|
||||
state_init(&state);
|
||||
|
||||
state_config(&state, conf, verbose, force_zero, force_empty, expect_unrecoverable, expect_recoverable);
|
||||
|
|
|
|||
12
speed.c
12
speed.c
|
|
@ -92,7 +92,7 @@ void speed(void)
|
|||
|
||||
gettimeofday(&start, 0);
|
||||
for(j=0;j<count;++j) {
|
||||
raid5_int32r2(buffer, diskmax + 1, block_size);
|
||||
raid5_int32r2(buffer, diskmax, block_size);
|
||||
}
|
||||
gettimeofday(&stop, 0);
|
||||
|
||||
|
|
@ -105,7 +105,7 @@ void speed(void)
|
|||
if (cpu_has_mmx()) {
|
||||
gettimeofday(&start, 0);
|
||||
for(j=0;j<count;++j) {
|
||||
raid5_mmxr2(buffer, diskmax + 1, block_size);
|
||||
raid5_mmxr2(buffer, diskmax, block_size);
|
||||
}
|
||||
gettimeofday(&stop, 0);
|
||||
|
||||
|
|
@ -118,7 +118,7 @@ void speed(void)
|
|||
if (cpu_has_sse2()) {
|
||||
gettimeofday(&start, 0);
|
||||
for(j=0;j<count;++j) {
|
||||
raid5_sse2r2(buffer, diskmax + 1, block_size);
|
||||
raid5_sse2r2(buffer, diskmax, block_size);
|
||||
}
|
||||
gettimeofday(&stop, 0);
|
||||
|
||||
|
|
@ -131,7 +131,7 @@ void speed(void)
|
|||
|
||||
gettimeofday(&start, 0);
|
||||
for(j=0;j<count;++j) {
|
||||
raid6_int32r2(buffer, diskmax + 2, block_size);
|
||||
raid6_int32r2(buffer, diskmax, block_size);
|
||||
}
|
||||
gettimeofday(&stop, 0);
|
||||
|
||||
|
|
@ -144,7 +144,7 @@ void speed(void)
|
|||
if (cpu_has_mmx()) {
|
||||
gettimeofday(&start, 0);
|
||||
for(j=0;j<count;++j) {
|
||||
raid6_mmxr2(buffer, diskmax + 2, block_size);
|
||||
raid6_mmxr2(buffer, diskmax, block_size);
|
||||
}
|
||||
gettimeofday(&stop, 0);
|
||||
|
||||
|
|
@ -157,7 +157,7 @@ void speed(void)
|
|||
if (cpu_has_sse2()) {
|
||||
gettimeofday(&start, 0);
|
||||
for(j=0;j<count;++j) {
|
||||
raid6_sse2r2(buffer, diskmax + 2, block_size);
|
||||
raid6_sse2r2(buffer, diskmax, block_size);
|
||||
}
|
||||
gettimeofday(&stop, 0);
|
||||
|
||||
|
|
|
|||
6
sync.c
6
sync.c
|
|
@ -189,11 +189,7 @@ static int state_sync_process(struct snapraid_state* state, int parity_f, int qa
|
|||
}
|
||||
|
||||
/* compute the parity */
|
||||
if (state->level == 1) {
|
||||
raid5_gen(buffer, diskmax + state->level, state->block_size);
|
||||
} else {
|
||||
raid6_gen(buffer, diskmax + state->level, state->block_size);
|
||||
}
|
||||
raid_gen(state->level, buffer, diskmax, state->block_size);
|
||||
|
||||
/* write the parity */
|
||||
ret = parity_write(state->parity, parity_f, i, buffer[diskmax], state->block_size);
|
||||
|
|
|
|||
8
test-raid6.conf
Normal file
8
test-raid6.conf
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
block_size 1
|
||||
parity test/parity
|
||||
q-parity test/q-parity
|
||||
content test/content
|
||||
disk d1 test/disk1/
|
||||
disk d2 test/disk2/
|
||||
disk d3 test/disk3/
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue