snapraid/raid/test.c

442 lines
8 KiB
C
Raw Normal View History

// SPDX-License-Identifier: GPL-2.0-or-later
2026-04-02 16:25:49 +02:00
// Copyright (C) 2013 Andrea Mazzoleni
2013-12-29 22:13:08 +01:00
#include "internal.h"
#include "cpu.h"
#include "combo.h"
#include "memory.h"
/**
* Binomial coefficient of n over r.
*/
static int ibc(int n, int r)
{
if (r == 0 || n == r)
return 1;
else
return ibc(n - 1, r - 1) + ibc(n - 1, r);
}
/**
* Power n ^ r;
*/
static int ipow(int n, int r)
{
int v = 1;
2014-11-12 20:41:00 +01:00
2013-12-29 22:13:08 +01:00
while (r) {
v *= n;
--r;
}
return v;
}
int raid_test_combo(void)
{
int r;
int count;
int p[RAID_PARITY_MAX];
for (r = 1; r <= RAID_PARITY_MAX; ++r) {
/* count combination (r of RAID_PARITY_MAX) elements */
count = 0;
combination_first(r, RAID_PARITY_MAX, p);
do {
++count;
} while (combination_next(r, RAID_PARITY_MAX, p));
2015-03-18 19:19:32 +01:00
if (count != ibc(RAID_PARITY_MAX, r)) {
/* LCOV_EXCL_START */
2013-12-29 22:13:08 +01:00
return -1;
2015-03-18 19:19:32 +01:00
/* LCOV_EXCL_STOP */
}
2013-12-29 22:13:08 +01:00
}
for (r = 1; r <= RAID_PARITY_MAX; ++r) {
/* count permutation (r of RAID_PARITY_MAX) elements */
count = 0;
permutation_first(r, RAID_PARITY_MAX, p);
do {
++count;
} while (permutation_next(r, RAID_PARITY_MAX, p));
2015-03-18 19:19:32 +01:00
if (count != ipow(RAID_PARITY_MAX, r)) {
/* LCOV_EXCL_START */
2013-12-29 22:13:08 +01:00
return -1;
2015-03-18 19:19:32 +01:00
/* LCOV_EXCL_STOP */
}
2013-12-29 22:13:08 +01:00
}
return 0;
}
int raid_test_insert(void)
{
int p[RAID_PARITY_MAX];
int r;
for (r = 1; r <= RAID_PARITY_MAX; ++r) {
permutation_first(r, RAID_PARITY_MAX, p);
do {
int i[RAID_PARITY_MAX];
int j;
/* insert in order */
for (j = 0; j < r; ++j)
raid_insert(j, i, p[j]);
/* check order */
2015-03-18 19:19:32 +01:00
for (j = 1; j < r; ++j) {
if (i[j - 1] > i[j]) {
/* LCOV_EXCL_START */
return -1;
2015-03-18 19:19:32 +01:00
/* LCOV_EXCL_STOP */
}
}
} while (permutation_next(r, RAID_PARITY_MAX, p));
}
return 0;
}
2013-12-29 22:13:08 +01:00
int raid_test_sort(void)
{
int p[RAID_PARITY_MAX];
int r;
for (r = 1; r <= RAID_PARITY_MAX; ++r) {
permutation_first(r, RAID_PARITY_MAX, p);
do {
int i[RAID_PARITY_MAX];
int j;
/* make a copy */
for (j = 0; j < r; ++j)
i[j] = p[j];
raid_sort(r, i);
/* check order */
2015-03-18 19:19:32 +01:00
for (j = 1; j < r; ++j) {
if (i[j - 1] > i[j]) {
/* LCOV_EXCL_START */
2013-12-29 22:13:08 +01:00
return -1;
2015-03-18 19:19:32 +01:00
/* LCOV_EXCL_STOP */
}
}
2013-12-29 22:13:08 +01:00
} while (permutation_next(r, RAID_PARITY_MAX, p));
}
return 0;
}
int raid_test_rec(int mode, int nd, size_t size)
{
void (*f[RAID_PARITY_MAX][4])(
int nr, int *id, int *ip, int nd, size_t size, void **vbuf);
void *v_alloc;
void **v;
2013-12-29 22:13:08 +01:00
void **data;
void **parity;
void **test;
void *data_save[RAID_PARITY_MAX];
void *parity_save[RAID_PARITY_MAX];
void *waste;
int nv;
2013-12-29 22:13:08 +01:00
int id[RAID_PARITY_MAX];
int ip[RAID_PARITY_MAX];
int i;
int j;
int nr;
int nf[RAID_PARITY_MAX];
2013-12-29 22:13:08 +01:00
int np;
raid_mode(mode);
if (mode == RAID_MODE_CAUCHY)
np = RAID_PARITY_MAX;
else
np = 3;
nv = nd + np * 2 + 2;
2013-12-29 22:13:08 +01:00
v = raid_malloc_vector(nd, nv, size, &v_alloc);
2015-03-18 19:19:32 +01:00
if (!v) {
/* LCOV_EXCL_START */
2013-12-29 22:13:08 +01:00
return -1;
2015-03-18 19:19:32 +01:00
/* LCOV_EXCL_STOP */
}
2013-12-29 22:13:08 +01:00
data = v;
parity = v + nd;
test = v + nd + np;
2013-12-29 22:13:08 +01:00
for (i = 0; i < np; ++i)
parity_save[i] = parity[i];
2014-11-12 20:41:00 +01:00
memset(v[nv - 2], 0, size);
raid_zero(v[nv - 2]);
2013-12-29 22:13:08 +01:00
2014-11-12 20:41:00 +01:00
waste = v[nv - 1];
2013-12-29 22:13:08 +01:00
/* fill with pseudo-random data with the arbitrary seed "1" */
raid_mrand_vector(1, nd, size, v);
2013-12-29 22:13:08 +01:00
/* setup recov functions */
for (i = 0; i < np; ++i) {
nf[i] = 0;
2013-12-29 22:13:08 +01:00
if (i == 0) {
f[i][nf[i]++] = raid_rec1_int8;
2013-12-30 21:12:29 +01:00
#ifdef CONFIG_X86
#ifdef CONFIG_SSSE3
2013-12-29 22:13:08 +01:00
if (raid_cpu_has_ssse3())
f[i][nf[i]++] = raid_rec1_ssse3;
#endif
#ifdef CONFIG_AVX2
2014-09-16 21:58:29 +02:00
if (raid_cpu_has_avx2())
f[i][nf[i]++] = raid_rec1_avx2;
#endif
2013-12-29 22:13:08 +01:00
#endif
} else if (i == 1) {
f[i][nf[i]++] = raid_rec2_int8;
2013-12-30 21:12:29 +01:00
#ifdef CONFIG_X86
#ifdef CONFIG_SSSE3
2013-12-29 22:13:08 +01:00
if (raid_cpu_has_ssse3())
f[i][nf[i]++] = raid_rec2_ssse3;
#endif
#ifdef CONFIG_AVX2
2014-09-16 21:58:29 +02:00
if (raid_cpu_has_avx2())
f[i][nf[i]++] = raid_rec2_avx2;
#endif
2013-12-29 22:13:08 +01:00
#endif
} else {
f[i][nf[i]++] = raid_recX_int8;
2013-12-30 21:12:29 +01:00
#ifdef CONFIG_X86
#ifdef CONFIG_SSSE3
2013-12-29 22:13:08 +01:00
if (raid_cpu_has_ssse3())
f[i][nf[i]++] = raid_recX_ssse3;
#endif
#ifdef CONFIG_AVX2
2014-09-16 21:58:29 +02:00
if (raid_cpu_has_avx2())
f[i][nf[i]++] = raid_recX_avx2;
#endif
2013-12-29 22:13:08 +01:00
#endif
}
}
/* compute the parity */
raid_gen_ref(nd, np, size, v);
2013-12-29 22:13:08 +01:00
/* set all the parity to the waste v */
2013-12-29 22:13:08 +01:00
for (i = 0; i < np; ++i)
parity[i] = waste;
/* all parity levels */
for (nr = 1; nr <= np; ++nr) {
/* all combinations (nr of nd) disks */
combination_first(nr, nd, id);
do {
/* all combinations (nr of np) parities */
combination_first(nr, np, ip);
do {
/* for each recover function */
2014-11-12 20:41:00 +01:00
for (j = 0; j < nf[nr - 1]; ++j) {
2013-12-29 22:13:08 +01:00
/* set */
for (i = 0; i < nr; ++i) {
/* remove the missing data */
data_save[i] = data[id[i]];
data[id[i]] = test[i];
/* set the parity to use */
parity[ip[i]] = parity_save[ip[i]];
}
/* recover */
2014-11-12 20:41:00 +01:00
f[nr - 1][j](nr, id, ip, nd, size, v);
2013-12-29 22:13:08 +01:00
/* check */
2015-03-18 19:19:32 +01:00
for (i = 0; i < nr; ++i) {
if (memcmp(test[i], data_save[i], size) != 0) {
/* LCOV_EXCL_START */
goto bail;
2015-03-18 19:19:32 +01:00
/* LCOV_EXCL_STOP */
}
}
2013-12-29 22:13:08 +01:00
/* restore */
for (i = 0; i < nr; ++i) {
/* restore the data */
data[id[i]] = data_save[i];
/* restore the parity */
parity[ip[i]] = waste;
}
}
} while (combination_next(nr, np, ip));
} while (combination_next(nr, nd, id));
}
free(v_alloc);
free(v);
2013-12-29 22:13:08 +01:00
return 0;
bail:
2015-03-18 19:19:32 +01:00
/* LCOV_EXCL_START */
free(v_alloc);
free(v);
return -1;
2015-03-18 19:19:32 +01:00
/* LCOV_EXCL_STOP */
2013-12-29 22:13:08 +01:00
}
int raid_test_par(int mode, int nd, size_t size)
{
2015-03-18 08:21:28 +01:00
void (*f[64])(int nd, size_t size, void **vbuf);
void *v_alloc;
void **v;
int nv;
2013-12-29 22:13:08 +01:00
int i, j;
int nf;
2013-12-29 22:13:08 +01:00
int np;
raid_mode(mode);
if (mode == RAID_MODE_CAUCHY)
np = RAID_PARITY_MAX;
else
np = 3;
nv = nd + np * 2;
2013-12-29 22:13:08 +01:00
v = raid_malloc_vector(nd, nv, size, &v_alloc);
2015-03-18 19:19:32 +01:00
if (!v) {
/* LCOV_EXCL_START */
2013-12-29 22:13:08 +01:00
return -1;
2015-03-18 19:19:32 +01:00
/* LCOV_EXCL_STOP */
}
2013-12-29 22:13:08 +01:00
2014-01-15 19:57:02 +01:00
/* check memory */
2015-03-18 19:19:32 +01:00
if (raid_mtest_vector(nv, size, v) != 0) {
/* LCOV_EXCL_START */
goto bail;
2015-03-18 19:19:32 +01:00
/* LCOV_EXCL_STOP */
}
2014-01-15 19:57:02 +01:00
/* fill with pseudo-random data with the arbitrary seed "2" */
raid_mrand_vector(2, nv, size, v);
2013-12-29 22:13:08 +01:00
/* compute the parity */
raid_gen_ref(nd, np, size, v);
2013-12-29 22:13:08 +01:00
/* copy in back buffers */
for (i = 0; i < np; ++i)
memcpy(v[nd + np + i], v[nd + i], size);
2013-12-29 22:13:08 +01:00
/* load all the available functions */
nf = 0;
2013-12-29 22:13:08 +01:00
f[nf++] = raid_gen1_int32;
f[nf++] = raid_gen1_int64;
f[nf++] = raid_gen2_int32;
f[nf++] = raid_gen2_int64;
2013-12-29 22:13:08 +01:00
2013-12-30 21:12:29 +01:00
#ifdef CONFIG_X86
#ifdef CONFIG_SSE2
2013-12-29 22:13:08 +01:00
if (raid_cpu_has_sse2()) {
f[nf++] = raid_gen1_sse2;
f[nf++] = raid_gen2_sse2;
2013-12-30 21:12:29 +01:00
#ifdef CONFIG_X86_64
f[nf++] = raid_gen2_sse2ext;
2013-12-29 22:13:08 +01:00
#endif
}
#endif
2014-09-14 18:03:40 +02:00
#ifdef CONFIG_AVX2
2014-09-14 18:03:40 +02:00
if (raid_cpu_has_avx2()) {
f[nf++] = raid_gen1_avx2;
f[nf++] = raid_gen2_avx2;
}
2013-12-30 10:13:10 +01:00
#endif
#endif /* CONFIG_X86 */
2013-12-29 22:13:08 +01:00
if (mode == RAID_MODE_CAUCHY) {
f[nf++] = raid_gen3_int8;
f[nf++] = raid_gen4_int8;
f[nf++] = raid_gen5_int8;
f[nf++] = raid_gen6_int8;
2013-12-29 22:13:08 +01:00
2013-12-30 21:12:29 +01:00
#ifdef CONFIG_X86
#ifdef CONFIG_SSSE3
2013-12-29 22:13:08 +01:00
if (raid_cpu_has_ssse3()) {
f[nf++] = raid_gen3_ssse3;
f[nf++] = raid_gen4_ssse3;
f[nf++] = raid_gen5_ssse3;
f[nf++] = raid_gen6_ssse3;
2013-12-30 21:12:29 +01:00
#ifdef CONFIG_X86_64
f[nf++] = raid_gen3_ssse3ext;
f[nf++] = raid_gen4_ssse3ext;
f[nf++] = raid_gen5_ssse3ext;
f[nf++] = raid_gen6_ssse3ext;
2013-12-29 22:13:08 +01:00
#endif
}
#endif
2014-09-15 22:31:25 +02:00
#ifdef CONFIG_AVX2
2014-09-15 22:31:25 +02:00
#ifdef CONFIG_X86_64
if (raid_cpu_has_avx2()) {
f[nf++] = raid_gen3_avx2ext;
2014-09-16 21:58:29 +02:00
f[nf++] = raid_gen4_avx2ext;
f[nf++] = raid_gen5_avx2ext;
f[nf++] = raid_gen6_avx2ext;
2014-09-15 22:31:25 +02:00
}
#endif
2013-12-29 22:13:08 +01:00
#endif
#endif /* CONFIG_X86 */
2013-12-29 22:13:08 +01:00
} else {
f[nf++] = raid_genz_int32;
f[nf++] = raid_genz_int64;
2013-12-30 10:13:10 +01:00
2013-12-30 21:12:29 +01:00
#ifdef CONFIG_X86
#ifdef CONFIG_SSE2
2013-12-29 22:13:08 +01:00
if (raid_cpu_has_sse2()) {
f[nf++] = raid_genz_sse2;
2013-12-30 21:12:29 +01:00
#ifdef CONFIG_X86_64
f[nf++] = raid_genz_sse2ext;
2013-12-29 22:13:08 +01:00
#endif
}
#endif
2014-09-15 22:31:25 +02:00
#ifdef CONFIG_AVX2
2014-09-15 22:31:25 +02:00
#ifdef CONFIG_X86_64
2014-09-16 21:58:29 +02:00
if (raid_cpu_has_avx2())
2014-09-15 22:31:25 +02:00
f[nf++] = raid_genz_avx2ext;
#endif
2013-12-29 22:13:08 +01:00
#endif
#endif /* CONFIG_X86 */
2013-12-29 22:13:08 +01:00
}
/* check all the functions */
for (j = 0; j < nf; ++j) {
2013-12-29 22:13:08 +01:00
/* compute parity */
f[j](nd, size, v);
2013-12-29 22:13:08 +01:00
/* check it */
2015-03-18 19:19:32 +01:00
for (i = 0; i < np; ++i) {
if (memcmp(v[nd + np + i], v[nd + i], size) != 0) {
/* LCOV_EXCL_START */
goto bail;
2015-03-18 19:19:32 +01:00
/* LCOV_EXCL_STOP */
}
}
2013-12-29 22:13:08 +01:00
}
free(v_alloc);
free(v);
2013-12-29 22:13:08 +01:00
return 0;
bail:
2015-03-18 19:19:32 +01:00
/* LCOV_EXCL_START */
free(v_alloc);
free(v);
return -1;
2015-03-18 19:19:32 +01:00
/* LCOV_EXCL_STOP */
2013-12-29 22:13:08 +01:00
}