Commit 568521d0 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'core-rslib-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull Reed-Solomon library updates from Thomas Gleixner:
 "A cleanup and fixes series from Ferdinand Blomqvist who analyzed the
  original Reed-Solomon library from Phil Karn on which the kernel
  implementation is based on.

  This comes with a test module which verifies all the various corner
  cases for correctness"

* 'core-rslib-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  rslib: Make some functions static
  rslib: Fix remaining decoder flaws
  rslib: Update documentation
  rslib: Fix handling of of caller provided syndrome
  rslib: decode_rs: Code cleanup
  rslib: decode_rs: Fix length parameter check
  rslib: Fix decoding of shortened codes
  rslib: Add tests for the encoder and decoder
parents 6b377547 ede7c247
...@@ -1754,6 +1754,18 @@ config RBTREE_TEST ...@@ -1754,6 +1754,18 @@ config RBTREE_TEST
A benchmark measuring the performance of the rbtree library. A benchmark measuring the performance of the rbtree library.
Also includes rbtree invariant checks. Also includes rbtree invariant checks.
config REED_SOLOMON_TEST
tristate "Reed-Solomon library test"
depends on DEBUG_KERNEL || m
select REED_SOLOMON
select REED_SOLOMON_ENC16
select REED_SOLOMON_DEC16
help
This option enables the self-test function of rslib at boot,
or at module load time.
If unsure, say N.
config INTERVAL_TREE_TEST config INTERVAL_TREE_TEST
tristate "Interval tree test" tristate "Interval tree test"
depends on DEBUG_KERNEL depends on DEBUG_KERNEL
......
...@@ -4,4 +4,4 @@ ...@@ -4,4 +4,4 @@
# #
obj-$(CONFIG_REED_SOLOMON) += reed_solomon.o obj-$(CONFIG_REED_SOLOMON) += reed_solomon.o
obj-$(CONFIG_REED_SOLOMON_TEST) += test_rslib.o
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
uint16_t *index_of = rs->index_of; uint16_t *index_of = rs->index_of;
uint16_t u, q, tmp, num1, num2, den, discr_r, syn_error; uint16_t u, q, tmp, num1, num2, den, discr_r, syn_error;
int count = 0; int count = 0;
int num_corrected;
uint16_t msk = (uint16_t) rs->nn; uint16_t msk = (uint16_t) rs->nn;
/* /*
...@@ -39,11 +40,21 @@ ...@@ -39,11 +40,21 @@
/* Check length parameter for validity */ /* Check length parameter for validity */
pad = nn - nroots - len; pad = nn - nroots - len;
BUG_ON(pad < 0 || pad >= nn); BUG_ON(pad < 0 || pad >= nn - nroots);
/* Does the caller provide the syndrome ? */ /* Does the caller provide the syndrome ? */
if (s != NULL) if (s != NULL) {
for (i = 0; i < nroots; i++) {
/* The syndrome is in index form,
* so nn represents zero
*/
if (s[i] != nn)
goto decode; goto decode;
}
/* syndrome is zero, no errors to correct */
return 0;
}
/* form the syndromes; i.e., evaluate data(x) at roots of /* form the syndromes; i.e., evaluate data(x) at roots of
* g(x) */ * g(x) */
...@@ -88,8 +99,7 @@ ...@@ -88,8 +99,7 @@
/* if syndrome is zero, data[] is a codeword and there are no /* if syndrome is zero, data[] is a codeword and there are no
* errors to correct. So return data[] unmodified * errors to correct. So return data[] unmodified
*/ */
count = 0; return 0;
goto finish;
} }
decode: decode:
...@@ -99,9 +109,9 @@ ...@@ -99,9 +109,9 @@
if (no_eras > 0) { if (no_eras > 0) {
/* Init lambda to be the erasure locator polynomial */ /* Init lambda to be the erasure locator polynomial */
lambda[1] = alpha_to[rs_modnn(rs, lambda[1] = alpha_to[rs_modnn(rs,
prim * (nn - 1 - eras_pos[0]))]; prim * (nn - 1 - (eras_pos[0] + pad)))];
for (i = 1; i < no_eras; i++) { for (i = 1; i < no_eras; i++) {
u = rs_modnn(rs, prim * (nn - 1 - eras_pos[i])); u = rs_modnn(rs, prim * (nn - 1 - (eras_pos[i] + pad)));
for (j = i + 1; j > 0; j--) { for (j = i + 1; j > 0; j--) {
tmp = index_of[lambda[j - 1]]; tmp = index_of[lambda[j - 1]];
if (tmp != nn) { if (tmp != nn) {
...@@ -175,6 +185,15 @@ ...@@ -175,6 +185,15 @@
if (lambda[i] != nn) if (lambda[i] != nn)
deg_lambda = i; deg_lambda = i;
} }
if (deg_lambda == 0) {
/*
* deg(lambda) is zero even though the syndrome is non-zero
* => uncorrectable error detected
*/
return -EBADMSG;
}
/* Find roots of error+erasure locator polynomial by Chien search */ /* Find roots of error+erasure locator polynomial by Chien search */
memcpy(&reg[1], &lambda[1], nroots * sizeof(reg[0])); memcpy(&reg[1], &lambda[1], nroots * sizeof(reg[0]));
count = 0; /* Number of roots of lambda(x) */ count = 0; /* Number of roots of lambda(x) */
...@@ -188,6 +207,12 @@ ...@@ -188,6 +207,12 @@
} }
if (q != 0) if (q != 0)
continue; /* Not a root */ continue; /* Not a root */
if (k < pad) {
/* Impossible error location. Uncorrectable error. */
return -EBADMSG;
}
/* store root (index-form) and error location number */ /* store root (index-form) and error location number */
root[count] = i; root[count] = i;
loc[count] = k; loc[count] = k;
...@@ -202,8 +227,7 @@ ...@@ -202,8 +227,7 @@
* deg(lambda) unequal to number of roots => uncorrectable * deg(lambda) unequal to number of roots => uncorrectable
* error detected * error detected
*/ */
count = -EBADMSG; return -EBADMSG;
goto finish;
} }
/* /*
* Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo * Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo
...@@ -223,7 +247,9 @@ ...@@ -223,7 +247,9 @@
/* /*
* Compute error values in poly-form. num1 = omega(inv(X(l))), num2 = * Compute error values in poly-form. num1 = omega(inv(X(l))), num2 =
* inv(X(l))**(fcr-1) and den = lambda_pr(inv(X(l))) all in poly-form * inv(X(l))**(fcr-1) and den = lambda_pr(inv(X(l))) all in poly-form
* Note: we reuse the buffer for b to store the correction pattern
*/ */
num_corrected = 0;
for (j = count - 1; j >= 0; j--) { for (j = count - 1; j >= 0; j--) {
num1 = 0; num1 = 0;
for (i = deg_omega; i >= 0; i--) { for (i = deg_omega; i >= 0; i--) {
...@@ -231,6 +257,13 @@ ...@@ -231,6 +257,13 @@
num1 ^= alpha_to[rs_modnn(rs, omega[i] + num1 ^= alpha_to[rs_modnn(rs, omega[i] +
i * root[j])]; i * root[j])];
} }
if (num1 == 0) {
/* Nothing to correct at this position */
b[j] = 0;
continue;
}
num2 = alpha_to[rs_modnn(rs, root[j] * (fcr - 1) + nn)]; num2 = alpha_to[rs_modnn(rs, root[j] * (fcr - 1) + nn)];
den = 0; den = 0;
...@@ -242,30 +275,52 @@ ...@@ -242,30 +275,52 @@
i * root[j])]; i * root[j])];
} }
} }
/* Apply error to data */
if (num1 != 0 && loc[j] >= pad) { b[j] = alpha_to[rs_modnn(rs, index_of[num1] +
uint16_t cor = alpha_to[rs_modnn(rs,index_of[num1] +
index_of[num2] + index_of[num2] +
nn - index_of[den])]; nn - index_of[den])];
/* Store the error correction pattern, if a num_corrected++;
* correction buffer is available */
if (corr) {
corr[j] = cor;
} else {
/* If a data buffer is given and the
* error is inside the message,
* correct it */
if (data && (loc[j] < (nn - nroots)))
data[loc[j] - pad] ^= cor;
} }
/*
* We compute the syndrome of the 'error' and check that it matches
* the syndrome of the received word
*/
for (i = 0; i < nroots; i++) {
tmp = 0;
for (j = 0; j < count; j++) {
if (b[j] == 0)
continue;
k = (fcr + i) * prim * (nn-loc[j]-1);
tmp ^= alpha_to[rs_modnn(rs, index_of[b[j]] + k)];
} }
if (tmp != alpha_to[s[i]])
return -EBADMSG;
} }
finish: /*
if (eras_pos != NULL) { * Store the error correction pattern, if a
for (i = 0; i < count; i++) * correction buffer is available
eras_pos[i] = loc[i] - pad; */
if (corr && eras_pos) {
j = 0;
for (i = 0; i < count; i++) {
if (b[i]) {
corr[j] = b[i];
eras_pos[j++] = loc[i] - pad;
}
}
} else if (data && par) {
/* Apply error to data and parity */
for (i = 0; i < count; i++) {
if (loc[i] < (nn - nroots))
data[loc[i] - pad] ^= b[i];
else
par[loc[i] - pad - len] ^= b[i];
}
} }
return count;
return num_corrected;
} }
...@@ -340,7 +340,8 @@ EXPORT_SYMBOL_GPL(encode_rs8); ...@@ -340,7 +340,8 @@ EXPORT_SYMBOL_GPL(encode_rs8);
* @data: data field of a given type * @data: data field of a given type
* @par: received parity data field * @par: received parity data field
* @len: data length * @len: data length
* @s: syndrome data field (if NULL, syndrome is calculated) * @s: syndrome data field, must be in index form
* (if NULL, syndrome is calculated)
* @no_eras: number of erasures * @no_eras: number of erasures
* @eras_pos: position of erasures, can be NULL * @eras_pos: position of erasures, can be NULL
* @invmsk: invert data mask (will be xored on data, not on parity!) * @invmsk: invert data mask (will be xored on data, not on parity!)
...@@ -354,7 +355,8 @@ EXPORT_SYMBOL_GPL(encode_rs8); ...@@ -354,7 +355,8 @@ EXPORT_SYMBOL_GPL(encode_rs8);
* decoding, so the caller has to ensure that decoder invocations are * decoding, so the caller has to ensure that decoder invocations are
* serialized. * serialized.
* *
* Returns the number of corrected bits or -EBADMSG for uncorrectable errors. * Returns the number of corrected symbols or -EBADMSG for uncorrectable
* errors. The count includes errors in the parity.
*/ */
int decode_rs8(struct rs_control *rsc, uint8_t *data, uint16_t *par, int len, int decode_rs8(struct rs_control *rsc, uint8_t *data, uint16_t *par, int len,
uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk, uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk,
...@@ -391,7 +393,8 @@ EXPORT_SYMBOL_GPL(encode_rs16); ...@@ -391,7 +393,8 @@ EXPORT_SYMBOL_GPL(encode_rs16);
* @data: data field of a given type * @data: data field of a given type
* @par: received parity data field * @par: received parity data field
* @len: data length * @len: data length
* @s: syndrome data field (if NULL, syndrome is calculated) * @s: syndrome data field, must be in index form
* (if NULL, syndrome is calculated)
* @no_eras: number of erasures * @no_eras: number of erasures
* @eras_pos: position of erasures, can be NULL * @eras_pos: position of erasures, can be NULL
* @invmsk: invert data mask (will be xored on data, not on parity!) * @invmsk: invert data mask (will be xored on data, not on parity!)
...@@ -403,7 +406,8 @@ EXPORT_SYMBOL_GPL(encode_rs16); ...@@ -403,7 +406,8 @@ EXPORT_SYMBOL_GPL(encode_rs16);
* decoding, so the caller has to ensure that decoder invocations are * decoding, so the caller has to ensure that decoder invocations are
* serialized. * serialized.
* *
* Returns the number of corrected bits or -EBADMSG for uncorrectable errors. * Returns the number of corrected symbols or -EBADMSG for uncorrectable
* errors. The count includes errors in the parity.
*/ */
int decode_rs16(struct rs_control *rsc, uint16_t *data, uint16_t *par, int len, int decode_rs16(struct rs_control *rsc, uint16_t *data, uint16_t *par, int len,
uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk, uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk,
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment